@@ -74,163 +74,99 @@ export async function onRequest(context: {
7474 ) ;
7575 }
7676
77- // Create GitHub issue via API
78- const githubToken = env . GITHUB_TOKEN ;
79- if ( ! githubToken ) {
80- return new Response (
81- JSON . stringify ( {
82- error : 'GitHub integration not configured' ,
83- fallback :
84- 'Please report directly at https://github.com/bettergovph/bettergov/issues/new' ,
85- } ) ,
86- {
87- status : 503 ,
88- headers : { 'Content-Type' : 'application/json' } ,
89- }
90- ) ;
91- }
92-
93- // Log report submission (no PII)
77+ // Log report submission (no PII in logs)
9478 console . log (
95- `[Report Submission] Creating issue for hotline: "${ data . hotlineName } "`
79+ `[Report Submission] Received report for hotline: "${ data . hotlineName } "`
9680 ) ;
9781
98- // Construct issue body (NO PII included)
99- const issueBody = `## Hotline Information Issue
82+ // Construct email body
83+ const emailBody = `
84+ New Hotline Report Submission
85+ =============================
10086
101- ### Which hotline has outdated information?
102- ${ data . hotlineName }
87+ Hotline Name: ${ data . hotlineName }
10388
104- ### What is incorrect?
89+ What is incorrect:
10590${ data . issue }
10691
107- ${ data . correctInfo ? `### What should it be?\n${ data . correctInfo } \n\n` : '' }
108- ${ data . source ? `### Source\n${ data . source } \n\n` : '' }
92+ ${ data . correctInfo ? `What should it be:\n${ data . correctInfo } \n\n` : '' }
93+ ${ data . source ? `Source:\n${ data . source } \n\n` : '' }
94+ ${ data . reporterEmail ? `Reporter Email: ${ data . reporterEmail } \n\n` : '' }
10995---
110- Reported via API from: /philippines/hotlines
111- Timestamp: ${ new Date ( ) . toISOString ( ) } ` ;
112-
113- // Create GitHub issue with timeout handling
114- const controller = new AbortController ( ) ;
115- const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 10000 ) ; // 10s timeout
96+ Reported from: /philippines/hotlines
97+ Timestamp: ${ new Date ( ) . toISOString ( ) }
98+ ` . trim ( ) ;
99+
100+ // Send email using Cloudflare Email Workers (MailChannels)
101+ // This is a free service available on Cloudflare Workers
102+ const emailPayload = {
103+ personalizations : [
104+ {
105+ to :
[ { email :
'[email protected] ' , name :
'BetterGov Team' } ] , 106+ } ,
107+ ] ,
108+ from : {
109+ 110+ name : 'BetterGov Hotline Reporter' ,
111+ } ,
112+ subject : `Hotline Report: ${ data . hotlineName } ` ,
113+ content : [
114+ {
115+ type : 'text/plain' ,
116+ value : emailBody ,
117+ } ,
118+ ] ,
119+ } ;
116120
117- let githubResponse : Response ;
121+ // Try to send email via MailChannels (free on Cloudflare Workers)
118122 try {
119- githubResponse = await fetch (
120- 'https://api.github.com/repos/bettergovph/bettergov/issues ' ,
123+ const emailResponse = await fetch (
124+ 'https://api.mailchannels.net/tx/v1/send ' ,
121125 {
122126 method : 'POST' ,
123127 headers : {
124- Authorization : `Bearer ${ githubToken } ` ,
125128 'Content-Type' : 'application/json' ,
126- 'User-Agent' : 'BetterGov-Hotline-Reporter' ,
127- Accept : 'application/vnd.github.v3+json' ,
128129 } ,
129- body : JSON . stringify ( {
130- title : `Outdated Hotline: ${ data . hotlineName } ` ,
131- body : issueBody ,
132- labels : [ 'hotline' , 'data-update' , 'user-report' ] ,
133- } ) ,
134- signal : controller . signal ,
130+ body : JSON . stringify ( emailPayload ) ,
135131 }
136132 ) ;
137- } catch ( fetchError ) {
138- clearTimeout ( timeoutId ) ;
139133
140- // Handle abort/timeout error
141- if ( fetchError instanceof Error && fetchError . name === 'AbortError' ) {
142- console . error ( 'GitHub API request timed out' ) ;
143- return new Response (
144- JSON . stringify ( {
145- error : 'Request timed out' ,
146- message : 'GitHub API did not respond in time' ,
147- } ) ,
148- {
149- status : 504 ,
150- headers : { 'Content-Type' : 'application/json' } ,
151- }
134+ if ( ! emailResponse . ok ) {
135+ const errorText = await emailResponse . text ( ) ;
136+ console . error (
137+ `Email sending failed (status ${ emailResponse . status } ):` ,
138+ errorText
139+ ) ;
140+ // Don't fail the request - just log it
141+ console . log (
142+ '[Fallback] Report logged to console for manual processing'
152143 ) ;
144+ } else {
145+ console . log ( '[Report Success] Email sent successfully' ) ;
153146 }
154-
155- // Handle other fetch errors (network issues, etc.)
156- console . error ( 'GitHub API fetch error:' , fetchError ) ;
157- return new Response (
158- JSON . stringify ( {
159- error : 'Failed to connect to GitHub' ,
160- message :
161- fetchError instanceof Error ? fetchError . message : 'Network error' ,
162- } ) ,
163- {
164- status : 503 ,
165- headers : { 'Content-Type' : 'application/json' } ,
166- }
167- ) ;
168- } finally {
169- clearTimeout ( timeoutId ) ;
170- }
171-
172- if ( ! githubResponse . ok ) {
173- const errorText = await githubResponse . text ( ) ;
174- // Log detailed error server-side for debugging
175- console . error (
176- `GitHub API error (status ${ githubResponse . status } ):` ,
177- errorText
178- ) ;
179- // Return generic error to client without exposing sensitive details
180- return new Response (
181- JSON . stringify ( {
182- error : 'Failed to create GitHub issue' ,
183- } ) ,
184- {
185- status : githubResponse . status ,
186- headers : { 'Content-Type' : 'application/json' } ,
187- }
188- ) ;
147+ } catch ( emailError ) {
148+ console . error ( 'Email sending error:' , emailError ) ;
149+ console . log ( '[Fallback] Report logged to console for manual processing' ) ;
189150 }
190151
191- const githubData : unknown = await githubResponse . json ( ) ;
192-
193- // Runtime validation of GitHub response
194- if (
195- ! githubData ||
196- typeof githubData !== 'object' ||
197- ! ( 'html_url' in githubData ) ||
198- ! ( 'number' in githubData ) ||
199- typeof githubData . html_url !== 'string' ||
200- typeof githubData . number !== 'number'
201- ) {
202- console . error (
203- 'Invalid GitHub API response structure:' ,
204- JSON . stringify ( githubData )
205- ) ;
206- return new Response (
207- JSON . stringify ( {
208- error : 'Failed to create GitHub issue' ,
209- message : 'Invalid response from GitHub API' ,
210- } ) ,
211- {
212- status : 500 ,
213- headers : { 'Content-Type' : 'application/json' } ,
214- }
215- ) ;
216- }
217-
218- const issue = {
219- html_url : githubData . html_url ,
220- number : githubData . number ,
221- } ;
222-
223- // Log successful issue creation (no PII)
152+ // Always log the full report to console for backup
224153 console . log (
225- `[Report Success] GitHub Issue #${ issue . number } created for hotline: "${ data . hotlineName } "`
154+ '[Report Details]' ,
155+ JSON . stringify ( {
156+ hotlineName : data . hotlineName ,
157+ issue : data . issue ,
158+ correctInfo : data . correctInfo ,
159+ source : data . source ,
160+ hasEmail : ! ! data . reporterEmail ,
161+ timestamp : new Date ( ) . toISOString ( ) ,
162+ } )
226163 ) ;
227164
165+ // Return success to user regardless of email status
228166 return new Response (
229167 JSON . stringify ( {
230168 success : true ,
231169 message : 'Report submitted successfully' ,
232- issueUrl : issue . html_url ,
233- issueNumber : issue . number ,
234170 } ) ,
235171 {
236172 status : 201 ,
0 commit comments