Lofton Gentry
unread,Jun 13, 2023, 4:45:02 PM6/13/23Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Google Apps Script Community
(This might be irrelevant, but it is important for background purposes)
I have a form that is submitted by users that can contain an image. When this form is submitted, an email is sent out with all of the relevant information from the submitted form, including the image that was attached to the form. The image is attached to the email as an attachment. To get the image as an attachment to the email, when the form is submitted, the image is saved to a google drive folder, and its id is returned. The id is used in a separate function to basically find the image in google drive, and attach it to the email.
(My specific issue)
I am trying to save an image to a google drive folder without using the Drive API (as I'm not allowed to for company reasons). I've determined that the most effective methodology in my case is to use a server-side proxy function to avoid a CORS based error. (Someone please correct me if I'm wrong with how I'm describing this) When a user submits a form on my front end, the image file uploaded is sent to my app script back end, which is then sent to my google drive. The issue I'm encountering is, once again, a CORS-policy error, but this time my error is with my own web app restricting me from sending the data to the back end. I tried to rectify this by setting headers that allow specific information, but it is not working. I'm thinking this is because ```.setHeaders()``` does not work in App Script, or, even though it's "my" web app, it's still being hosted by google, so they'll still restrict it. I will list my front-end and back-end code below. I can provide any further details as necessary.
Front End Code:
```
<script>
function saveAlert() {
google.script.run.withSuccessHandler(saveNewAlert).getPayload()
}
//takes user input from a modal dialog form and sends it to a server-side function named saveAlerts() for processing and storage in a Google Sheet
async function saveNewAlert(data){
let out = []
//Setting controls object to each of the html input elements in the form
let controls = {
alertSelect: document.getElementById('alertSelect'),
alertLocation: document.getElementById('alertLocation'),
alertCode: document.getElementById('alertCode'),
servicesAffected: document.getElementById('servicesAffected'),
alertAddress: document.getElementById('alertAddress'),
alertSubject: document.getElementById('alertSubject'),
alertBody: tinymce.activeEditor.getContent(),
alertDate: document.getElementById('alertDate'),
alertEndDate: document.getElementById('alertEndDate'),
userEmail: document.getElementById('userEmail'),
imageUpload: document.getElementById('imageUpload')
}
//If-check to make sure form is filled out properly
if(validateInput(controls)){
let modalSpinner = document.getElementById('modalSpinner')
modalSpinner.hidden = false
let alertDateFinal = controls.alertDate.value.replaceAll('-','/')
let alertEndDateFinal = controls.alertEndDate.value.replaceAll('-','/')
alertDate.value === '' ? new Date(alertDateFinal).toLocaleDateString() : new Date(alertDateFinal)
alertEndDate.value === '' ? new Date(alertEndDateFinal).toLocaleDateString() : new Date(alertEndDateFinal)
let accessToken = data.accessToken
webAppUrl = data.webAppUrl
let imageIds = []
let formData = new FormData()
for(let i = 0; i < imageUpload.files.length; i++){
let formData = new FormData()
formData.append('imageFile', imageUpload.files[i])
await fetch(webAppUrl + '?action=uploadImage', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${accessToken}`
},
body: formData
})
.then(res => res.text())
.then(fileId => {
imageIds.push(fileId)
})
.catch(error => {
console.error('Error saving files', error)
})
}
//Creating new record based on values in the controls object
let record = {
'Alert Type': controls.alertSelect.value,
'Alert Location': controls.alertLocation.value,
'Alert Code': controls.alertCode.value,
'Services Affected': controls.servicesAffected.value,
'Alert Address': controls.alertAddress.value,
'Alert Subject': controls.alertSubject.value,
'Alert Details': controls.alertBody,
'Alert Date': alertDateFinal,
'Alert End Date': alertEndDateFinal,
'User Email': controls.userEmail.value,
'Alert Active': true,
// 'Images': imageIds
}
//Pushing the record to the server side function 'saveAlerts()', which adds the alert created from the form to the google sheet
out.push(record)
google.script.run.withSuccessHandler(clearForm).saveAlerts(out)
} else{
window.alert('Please Check Input')
}
}
</script>
```
Back End Code:
```
function doPost(e){
if(e.parameter.action === 'uploadImage'){
let imageFile = e.parameter.imageFile
let fileId = saveImageToDrive(imageFile)
let headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
}
return ContentService.createTextOutput(fileId).setMimeType(ContentService.MimeType.TEXT).setHeaders(headers)
}
}
```
Relevant Function ```.getPayload()```
```
function getPayload() {
const payload = {
accessToken: ScriptApp.getOAuthToken(),
webAppUrl: ScriptApp.getService().getUrl()
}
return payload
}
```
This function returns a token to allow access to google APIs (I believe I need it here, but am unsure), and the web app URL. I return the web app URL as well because when testing, the URL changes, so I just capture the current URL and use that instead of setting a pre-defined one.