You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(async()=>{constprocess=require('process');constfs=require('fs');constchild=require('child_process');const{ rword }=require('rword');constpath=require('path');constreadline=require('readline/promises').createInterface({input: process.stdin,output: process.stdout});rword.load('big');functioncreateProjectId(){constword1=rword.generate(1,{length: 4+Math.floor(Math.random()*7)});constword2=rword.generate(1,{length: 4+Math.floor(Math.random()*(30-8-word1.length-4))});return`${word1}-${word2}-${Math.floor(99999+Math.random()*900001)}`;}constexec=(command)=>child.execSync(command,{stdio: 'inherit'});functionversionTest({
name,
download =undefined,
command =undefined,
fail =true}){command=command||`${name} --version`;if(!/\d+\.\d/.test(child.execSync(command))){if(fail){console.error(`${name} is required${download ? `, install from ${download}` : ''}`);process.exit(1);}else{returnfalse;}}returntrue;}// TODO configure project nameconstappName='Blackbaud-to-Google Group Sync';// TODO configure project IDconstprojectId=createProjectId();constflags='--quiet --format=json';constflagsWithProject=`${flags} --project=${projectId}`;functiongcloud(command,withProjectId=true){letactualFlags=flagsWithProject;if(withProjectId===null){actualFlags='';}elseif(actualFlags===false){actualFlags=flags;}constresult=child.execSync(`gcloud ${command}${actualFlags} `);try{returnJSON.parse(result);}catch(e){returnresult;}}asyncfunctionchoiceFrom({ prompt, list, display, defaultChoice =1}){switch(list.length){case0:
thrownewError('empty list');case1:
defaultChoice=1;break;default:
if(defaultChoice>list.length){defaultChoice=undefined;}}console.log(prompt);list.forEach((item,i)=>console.log(` ${i}. ${item[display]}`));letchoice;letquestion=`(${defaultChoice>1 ? 1 : '[1]'}-${defaultChoice<list.length ? `[${defaultChoice}]` : ''}-${defaultChoice===list.length ? `[${defaultChoice}]` : list.length})`;do{choice=awaitreadline.question(question);if(choice.length){choice=(parseInt(choice)||0)-1;}else{choice=defaultChoice-1;}}while(choice<0||choice>=list.length);returnlist[choice];}asyncfunctionnonEmpty({ prompt }){letresponse;do{response=awaitreadline.question(prompt);}while(response.length===0);returnresponse;}asyncfunctionuntilBlank({ prompt }){constresponses=[];letresponse;do{response=awaitreadline.question(`${prompt} [<Enter> to end]`);if(response.length>0){responses.push(response);}}while(response.length>0);returnresponses;}// set project root as cwdprocess.chdir(path.join(__dirname,'..'));// test for CLI dependenciesversionTest({name: 'npm',download: 'https://nodejs.org/'});versionTest({name: 'composer',download: 'https://getcomposer.org/'});versionTest({name: 'gcloud',download: 'https://cloud.google.com/sdk/docs/install'});constpnpm=versionTest({name: 'pnpm',dowload: 'https://pnpm.io/',fail: false});// install dependenciesexec(`${pnpm ? 'pnpm' : 'npm'} install`);exec('composer install');// create a new projectletresponse=gcloud(`projects create --name="${appName}" ${projectId}`,false);if(/error/i.test(response)){console.error(response);process.exit(1);}// enable billinggcloud(`components install beta`,null);constaccountId=path.basename((awaitchoiceFrom({prompt: 'Select a billing account for this project',list: gcloud(`beta billing accounts list --filter=open=true`),display: 'displayName'})).name);gcloud(`beta billing projects link ${projectId} --billing-account="${accountId}`,false);// enable APIsgcloud(`services enable admin.googleapis.com`);gcloud(`services enable iap.googleapis.com`);gcloud(`services enable secretmanager.googleapis.com`);gcloud(`services enable cloudscheduler.googleapis.com`);gcloud(`services enable appengine.googleapis.com`);// configure workspace admin as owner// TODO output directions/linksconstgoogleDelegatedAdmin=awaitreadline.question('Enter the Google ID for a Workspace Admin who will delegate authority for this app');gcloud(`projects add-iam-policy-binding ${projectId} --member="user:${googleDelegatedAdmin}" --role="roles/owner"`,false);// create App Engine instance// TODO set default region us-east4constregion=awaitchoiceFrom({prompt: 'Select a region for the app engine instance',list: gcloud(`app regions list`),display: 'region'}).region;gcloud(`app create --region=${region}`);consturl=`https://${gcloud(`app describe`).defaultHostname}`;fs.writeFileSync('.env',`PROJECT=${projectId}URL=${url}`);// create default instance so IAP can be configuredexec(`npm run build`);exec(`npm run deploy`);// configure IAP (and OAuth consent screen)constsupportEmail=awaitnonEmpty({prompt: 'Enter a support email address for the app'});constbrand=gcloud(`iap oauth-brands create --application_title${appName} --support_email=${supportEmail}`).name;constoauth=gcloud(`iap oauth-clients create ${brand} --display_name=IAP-App-Engine-app`);gcloud(`iap web enable --resource-type=app-engine --oauth2-client-id=${path.basename(oauth.name)} --oauth2-client-secret=${oauth.secret}`);(awaituntilBlank({prompt: 'Email address of user who can access the app interface'})).forEach((userEmail)=>gcloud(`projects add-iam-policy-binding ${projectId} --member="user:${userEmail}" --role="roles/iap.httpsResourceAccessor"`,false));// configure Blackbaud SKY appconstblackbaudAccessKey=awaitnonEmpty({prompt:
'Enter a subscription access key from https://developer.blackbaud.com/subscriptions'});console.log('Create a new app at https://developer.blackbaud.com/apps');constblackbaudClientId=awaitnonEmpty({prompt: "Enter the app's OAuth client ID"});constblackbaudClientSecret=awaitnonEmpty({prompt: "Enter one of the app's OAuth secrets"});constblackbaudRedirectUrl=`${url}/redirect`;console.log(`Configure ${blackbaudRedirectUrl} as the app's redirect URL`);// TODO pause here?// TODO directions for limiting scope of app// configure delegated admin service accountconstserviceAccount=gcloud(`iam service-accounts create ${appName.toLowerCase().replace(/[^a-z]/g,'-').replace(/--/g,'-')} --display-name="Google Delegated Admin"`);console.log(`${googleDelegatedAdmin} needs to follow the directions at https://github.com/groton-school/blackbaud-to-google-group-sync/blob/main/docs/google-workspace-admin.md`);constcredentials=`${serviceAccount.uniqueId}.json`;gcloud(`iam service-accounts keys create ${credentials} --iam-account=${serviceAccount.email}`);console.log(`The Service Account Unique ID is ${serviceAccount.uniqueId}`);// TODO pause here?// store secretsexec(`echo "${blackbaudAccessKey}" | gcloud secrets create BLACKBAUD_ACCESS_KEY --data-file=- ${flagsWithProject}`);exec(`echo "null" | gcloud secrets create BLACKBAUD_API_TOKEN --data-file=- ${flagsWithProject}`);exec(`echo "${blackbaudClientId}" | gcloud secrets create BLACKBAUD_CLIENT_ID --data-file=- ${flagsWithProject}`);exec(`echo "${blackbaudClientSecret}" | gcloud secrets create BLACKBAUD_CLIENT_SECRET --data-file=- ${flagsWithProject}`);exec(`echo "${blackbaudRedirectUrl}" | gcloud secrets create BLACKBAUD_REDIRECT_URL --data-file=- ${flagsWithProject}`);gcloud(`secrets create GOOGLE_CREDENTIALS --data-file=${credentials}`);fs.unlinkSync(credentials);exec(`echo "${googleDelegatedAdmin}" | gcloud secrets create GOOGLE_DELEGATED_ADMIN --data-file=- ${flagsWithProject}`);console.log(`Authorize the app at ${url}`);// TODO pause here?// schedule daily sync// TODO configurable schedule// TODO configurable job namegcloud(`scheduler jobs create app-engine daily-blackbaud-to-google-sync --schedule="0 1 * * *" --relative-url="/sync"`);})();
The text was updated successfully, but these errors were encountered:
https://api.github.com/groton-school/blackbaud-to-google-group-sync/blob/d87e266cf36df1864a097c23f7cfa7ac256f2f22/scripts/setup.js#L291
The text was updated successfully, but these errors were encountered: