Skip to content

Instantly share code, notes, and snippets.

@idoleat
Last active May 3, 2024 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idoleat/21752e2ec0a5d1e0283390abe27466e2 to your computer and use it in GitHub Desktop.
Save idoleat/21752e2ec0a5d1e0283390abe27466e2 to your computer and use it in GitHub Desktop.
let HOMEWORK_NOTE_ID = '' // hackmd note to write to
let HACKMD_API_KEY = '' // your hackmd api key
let GITHUB_PERSONAL_ACCESS_TOKEN = '' // currently not in use
let EMAIL = {
'recipient': '',
'subject': 'Linux 核心課程: 已收到第 4 次作業的提交',
'body': '(本信件是自動產生,請不要回覆)\n請詳閱 https://hackmd.io/@sysprog/linux2024-lab0 的說明,確認 HackMD 筆記的存取權限及內容規範符合預期,若登記成功,應可在 https://hackmd.io/@sysprog/linux2024-homework4 見到你提交的 GitHub/HackMD 超連結。\n\n'
}
let PUBLISHED_LINKS = []; // kind of ugly but it works
// Exexcute this once to subscribe onSubmit event
function setTrigger() {
let currentForm = FormApp.getActiveForm();
ScriptApp.newTrigger('onSubmit')
.forForm(currentForm)
.onFormSubmit()
.create();
}
function onSubmit(e){
let reponses = e.response.getItemResponses();
let username = reponses[2].getResponse();
let note = reponses[3].getResponse();
EMAIL.recipient = reponses[0].getResponse();
let code = reponses[???].getResponse(); // Fill in corresponding index
if(logError(checkMail(EMAIL.recipient, code)) && logError(checkUsername(username)) && logError(checkNotePermission(note))){
// second one won't be check if failed on the first one
let content_to_insert = ` * [開發紀錄](${PUBLISHED_LINKS[0]})`;
logError(updateNote(HOMEWORK_NOTE_ID, username, content_to_insert)); // May fail
}
GmailApp.sendEmail(EMAIL.recipient, EMAIL.subject, EMAIL.body);
console.log('Email sent!');
}
function checkMail(addr, code){
// second argument is a RSA private key in pem format, which could be generated by $ openssl genrsa
let sig = Utilities.computeRsaSha256Signature(addr,
"-----BEGIN PRIVATE KEY-----\nYOUR_KEY\n-----END PRIVATE KEY-----\n");
if(code !== Utilities.base64Encode(sig))
return 16;
return 200;
}
function checkRepo(username, repo) {
let pattern = new RegExp(`^(https:\/\/github.com\/${username})`);
if(repo.match(pattern) === null){
return 16;
}
else{
return 200;
}
}
// only work on my repo
function checkGHAction() {
let GET_option = {
'muteHttpExceptions': true,
'headers': {
'Authorization': `Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}`,
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
}
let response = UrlFetchApp.fetch(`https://api.github.com/repos/idoleat/lab0-c/actions/permissions`, GET_option);
console.log(`GitHub Action enabled? ${JSON.parse(response).enabled}`);
}
function checkRepo(username, repo) {
let pattern = new RegExp(`^(https:\/\/github.com\/${username})`);
if(repo.match(pattern) === null){
return 16;
}
else{
return 200;
}
}
function checkNotePermission(url){
console.log(`Check note: ${url}`);
let response;
let GET_options = {
'method': 'get',
'muteHttpExceptions': true,
'headers': {
'Authorization': `Bearer ${HACKMD_API_KEY}`
}
};
response = UrlFetchApp.fetch(`${url}/edit`, {'muteHttpExceptions': true});
if(response.getResponseCode() !== 200){
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
if(response.getResponseCode() !== 200){
return response.getResponseCode();
}
let body = JSON.parse(response);
if(body['readPermission'] !== 'guest'){ // should be reported at the first check though
return 10;
}
if(body['writePermission'] !== 'signed_in' && body['writePermission'] !== 'guest'){
return 11;
}
if(body['publishedAt'] === null){
return 12;
}
PUBLISHED_LINKS.push(body['publishLink']);
console.log('All check passed!'); // I don't know why this won't show
return 200;
}
/// @noteID: String
function updateNote(noteID, username, linksStr){
let response;
let data = {
'content': '',
'readPermission': '',
'writePermission': '',
'permalink': ''
}
let GET_options = {
'method': 'get',
'muteHttpExceptions': true,
'headers': {
'Authorization': `Bearer ${HACKMD_API_KEY}`
}
};
response = UrlFetchApp.fetch(`https://api.hackmd.io/v1/notes/${noteID}`, GET_options); // May fail
if(response.getResponseCode() !== 200){
return 13;
}
let body = JSON.parse(response);
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){
let pattern = `- \\[ \\] ${username}\n.*\n`; // wildcard does not include \n
let lines = linksStr.match(/\n/);
if(lines !== null){
for(let i=0; i<lines.length; i++){
pattern += '.*\n';
}
}
// Update the existed links
const toReplace = new RegExp(pattern);
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}`
}
};
response = UrlFetchApp.fetch(`https://api.hackmd.io/v1/teams/sysprog/notes/${noteID}`, PATCH_options); // May fail
if(response.getResponseCode() !== 202){
return 15;
}
console.log('Updated successfully.');
return 200;
}
function logError(result){
switch(result){
case 200:
console.log('response 200. continue');
return true;
case 403:
console.log('We do not have permisison to view the note.');
EMAIL.body += '錯誤: 沒有權限瀏覽筆記,請檢查權限設定。';
break;
case 404:
console.log('We can not find your note.');
EMAIL.body += '錯誤: 無法找到此筆記,請檢查網址是否正確。';
break;
case 10:
console.log('Read permission should be set to everyone.');
EMAIL.body += '錯誤: 筆記應允許所有人瀏覽,請更新筆記權限。';
break;
case 11:
console.log('Write permission should be set to signed-in user.');
EMAIL.body += '錯誤: 筆記應設為允許所有登入者編輯,請更新編輯權限。';
break;
case 12:
console.log('Note should be published.');
EMAIL.body += '錯誤: 筆記應公開發布於網際網路,請參閱 HackMD 文件。';
break;
case 13:
console.log('Not responded with 200 while getting the note for listing homeworks.');
EMAIL.body += '* Not responded with 200 while getting the note for listing homeworks ,請回報此狀況。';
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;
case 16:
console.log('錯誤: GitHub 帳號或 fork 後的網址不符合預期');
EMAIL.body += '錯誤: GitHub 帳號或 fork 後的網址不符合預期';
break;
case 17:
console.log('錯誤: 電子郵件地址無法收信');
EMAIL.body += '錯誤: 電子郵件地址無法收信';
break;
default:
console.log(`Unexpected error code ${result}. Please report this problem.`);
EMAIL.body += `* Unexpected error code ${result} ,請回報此狀況。`;
break;
}
EMAIL.body += '\n錯誤改正後,請用指定的 Google 表單提交。'
return false;
}
function test(){
let currentForm = FormApp.getActiveForm();
const formResponse = currentForm.createResponse();
const items = currentForm.getItems();
formResponse.withItemResponse(items[0].asTextItem().createResponse('idoleat@ccns.ncku.edu.tw'));
formResponse.withItemResponse(items[1].asTextItem().createResponse('簡志瑋'));
formResponse.withItemResponse(items[2].asTextItem().createResponse('idoleat'));
formResponse.withItemResponse(items[4].asTextItem().createResponse('https://github.com/idoleat/Christmas-card'));
formResponse.withItemResponse(items[5].asTextItem().createResponse('https://hackmd.io/@idoleat/damp-air'));
formResponse.submit();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment