Google drive backend for annotation
We use a google app script to handle the uploads from some of the sub-communities. This script is embedded in the beta version of the annotation tool. It operates under the neurobagel google account.
The Google Script
NOTE: when copy pasting for use, ensure to update the UPLOAD_PASSWORD and MAIN_FOLDER_ID.
const MAIN_FOLDER_ID = '';
function doPost(e) {
try {
const data = JSON.parse(e.postData.contents);
// ACTION: GET SITES (List Folders)
if (data.action === 'getSites') {
const mainFolder = DriveApp.getFolderById(MAIN_FOLDER_ID);
const folders = mainFolder.getFolders();
const siteNames = [];
while (folders.hasNext()) {
siteNames.push(folders.next().getName());
}
// Sort alphabetically
siteNames.sort();
return ContentService.createTextOutput(
JSON.stringify({
status: 'success',
sites: siteNames,
})
).setMimeType(ContentService.MimeType.JSON);
}
// ACTION: UPLOAD FILE
const UPLOAD_PASSWORD = '***';
if (data.password !== UPLOAD_PASSWORD) {
return ContentService.createTextOutput(
JSON.stringify({
status: 'auth_failed',
message: 'Incorrect Password',
})
).setMimeType(ContentService.MimeType.JSON);
}
const filename = data.filename;
const content = data.content;
const description = data.description || '';
const folderName = data.folderName; // The site name, e.g., "Site A"
// 1. Get the Main Folder
const mainFolder = DriveApp.getFolderById(MAIN_FOLDER_ID);
let targetFolder = mainFolder;
// 2. If a specific folder name (Site) is provided, find or create it
if (folderName) {
const folders = mainFolder.getFoldersByName(folderName);
if (folders.hasNext()) {
targetFolder = folders.next();
} else {
targetFolder = mainFolder.createFolder(folderName);
}
}
// 3. Check for existing file
const existingFiles = targetFolder.getFilesByName(filename);
const fileExists = existingFiles.hasNext();
// If checkExists is true and file exists, return CONFLICT (don't write yet)
if (data.checkExists && fileExists) {
return ContentService.createTextOutput(
JSON.stringify({
status: 'conflict',
message: 'File already exists',
})
).setMimeType(ContentService.MimeType.JSON);
}
// 4. Create or Update file
let file;
if (fileExists) {
// Update existing file
file = existingFiles.next();
file.setContent(content);
file.setDescription(description);
} else {
// Create new file
file = targetFolder.createFile(filename, content, MimeType.PLAIN_TEXT);
file.setDescription(description);
}
// 5. Handle Comments (Optional)
if (data.commentsContent) {
const commentsFolderName = 'comments';
let commentsFolder;
const cFolders = targetFolder.getFoldersByName(commentsFolderName);
if (cFolders.hasNext()) {
commentsFolder = cFolders.next();
} else {
commentsFolder = targetFolder.createFolder(commentsFolderName);
}
// Comments filename: same as base filename but .txt
const commentsFilename = filename.replace(/\.json$/i, '') + '.txt';
const existingComments = commentsFolder.getFilesByName(commentsFilename);
if (existingComments.hasNext()) {
// Update the first file found (Preserve ID)
const commentsFile = existingComments.next();
commentsFile.setContent(data.commentsContent);
} else {
// Create new if none exist
commentsFolder.createFile(commentsFilename, data.commentsContent, MimeType.PLAIN_TEXT);
}
}
return ContentService.createTextOutput(
JSON.stringify({
status: 'success',
fileId: file.getId(),
url: file.getUrl(),
folder: targetFolder.getName(),
folderId: targetFolder.getId(),
})
).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService.createTextOutput(
JSON.stringify({
status: 'error',
message: error.toString(),
})
).setMimeType(ContentService.MimeType.JSON);
}
}
function doOptions(e) {
return ContentService.createTextOutput('');
}
Deployment
Here are the steps you need to take to deploy or update the Google script.
Prep
- Log into the google account you want to run this script as
- you should use the neurobagel account
- Seb has the login credentials
- Go to https://script.google.com/.
- You should already have access to the
nb_annotation_community_dict_uploaderproject - which is the E-PD backend.
Make a new project
- Click on "new project"
- Copy the App script into the editable area
- Change the values for the GDrive folder and change the password secrets
- Share the project with the rest of the NB maintainers (but leave it on "restricted")
(Re-)Deploying the script
- Click
Deploy > Manage deployments - Click the
Editbutton (pen looking icon) in the modal that opens - Make a new version (or first deploy), give it a name
- Under "execute as", use your user (e.g. the Neurobagel account)
- Under "who has access", set "Anyone".
- If you set "Only myself" then nobody but you can use the backend
- If you set "Anyone with a Google Account", then we might as well just go full OAuth because users will have to log in first
- Click deploy, make a note of the "Web App URL"
- You will pass this as an environment variable to the frontend
- The .env variable is called
NB_GOOGLE_APPS_SCRIPT_URL