import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();
// Add necessary network domain
pack.addNetworkDomain("googleapis.com");
// Set up OAuth2 authentication for both private and shared accounts
pack.setUserAuthentication({
type: coda.AuthenticationType.OAuth2,
authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
tokenUrl: "https://oauth2.googleapis.com/token",
scopes: [
"https://www.googleapis.com/auth/drive.file", // Access to Google Drive files (for both private and shared accounts)
],
additionalParams: {
access_type: "offline", // Allows refresh tokens for long-term access
prompt: "consent", // Ensures the user can select between private and shared accounts
},
});
// Function to extract folder ID from URL
function extractFolderIdFromUrl(folderUrl?: string): string | undefined {
if (!folderUrl) return undefined;
const parts = folderUrl.split("/folders/");
if (parts.length > 1) {
return parts[1].split("?")[0]; // Remove any query parameters
}
return undefined;
}
// Function to handle API requests with token validation first
async function fetchWithTokenValidation(context: coda.ExecutionContext, fetchOptions: any) {
try {
let response = await context.fetcher.fetch(fetchOptions);
return response;
} catch (error) {
if (error.statusCode === 401) {
// Token expired, re-throw the error to trigger a token refresh by Coda
throw error;
}
// Handle other errors as normal
throw new Error(`API request failed. Status code: ${error.statusCode}, Message: ${error.message}`);
}
}
// Function to create a folder in Google Drive
async function createFolder(context: coda.ExecutionContext, folderName: string, parentFolderURL?: string): Promise<string> {
try {
// Extract folder ID from URL
const parentFolderId = extractFolderIdFromUrl(parentFolderURL);
const body = {
name: folderName,
mimeType: "application/vnd.google-apps.folder",
parents: parentFolderId ? [parentFolderId] : [],
};
const fetchOptions = {
method: "POST",
url: "https://www.googleapis.com/drive/v3/files?fields=id",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
};
const response = await fetchWithTokenValidation(context, fetchOptions);
if (response.status !== 200 && response.status !== 201) {
throw new Error(`Failed to create folder. Status code: ${response.status}`);
}
const newFolderId = response.body.id;
return `https://drive.google.com/drive/folders/${newFolderId}`;
} catch (error) {
throw new Error(`Error creating folder: ${error.message}`);
}
}
// CreateFolderAndGetURL action that returns the folder URL
pack.addFormula({
name: "CreateFolderAndGetURL",
description: "Creates a folder in Google Drive and returns the folder URL.",
parameters: [
coda.makeParameter({
type: coda.ParameterType.String,
name: "folderName",
description: "The name of the folder to create.",
}),
coda.makeParameter({
type: coda.ParameterType.String,
name: "parentFolderURL",
description: "The URL of the parent folder.",
optional: true,
}),
],
resultType:coda.ValueType.String,
isAction:true,
execute :async function ([folderName,parentFolderURL],context){
try {
const folderUrl=await createFolder(context, folderName, parentFolderURL);
return folderUrl;
}catch(error){
throw new Error(`Error in CreateFolderAndGetURL formula execution. ${error.message}`);
}
},
});
// CreateFolder action that returns success/failure message after creation
pack.addFormula({
name:'CreateFolder',
description:'Creates a folder in Google Drive and returns a success or failure message.',
parameters:[
coda.makeParameter({
type:coda.ParameterType.String,
name:'folderName',
description:'The name of the folder to create.',
}),
coda.makeParameter({
type:coda.ParameterType.String,
name:'parentFolderURL',
description:'The URL of the parent folder.',
optional:true,
}),
],
resultType:coda.ValueType.String,
isAction:true,
execute :async function ([folderName,parentFolderURL],context){
try {
await createFolder(context, folderName, parentFolderURL);
return `폴더 생성 성공!`;
}catch(error){
return `폴더 생성 실패! 오류 메시지:${error.message}`;
}
},
});
Hello!
I’m in the middle of making google drive folder pack.
I think I did eveyrthing right to satisfy Oauth 2.0 requirements, especially for token expiry, but everytime I use the buttons in different computers or time passes, this pack keeps giving me 401 error. What should I do? Thank you!!