Last active
December 26, 2023 15:14
-
-
Save idoleat/32ca51fe5d4a433a4f76b2b4958d1507 to your computer and use it in GitHub Desktop.
version 1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let HOMEWORK_NOTE_ID = 'your note id'; | |
let HACKMD_API_KEY = 'your key'; | |
let EMAIL = { | |
'recipient': '', | |
'subject': 'Thanks for handing in your home work!', | |
'body': '' | |
} | |
function onOpen(e) { | |
let currentForm = FormApp.getActiveForm(); | |
let usernameValidation = FormApp.createTextValidation() // To prevent injection | |
.setHelpText('Please provide a valid usename') | |
.requireTextMatchesPattern('[a-zA-Z0-9\-_]+') | |
.build(); | |
let noteValidation = FormApp.createTextValidation() | |
.setHelpText('Please provide a valid hackmd published note link') | |
.requireTextMatchesPattern('https:\/\/hackmd\.io\/@[a-zA-Z0-9\-_]+\/\[a-zA-Z0-9\-_]+') | |
.build(); | |
let githubValidation = FormApp.createTextValidation() | |
.setHelpText('Please provide a valid github repository link') | |
.requireTextMatchesPattern('https:\/\/github\.com\/[a-zA-Z0-9\-_]+\/\[a-zA-Z0-9\-_]+') | |
.build(); | |
const items = currentForm.getItems(); | |
items[0].asTextItem().setValidation(usernameValidation); | |
items[1].asTextItem().setValidation(noteValidation); | |
items[2].asTextItem().setValidation(githubValidation); | |
items[3].asTextItem().setValidation(noteValidation); | |
console.log(`Text validation set on questions`); | |
// Optional. Deletes all triggers in the current project. | |
//let triggers = ScriptApp.getProjectTriggers(); // why sometimes get an error on no permission? | |
//for (var i = 0; i < triggers.length; i++) { | |
// ScriptApp.deleteTrigger(triggers[i]); | |
//} | |
ScriptApp.newTrigger('onSubmit') | |
.forForm(currentForm) | |
.onFormSubmit() | |
.create(); | |
} | |
function onSubmit(e){ | |
let reponses = e.response.getItemResponses(); | |
let username = reponses[0].getResponse(); // should be sanitized | |
let note_1 = reponses[1].getResponse(); | |
let repo = reponses[2].getResponse(); | |
let note_2 = reponses[3].getResponse(); | |
EMAIL.recipient = reponses[4].getResponse(); | |
if(emailResult(checkNotePermission(note_1)) && emailResult(checkNotePermission(note_2))){ | |
// second one won't be check if failed on the first one | |
let content_to_insert = ` * [開發紀錄](${note_1}) / [GitHub](${repo})\n * [開發紀錄 (Quiz)](${note_2})`; | |
emailResult(updateNote(HOMEWORK_NOTE_ID, username, content_to_insert)); // May fail | |
} | |
GmailApp.sendEmail(EMAIL.recipient, EMAIL.subject, EMAIL.body); | |
console.log('Email sent!'); | |
} | |
function checkNotePermission(url){ | |
console.log(`Check note: ${url}`); | |
let response; | |
let GET_options = { | |
'method': 'get', | |
'muteHttpExceptions': true, | |
'headers': { | |
'Authorization': `Bearer ${HACKMD_API_KEY}` | |
} | |
}; | |
//do{ | |
// response = UrlFetchApp.fetch(`${url}/edit`, {'muteHttpExceptions': true}); | |
//} | |
//while(response.getResponseCode() !== 302); | |
response = UrlFetchApp.fetch(`${url}/edit`, {'muteHttpExceptions': true}); // May 403 (even with public note) | |
if(response.getResponseCode() !== 302){ | |
return response.getResponseCode(); | |
} | |
let noteID = response.getHeaders()['hackmd-note-id']; | |
console.log(`Note ID: ${noteID}`); | |
response = UrlFetchApp.fetch(`https://api.hackmd.io/v1/notes/${noteID}`, GET_options); // May fail | |
let body = JSON.parse(response); | |
if(body['readPermission'] !== 'guest'){ // should be reported at the first check though | |
return 10; | |
} | |
if(body['writePermission'] !== 'signed_in'){ | |
return 11; | |
} | |
if(body['publishedAt'] === null){ | |
return 12; | |
} | |
console.log('All check passed!'); // I don't know why this won't show | |
return 200; | |
} | |
/// @noteID: String | |
function updateNote(noteID, username, linksStr){ | |
let reponse; | |
let data = { | |
'content': '', | |
'readPermission': '', | |
'writePermission': '', | |
'permalink': '' | |
} | |
let GET_options = { | |
'method': 'get', | |
'muteHttpExceptions': true, | |
'headers': { | |
'Authorization': `Bearer ${HACKMD_API_KEY}` | |
} | |
}; | |
reponse = UrlFetchApp.fetch(`https://api.hackmd.io/v1/notes/${noteID}`, GET_options); // May fail | |
if(reponse.getResponseCode() !== 200){ | |
return 13; | |
} | |
let body = JSON.parse(reponse); | |
// Shallow copy | |
data.readPermission = body.readPermission; | |
data.writePermission = body.writePermission; | |
data.permalink = body.permalink; | |
// Check if ID existed. Update or Add accordingly. | |
let pattern = new RegExp(username); | |
let result = body.content.match(pattern); | |
if(result === null){ | |
// Add an entry to buttom | |
data.content = body.content + `- [ ] ${username}\n${linksStr}\n`; | |
console.log(`Note updated with new entry as: ${data.content}`); | |
} | |
else if(result.length === 1){ | |
// Update the existed links | |
const toReplace = new RegExp(`- \\[ \\] ${username}\n.*\n.*\n`); // wildcard does not include \n | |
data.content = body.content.replace(toReplace, `- [ ] ${username}\n${linksStr}\n- [ ]`); | |
console.log(`Note updated as: ${data.content}`); | |
} | |
else{ | |
console.log('WTF'); | |
// cases that other that 0 or 1 is unexpected and should be unreachable | |
return 14; | |
} | |
let PATCH_options = { | |
'method': 'patch', | |
'muteHttpExceptions': true, | |
'contentType': 'application/json', | |
'payload' : JSON.stringify(data), | |
'headers': { | |
'Authorization': `Bearer ${HACKMD_API_KEY}` | |
} | |
}; | |
reponse = UrlFetchApp.fetch(`https://api.hackmd.io/v1/notes/${noteID}`, PATCH_options); // May fail | |
if(reponse.getResponseCode() !== 202){ | |
return 15; | |
} | |
console.log('Updated successfully.'); | |
return 200; | |
} | |
function emailResult(result){ | |
let msg; | |
switch(result){ | |
case 200: | |
console.log('ok. continue'); | |
return true; | |
case 403: | |
console.log('We do not have permisison to view the note or something wrong with HackMD.'); | |
EMAIL.body += 'We do not have permisison to view the note or something wrong with HackMD.'; | |
break; | |
case 404: | |
console.log('We can not find your note.'); | |
EMAIL.body += 'We can not find your note.'; | |
break; | |
case 10: | |
console.log('Read permission should be set to everyone.'); | |
EMAIL.body += 'Read permission should be set to everyone.'; | |
break; | |
case 11: | |
console.log('Write permission should be set to signed-in user.'); | |
EMAIL.body += 'Write permission should be set to signed-in user.'; | |
break; | |
case 12: | |
console.log('Note should be published.'); | |
EMAIL.body += 'Note should be published.'; | |
break; | |
case 13: | |
console.log('Not responded with 200 while getting the note.'); | |
EMAIL.body += 'Not responded with 200 while getting the note.'; | |
break; | |
case 14: | |
console.log('More than one entry in the note with same username'); | |
EMAIL.body += 'More than one entry in the note with same username'; | |
break; | |
case 15: | |
console.log('Not responded with 202 while updating the note.'); | |
EMAIL.body += 'Not responded with 202 while updating the note.'; | |
break; | |
default: | |
console.log(`Unexpected error code ${result}. Please report this problem.`); | |
EMAIL.body += `Unexpected error code ${result}. Please report this problem.`; | |
} | |
return false; | |
} | |
// Sometimes it won't work, with no error message attached..... | |
function test(){ | |
let currentForm = FormApp.getActiveForm(); | |
const formResponse = currentForm.createResponse(); | |
const items = currentForm.getItems(); | |
formResponse.withItemResponse(items[0].asTextItem().createResponse('superman')); | |
formResponse.withItemResponse(items[1].asTextItem().createResponse('https://hackmd.io/@idoleat/AudioAdventureMap')); | |
formResponse.withItemResponse(items[2].asTextItem().createResponse('https://github.com/idoleat/Christmas-card')); | |
formResponse.withItemResponse(items[3].asTextItem().createResponse('https://hackmd.io/@idoleat/AudioAdventureMap')); | |
formResponse.withItemResponse(items[4].asTextItem().createResponse('[email protected]')); | |
formResponse.submit(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment