Initial commit
This commit is contained in:
		
							
								
								
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules | ||||
| npm-debug.log | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| node_modules | ||||
| token.json | ||||
| credentials.json | ||||
							
								
								
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Based on node | ||||
| FROM node:13-alpine | ||||
|  | ||||
| RUN apk add git | ||||
|  | ||||
| # Create app directory | ||||
| WORKDIR /usr/src/app | ||||
|  | ||||
| # Install app dependencies | ||||
| RUN git clone https://git.heshapps.com/asolkar/mma-gpacts-app.git . | ||||
|  | ||||
| RUN npm install | ||||
| RUN npm ci --only=production | ||||
|  | ||||
| EXPOSE 3000 | ||||
| CMD ["node", "index.js"] | ||||
|  | ||||
							
								
								
									
										47
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| # Build docker image | ||||
|  | ||||
|     % cd <app source directory> | ||||
|     % docker build --tag mahesh/mma-gpacts-app --no-cache . | ||||
|  | ||||
| *Note*: If `--no-cache` is not used, cloning of git repo from the docker file does not work in subsequent builds | ||||
|  | ||||
| # Run docker container | ||||
|  | ||||
|     % docker run --publish 49330:3000 --detach mahesh/mma-gpacts-app | ||||
|     7e4dfed65d776e3c8cd8e5c6e970699b561bbbc6f2d63d5d75b7ee68c9672358 | ||||
|  | ||||
| # Get a shell in running container | ||||
|  | ||||
|     % docker exec --interactive --tty 7e4dfed65d776e3c8cd8e5c6e970699b561bbbc6f2d63d5d75b7ee68c9672358 /bin/bash | ||||
|  | ||||
| # Manage docker containers | ||||
|  | ||||
| * List running containers | ||||
|  | ||||
| ``` | ||||
|     % docker ps | ||||
|     CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                     NAMES | ||||
|     d511b20c73d6        mahesh/mma-gpacts-app "docker-entrypoint.s…"   8 minutes ago       Up 8 minutes        0.0.0.0:49330->3000/tcp   upbeat_lederberg | ||||
| ``` | ||||
|  | ||||
| * List all docker containrs | ||||
|  | ||||
| ``` | ||||
|     % docker ps --all | ||||
|     CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                       PORTS               NAMES | ||||
|     d511b20c73d6        mahesh/mma-gpacts-app  "docker-entrypoint.s…"   12 minutes ago      Exited (137) 3 minutes ago                       upbeat_lederberg | ||||
|     % docker ps --all --quiet | ||||
|     d511b20c73d6 | ||||
| ``` | ||||
|  | ||||
| * Stop a running container | ||||
|  | ||||
| ``` | ||||
|     % docker stop d511b20c73d6 | ||||
| ``` | ||||
|  | ||||
| * Remove a container | ||||
|  | ||||
| ``` | ||||
|     % docker rm d511b20c73d6 | ||||
| ``` | ||||
							
								
								
									
										94
									
								
								auth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								auth.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| // Authentication tasks | ||||
| // -------------------- | ||||
| const fs        = require('fs'); | ||||
| const {google}  = require('googleapis'); | ||||
|  | ||||
| // If modifying these scopes, delete token.json. | ||||
| const SCOPES = ['https://www.googleapis.com/auth/photoslibrary.readonly.appcreateddata']; | ||||
|  | ||||
| // The file token.json stores the user's access and refresh tokens, and is | ||||
| // created automatically when the authorization flow completes for the first | ||||
| // time. | ||||
| const TOKEN_PATH = 'token.json'; | ||||
|  | ||||
| function run(req, res, callback) { | ||||
|     // Load client secrets from a local file. | ||||
|     fs.readFile('credentials.json', (err, content) => { | ||||
|         if (err) { | ||||
|             return console.log('Error loading client secret file:', err); | ||||
|         } | ||||
|         // Authorize a client with credentials, then call the Google Drive API. | ||||
|         authorize(JSON.parse(content), req, res, callback); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| // Authentication related | ||||
| function auth_redirect(req, res) { | ||||
|     // Load client secrets from a local file. | ||||
|     fs.readFile('credentials.json', (err, content) => { | ||||
|         if (err) { | ||||
|             return console.log('Error loading client secret file:', err); | ||||
|         } | ||||
|  | ||||
|         // Authorize a client with credentials | ||||
|         const credentials = JSON.parse(content); | ||||
|         const {client_secret, client_id, redirect_uris} = credentials.web; | ||||
|         const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]); | ||||
|         // oAuth2Client.getToken(ur.searchParams.get("code"), (err, token) => { | ||||
|         oAuth2Client.getToken(req.param("code"), (err, token) => { | ||||
|             if (err) { | ||||
|                 return console.error('Error retrieving access token', err); | ||||
|             } | ||||
|  | ||||
|             oAuth2Client.setCredentials(token); | ||||
|             // Store the token to disk for later program executions | ||||
|             fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => { | ||||
|                 if (err) return console.error(err); | ||||
|                 console.log('Token stored to', TOKEN_PATH); | ||||
|             }); | ||||
|  | ||||
|             res.redirect(301, '/tiny'); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create an OAuth2 client with the given credentials, and then execute the | ||||
|  * given callback function. | ||||
|  * @param {Object} credentials The authorization client credentials. | ||||
|  * @param {function} callback The callback to call with the authorized client. | ||||
|  */ | ||||
| function authorize(credentials, req, res, callback) { | ||||
|     const {client_secret, client_id, redirect_uris} = credentials.web; | ||||
|     const oAuth2Client = new google.auth.OAuth2( | ||||
|         client_id, client_secret, redirect_uris[0]); | ||||
|  | ||||
|     // Check if we have previously stored a token. | ||||
|     fs.readFile(TOKEN_PATH, (err, token) => { | ||||
|         if (err) return getAccessToken(oAuth2Client, req, res, callback); | ||||
|         oAuth2Client.setCredentials(JSON.parse(token)); | ||||
|         callback(req, res); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get and store new token after prompting for user authorization, and then | ||||
|  * execute the given callback with the authorized OAuth2 client. | ||||
|  * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for. | ||||
|  * @param {getEventsCallback} callback The callback for the authorized client. | ||||
|  */ | ||||
| function getAccessToken(oAuth2Client, req, res, callback) { | ||||
|     const authUrl = oAuth2Client.generateAuthUrl({ | ||||
|         access_type: 'online', | ||||
|         scope: SCOPES, | ||||
|     }); | ||||
|     res.redirect(301, authUrl); | ||||
| } | ||||
|  | ||||
| // Exported functions | ||||
| module.exports = { | ||||
|     run: run, | ||||
|     redirect: auth_redirect | ||||
| } | ||||
|  | ||||
| // vim: ai ts=4 sts=4 et sw=4 ft=javascript | ||||
							
								
								
									
										9
									
								
								config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| // App configuration | ||||
| // ----------------- | ||||
| module.exports = { | ||||
|     app_name: 'Google Photos Actions', | ||||
|     hostname: '0.0.0.0', | ||||
|     port: 3000 | ||||
| } | ||||
|  | ||||
| // vim: ai ts=4 sts=4 et sw=4 ft=javascript | ||||
							
								
								
									
										34
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const express   = require('express') | ||||
|  | ||||
| // ---------------------------------------------------------------------- | ||||
| var config  = require('./config.js'); | ||||
| var auth    = require('./auth.js'); | ||||
| var tasks   = require('./tasks.js'); | ||||
|  | ||||
| var app     = express(); | ||||
|  | ||||
| // ---------------------------------------------------------------------- | ||||
| // Routes: | ||||
|  | ||||
| // - Home page | ||||
| app.get('/',            (req, res) => tasks.home_page(req, res)); | ||||
|  | ||||
| // - Redirect for OAuth | ||||
| app.get('/redirect',    (req, res) => auth.redirect(req, res)); | ||||
|  | ||||
| // - Authenticated routes | ||||
| app.get('/tiny',        (req, res) => auth.run(req, res, tasks.tiny_photos)); | ||||
|  | ||||
| // - Assets | ||||
| app.get('/favicon.ico', (req, res) => res.sendStatus(204)); | ||||
|  | ||||
| // - Default (404) | ||||
| app.get('*',            (req, res) => tasks.not_found(req, res)); | ||||
|  | ||||
| // ---------------------------------------------------------------------- | ||||
| // Launch App | ||||
| app.listen(config.port, () => console.log(`${config.app_name} running on port ${config.port}!`)) | ||||
|  | ||||
| // vim: ai ts=4 sts=4 et sw=4 ft=javascript | ||||
							
								
								
									
										672
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										672
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,672 @@ | ||||
| { | ||||
|     "name": "mma_gp_acts_app", | ||||
|     "version": "0.1", | ||||
|     "lockfileVersion": 1, | ||||
|     "requires": true, | ||||
|     "dependencies": { | ||||
|         "abort-controller": { | ||||
|             "version": "3.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", | ||||
|             "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", | ||||
|             "requires": { | ||||
|                 "event-target-shim": "^5.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "accepts": { | ||||
|             "version": "1.3.7", | ||||
|             "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", | ||||
|             "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", | ||||
|             "requires": { | ||||
|                 "mime-types": "~2.1.24", | ||||
|                 "negotiator": "0.6.2" | ||||
|             } | ||||
|         }, | ||||
|         "agent-base": { | ||||
|             "version": "6.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", | ||||
|             "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", | ||||
|             "requires": { | ||||
|                 "debug": "4" | ||||
|             } | ||||
|         }, | ||||
|         "array-flatten": { | ||||
|             "version": "1.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", | ||||
|             "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" | ||||
|         }, | ||||
|         "arrify": { | ||||
|             "version": "2.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", | ||||
|             "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" | ||||
|         }, | ||||
|         "base64-js": { | ||||
|             "version": "1.3.1", | ||||
|             "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", | ||||
|             "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" | ||||
|         }, | ||||
|         "bignumber.js": { | ||||
|             "version": "7.2.1", | ||||
|             "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", | ||||
|             "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" | ||||
|         }, | ||||
|         "body-parser": { | ||||
|             "version": "1.19.0", | ||||
|             "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", | ||||
|             "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", | ||||
|             "requires": { | ||||
|                 "bytes": "3.1.0", | ||||
|                 "content-type": "~1.0.4", | ||||
|                 "debug": "2.6.9", | ||||
|                 "depd": "~1.1.2", | ||||
|                 "http-errors": "1.7.2", | ||||
|                 "iconv-lite": "0.4.24", | ||||
|                 "on-finished": "~2.3.0", | ||||
|                 "qs": "6.7.0", | ||||
|                 "raw-body": "2.4.0", | ||||
|                 "type-is": "~1.6.17" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "debug": { | ||||
|                     "version": "2.6.9", | ||||
|                     "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|                     "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|                     "requires": { | ||||
|                         "ms": "2.0.0" | ||||
|                     } | ||||
|                 }, | ||||
|                 "ms": { | ||||
|                     "version": "2.0.0", | ||||
|                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|                     "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | ||||
|                 }, | ||||
|                 "qs": { | ||||
|                     "version": "6.7.0", | ||||
|                     "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", | ||||
|                     "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "buffer-equal-constant-time": { | ||||
|             "version": "1.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", | ||||
|             "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" | ||||
|         }, | ||||
|         "bytes": { | ||||
|             "version": "3.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", | ||||
|             "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" | ||||
|         }, | ||||
|         "content-disposition": { | ||||
|             "version": "0.5.3", | ||||
|             "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", | ||||
|             "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", | ||||
|             "requires": { | ||||
|                 "safe-buffer": "5.1.2" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "safe-buffer": { | ||||
|                     "version": "5.1.2", | ||||
|                     "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | ||||
|                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "content-type": { | ||||
|             "version": "1.0.4", | ||||
|             "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", | ||||
|             "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" | ||||
|         }, | ||||
|         "cookie": { | ||||
|             "version": "0.4.0", | ||||
|             "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", | ||||
|             "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" | ||||
|         }, | ||||
|         "cookie-signature": { | ||||
|             "version": "1.0.6", | ||||
|             "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", | ||||
|             "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" | ||||
|         }, | ||||
|         "debug": { | ||||
|             "version": "4.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", | ||||
|             "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", | ||||
|             "requires": { | ||||
|                 "ms": "^2.1.1" | ||||
|             } | ||||
|         }, | ||||
|         "depd": { | ||||
|             "version": "1.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", | ||||
|             "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" | ||||
|         }, | ||||
|         "destroy": { | ||||
|             "version": "1.0.4", | ||||
|             "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", | ||||
|             "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" | ||||
|         }, | ||||
|         "ecdsa-sig-formatter": { | ||||
|             "version": "1.0.11", | ||||
|             "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", | ||||
|             "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", | ||||
|             "requires": { | ||||
|                 "safe-buffer": "^5.0.1" | ||||
|             } | ||||
|         }, | ||||
|         "ee-first": { | ||||
|             "version": "1.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | ||||
|             "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" | ||||
|         }, | ||||
|         "encodeurl": { | ||||
|             "version": "1.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", | ||||
|             "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" | ||||
|         }, | ||||
|         "escape-html": { | ||||
|             "version": "1.0.3", | ||||
|             "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | ||||
|             "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" | ||||
|         }, | ||||
|         "etag": { | ||||
|             "version": "1.8.1", | ||||
|             "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", | ||||
|             "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" | ||||
|         }, | ||||
|         "event-target-shim": { | ||||
|             "version": "5.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", | ||||
|             "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" | ||||
|         }, | ||||
|         "express": { | ||||
|             "version": "4.17.1", | ||||
|             "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", | ||||
|             "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", | ||||
|             "requires": { | ||||
|                 "accepts": "~1.3.7", | ||||
|                 "array-flatten": "1.1.1", | ||||
|                 "body-parser": "1.19.0", | ||||
|                 "content-disposition": "0.5.3", | ||||
|                 "content-type": "~1.0.4", | ||||
|                 "cookie": "0.4.0", | ||||
|                 "cookie-signature": "1.0.6", | ||||
|                 "debug": "2.6.9", | ||||
|                 "depd": "~1.1.2", | ||||
|                 "encodeurl": "~1.0.2", | ||||
|                 "escape-html": "~1.0.3", | ||||
|                 "etag": "~1.8.1", | ||||
|                 "finalhandler": "~1.1.2", | ||||
|                 "fresh": "0.5.2", | ||||
|                 "merge-descriptors": "1.0.1", | ||||
|                 "methods": "~1.1.2", | ||||
|                 "on-finished": "~2.3.0", | ||||
|                 "parseurl": "~1.3.3", | ||||
|                 "path-to-regexp": "0.1.7", | ||||
|                 "proxy-addr": "~2.0.5", | ||||
|                 "qs": "6.7.0", | ||||
|                 "range-parser": "~1.2.1", | ||||
|                 "safe-buffer": "5.1.2", | ||||
|                 "send": "0.17.1", | ||||
|                 "serve-static": "1.14.1", | ||||
|                 "setprototypeof": "1.1.1", | ||||
|                 "statuses": "~1.5.0", | ||||
|                 "type-is": "~1.6.18", | ||||
|                 "utils-merge": "1.0.1", | ||||
|                 "vary": "~1.1.2" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "debug": { | ||||
|                     "version": "2.6.9", | ||||
|                     "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|                     "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|                     "requires": { | ||||
|                         "ms": "2.0.0" | ||||
|                     } | ||||
|                 }, | ||||
|                 "ms": { | ||||
|                     "version": "2.0.0", | ||||
|                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|                     "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | ||||
|                 }, | ||||
|                 "qs": { | ||||
|                     "version": "6.7.0", | ||||
|                     "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", | ||||
|                     "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" | ||||
|                 }, | ||||
|                 "safe-buffer": { | ||||
|                     "version": "5.1.2", | ||||
|                     "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | ||||
|                     "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "extend": { | ||||
|             "version": "3.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", | ||||
|             "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" | ||||
|         }, | ||||
|         "fast-text-encoding": { | ||||
|             "version": "1.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.1.tgz", | ||||
|             "integrity": "sha512-x4FEgaz3zNRtJfLFqJmHWxkMDDvXVtaznj2V9jiP8ACUJrUgist4bP9FmDL2Vew2Y9mEQI/tG4GqabaitYp9CQ==" | ||||
|         }, | ||||
|         "finalhandler": { | ||||
|             "version": "1.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", | ||||
|             "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", | ||||
|             "requires": { | ||||
|                 "debug": "2.6.9", | ||||
|                 "encodeurl": "~1.0.2", | ||||
|                 "escape-html": "~1.0.3", | ||||
|                 "on-finished": "~2.3.0", | ||||
|                 "parseurl": "~1.3.3", | ||||
|                 "statuses": "~1.5.0", | ||||
|                 "unpipe": "~1.0.0" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "debug": { | ||||
|                     "version": "2.6.9", | ||||
|                     "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|                     "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|                     "requires": { | ||||
|                         "ms": "2.0.0" | ||||
|                     } | ||||
|                 }, | ||||
|                 "ms": { | ||||
|                     "version": "2.0.0", | ||||
|                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|                     "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "forwarded": { | ||||
|             "version": "0.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", | ||||
|             "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" | ||||
|         }, | ||||
|         "fresh": { | ||||
|             "version": "0.5.2", | ||||
|             "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | ||||
|             "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" | ||||
|         }, | ||||
|         "gaxios": { | ||||
|             "version": "2.3.4", | ||||
|             "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.4.tgz", | ||||
|             "integrity": "sha512-US8UMj8C5pRnao3Zykc4AAVr+cffoNKRTg9Rsf2GiuZCW69vgJj38VK2PzlPuQU73FZ/nTk9/Av6/JGcE1N9vA==", | ||||
|             "requires": { | ||||
|                 "abort-controller": "^3.0.0", | ||||
|                 "extend": "^3.0.2", | ||||
|                 "https-proxy-agent": "^5.0.0", | ||||
|                 "is-stream": "^2.0.0", | ||||
|                 "node-fetch": "^2.3.0" | ||||
|             } | ||||
|         }, | ||||
|         "gcp-metadata": { | ||||
|             "version": "3.5.0", | ||||
|             "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.5.0.tgz", | ||||
|             "integrity": "sha512-ZQf+DLZ5aKcRpLzYUyBS3yo3N0JSa82lNDO8rj3nMSlovLcz2riKFBsYgDzeXcv75oo5eqB2lx+B14UvPoCRnA==", | ||||
|             "requires": { | ||||
|                 "gaxios": "^2.1.0", | ||||
|                 "json-bigint": "^0.3.0" | ||||
|             } | ||||
|         }, | ||||
|         "google-auth-library": { | ||||
|             "version": "5.10.1", | ||||
|             "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", | ||||
|             "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", | ||||
|             "requires": { | ||||
|                 "arrify": "^2.0.0", | ||||
|                 "base64-js": "^1.3.0", | ||||
|                 "ecdsa-sig-formatter": "^1.0.11", | ||||
|                 "fast-text-encoding": "^1.0.0", | ||||
|                 "gaxios": "^2.1.0", | ||||
|                 "gcp-metadata": "^3.4.0", | ||||
|                 "gtoken": "^4.1.0", | ||||
|                 "jws": "^4.0.0", | ||||
|                 "lru-cache": "^5.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "google-p12-pem": { | ||||
|             "version": "2.0.4", | ||||
|             "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", | ||||
|             "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", | ||||
|             "requires": { | ||||
|                 "node-forge": "^0.9.0" | ||||
|             } | ||||
|         }, | ||||
|         "googleapis": { | ||||
|             "version": "48.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-48.0.0.tgz", | ||||
|             "integrity": "sha512-ysp0/GN1BdOC8no1M6Pn/jS445xLL/FiTRa+aYJXD/HhtWFb+NOlNSfHIVnLjlQZsCn6L4qj1EpOaM/979nnEw==", | ||||
|             "requires": { | ||||
|                 "google-auth-library": "^5.6.1", | ||||
|                 "googleapis-common": "^3.2.0" | ||||
|             } | ||||
|         }, | ||||
|         "googleapis-common": { | ||||
|             "version": "3.2.2", | ||||
|             "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-3.2.2.tgz", | ||||
|             "integrity": "sha512-sTEXlauVce4eMX0S6hVoiWgxVzQZ7dc16KcGF7eh+A+uIyDgXqnuwOMZw+svX4gOJv6w4ACecm23Qh9UDaldsw==", | ||||
|             "requires": { | ||||
|                 "extend": "^3.0.2", | ||||
|                 "gaxios": "^2.0.1", | ||||
|                 "google-auth-library": "^5.6.1", | ||||
|                 "qs": "^6.7.0", | ||||
|                 "url-template": "^2.0.8", | ||||
|                 "uuid": "^7.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "gtoken": { | ||||
|             "version": "4.1.4", | ||||
|             "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", | ||||
|             "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", | ||||
|             "requires": { | ||||
|                 "gaxios": "^2.1.0", | ||||
|                 "google-p12-pem": "^2.0.0", | ||||
|                 "jws": "^4.0.0", | ||||
|                 "mime": "^2.2.0" | ||||
|             } | ||||
|         }, | ||||
|         "http-errors": { | ||||
|             "version": "1.7.2", | ||||
|             "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", | ||||
|             "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", | ||||
|             "requires": { | ||||
|                 "depd": "~1.1.2", | ||||
|                 "inherits": "2.0.3", | ||||
|                 "setprototypeof": "1.1.1", | ||||
|                 "statuses": ">= 1.5.0 < 2", | ||||
|                 "toidentifier": "1.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "https-proxy-agent": { | ||||
|             "version": "5.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", | ||||
|             "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", | ||||
|             "requires": { | ||||
|                 "agent-base": "6", | ||||
|                 "debug": "4" | ||||
|             } | ||||
|         }, | ||||
|         "iconv-lite": { | ||||
|             "version": "0.4.24", | ||||
|             "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", | ||||
|             "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", | ||||
|             "requires": { | ||||
|                 "safer-buffer": ">= 2.1.2 < 3" | ||||
|             } | ||||
|         }, | ||||
|         "inherits": { | ||||
|             "version": "2.0.3", | ||||
|             "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", | ||||
|             "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" | ||||
|         }, | ||||
|         "ipaddr.js": { | ||||
|             "version": "1.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", | ||||
|             "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" | ||||
|         }, | ||||
|         "is-stream": { | ||||
|             "version": "2.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", | ||||
|             "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" | ||||
|         }, | ||||
|         "json-bigint": { | ||||
|             "version": "0.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", | ||||
|             "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", | ||||
|             "requires": { | ||||
|                 "bignumber.js": "^7.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "jwa": { | ||||
|             "version": "2.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", | ||||
|             "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", | ||||
|             "requires": { | ||||
|                 "buffer-equal-constant-time": "1.0.1", | ||||
|                 "ecdsa-sig-formatter": "1.0.11", | ||||
|                 "safe-buffer": "^5.0.1" | ||||
|             } | ||||
|         }, | ||||
|         "jws": { | ||||
|             "version": "4.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", | ||||
|             "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", | ||||
|             "requires": { | ||||
|                 "jwa": "^2.0.0", | ||||
|                 "safe-buffer": "^5.0.1" | ||||
|             } | ||||
|         }, | ||||
|         "lru-cache": { | ||||
|             "version": "5.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", | ||||
|             "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", | ||||
|             "requires": { | ||||
|                 "yallist": "^3.0.2" | ||||
|             } | ||||
|         }, | ||||
|         "media-typer": { | ||||
|             "version": "0.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", | ||||
|             "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" | ||||
|         }, | ||||
|         "merge-descriptors": { | ||||
|             "version": "1.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", | ||||
|             "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" | ||||
|         }, | ||||
|         "methods": { | ||||
|             "version": "1.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", | ||||
|             "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" | ||||
|         }, | ||||
|         "mime": { | ||||
|             "version": "2.4.4", | ||||
|             "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", | ||||
|             "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" | ||||
|         }, | ||||
|         "mime-db": { | ||||
|             "version": "1.43.0", | ||||
|             "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", | ||||
|             "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" | ||||
|         }, | ||||
|         "mime-types": { | ||||
|             "version": "2.1.26", | ||||
|             "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", | ||||
|             "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", | ||||
|             "requires": { | ||||
|                 "mime-db": "1.43.0" | ||||
|             } | ||||
|         }, | ||||
|         "ms": { | ||||
|             "version": "2.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||
|             "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | ||||
|         }, | ||||
|         "negotiator": { | ||||
|             "version": "0.6.2", | ||||
|             "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", | ||||
|             "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" | ||||
|         }, | ||||
|         "node-fetch": { | ||||
|             "version": "2.6.0", | ||||
|             "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | ||||
|             "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | ||||
|         }, | ||||
|         "node-forge": { | ||||
|             "version": "0.9.1", | ||||
|             "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", | ||||
|             "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" | ||||
|         }, | ||||
|         "on-finished": { | ||||
|             "version": "2.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", | ||||
|             "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", | ||||
|             "requires": { | ||||
|                 "ee-first": "1.1.1" | ||||
|             } | ||||
|         }, | ||||
|         "parseurl": { | ||||
|             "version": "1.3.3", | ||||
|             "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", | ||||
|             "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" | ||||
|         }, | ||||
|         "path-to-regexp": { | ||||
|             "version": "0.1.7", | ||||
|             "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", | ||||
|             "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" | ||||
|         }, | ||||
|         "proxy-addr": { | ||||
|             "version": "2.0.6", | ||||
|             "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", | ||||
|             "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", | ||||
|             "requires": { | ||||
|                 "forwarded": "~0.1.2", | ||||
|                 "ipaddr.js": "1.9.1" | ||||
|             } | ||||
|         }, | ||||
|         "qs": { | ||||
|             "version": "6.9.3", | ||||
|             "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", | ||||
|             "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==" | ||||
|         }, | ||||
|         "range-parser": { | ||||
|             "version": "1.2.1", | ||||
|             "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", | ||||
|             "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" | ||||
|         }, | ||||
|         "raw-body": { | ||||
|             "version": "2.4.0", | ||||
|             "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", | ||||
|             "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", | ||||
|             "requires": { | ||||
|                 "bytes": "3.1.0", | ||||
|                 "http-errors": "1.7.2", | ||||
|                 "iconv-lite": "0.4.24", | ||||
|                 "unpipe": "1.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "safe-buffer": { | ||||
|             "version": "5.2.0", | ||||
|             "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", | ||||
|             "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" | ||||
|         }, | ||||
|         "safer-buffer": { | ||||
|             "version": "2.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||||
|             "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" | ||||
|         }, | ||||
|         "send": { | ||||
|             "version": "0.17.1", | ||||
|             "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", | ||||
|             "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", | ||||
|             "requires": { | ||||
|                 "debug": "2.6.9", | ||||
|                 "depd": "~1.1.2", | ||||
|                 "destroy": "~1.0.4", | ||||
|                 "encodeurl": "~1.0.2", | ||||
|                 "escape-html": "~1.0.3", | ||||
|                 "etag": "~1.8.1", | ||||
|                 "fresh": "0.5.2", | ||||
|                 "http-errors": "~1.7.2", | ||||
|                 "mime": "1.6.0", | ||||
|                 "ms": "2.1.1", | ||||
|                 "on-finished": "~2.3.0", | ||||
|                 "range-parser": "~1.2.1", | ||||
|                 "statuses": "~1.5.0" | ||||
|             }, | ||||
|             "dependencies": { | ||||
|                 "debug": { | ||||
|                     "version": "2.6.9", | ||||
|                     "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|                     "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|                     "requires": { | ||||
|                         "ms": "2.0.0" | ||||
|                     }, | ||||
|                     "dependencies": { | ||||
|                         "ms": { | ||||
|                             "version": "2.0.0", | ||||
|                             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | ||||
|                             "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 "mime": { | ||||
|                     "version": "1.6.0", | ||||
|                     "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", | ||||
|                     "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" | ||||
|                 }, | ||||
|                 "ms": { | ||||
|                     "version": "2.1.1", | ||||
|                     "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", | ||||
|                     "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "serve-static": { | ||||
|             "version": "1.14.1", | ||||
|             "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", | ||||
|             "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", | ||||
|             "requires": { | ||||
|                 "encodeurl": "~1.0.2", | ||||
|                 "escape-html": "~1.0.3", | ||||
|                 "parseurl": "~1.3.3", | ||||
|                 "send": "0.17.1" | ||||
|             } | ||||
|         }, | ||||
|         "setprototypeof": { | ||||
|             "version": "1.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", | ||||
|             "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" | ||||
|         }, | ||||
|         "statuses": { | ||||
|             "version": "1.5.0", | ||||
|             "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", | ||||
|             "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" | ||||
|         }, | ||||
|         "toidentifier": { | ||||
|             "version": "1.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", | ||||
|             "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" | ||||
|         }, | ||||
|         "type-is": { | ||||
|             "version": "1.6.18", | ||||
|             "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", | ||||
|             "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", | ||||
|             "requires": { | ||||
|                 "media-typer": "0.3.0", | ||||
|                 "mime-types": "~2.1.24" | ||||
|             } | ||||
|         }, | ||||
|         "unpipe": { | ||||
|             "version": "1.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", | ||||
|             "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" | ||||
|         }, | ||||
|         "url-template": { | ||||
|             "version": "2.0.8", | ||||
|             "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", | ||||
|             "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" | ||||
|         }, | ||||
|         "utils-merge": { | ||||
|             "version": "1.0.1", | ||||
|             "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", | ||||
|             "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" | ||||
|         }, | ||||
|         "uuid": { | ||||
|             "version": "7.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz", | ||||
|             "integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw==" | ||||
|         }, | ||||
|         "vary": { | ||||
|             "version": "1.1.2", | ||||
|             "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", | ||||
|             "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" | ||||
|         }, | ||||
|         "yallist": { | ||||
|             "version": "3.1.1", | ||||
|             "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", | ||||
|             "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| { | ||||
|     "name": "mma_gp_acts_app", | ||||
|     "version": "0.1", | ||||
|     "description": "Google Photos Actions app", | ||||
|     "author": "Mahesh Asolkar <mahesh@mahesha.com>", | ||||
|     "main": "index.js", | ||||
|     "scripts": { | ||||
|         "start": "node main.js" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "express": "^4.17.1", | ||||
|         "googleapis": "^48.0.0" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										62
									
								
								page.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								page.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Page template tasks | ||||
| // ------------------- | ||||
|  | ||||
| var config = require('./config.js'); | ||||
|  | ||||
| function page_style() { | ||||
|     return ` | ||||
| .title { | ||||
|     font-family: 'Bowlby One SC', cursive; | ||||
|     font-size: xx-large; | ||||
|     text-align: center; | ||||
|     margin-top: 200px; | ||||
| } | ||||
| .heading { | ||||
|     font-family: 'Special Elite', cursive; | ||||
|     font-size: large; | ||||
|     text-align: center; | ||||
|     margin-top: 20px; | ||||
|     margin-bottom: 20px; | ||||
| } | ||||
| .content { | ||||
|     font-family: sans-serif; | ||||
|     font-size: medium; | ||||
|     text-align: center; | ||||
|     margin-top: 20px; | ||||
|     margin-bottom: 20px; | ||||
| } | ||||
| .yes { | ||||
|     color: green; | ||||
| } | ||||
| .no { | ||||
|     color: red; | ||||
| }`; | ||||
| } | ||||
|  | ||||
| function page_head(title) { | ||||
|     return `<html> | ||||
|   <head> | ||||
|     <title>${config.app_name}: ${title}</title> | ||||
|     <link href="https://fonts.googleapis.com/css?family=Bowlby+One+SC|Special+Elite&display=swap" | ||||
|     rel="stylesheet"> | ||||
|     <style type="text/css">` | ||||
|     + page_style() + | ||||
|     `</style> | ||||
|   </head> | ||||
|   <body> | ||||
|     <h1 class="title">${config.app_name}</h1> | ||||
|     <p class="content"><a href="/">Home</a> | <a href="/tiny">Tiny Photos</a></p>`; | ||||
| } | ||||
|  | ||||
| function page_tail() { | ||||
|     return `  </body> | ||||
| </html>`; | ||||
| } | ||||
|  | ||||
| // Exported functions | ||||
| module.exports = { | ||||
|     head: page_head, | ||||
|     tail: page_tail | ||||
| } | ||||
|  | ||||
| // vim: ai ts=4 sts=4 et sw=4 ft=javascript | ||||
							
								
								
									
										41
									
								
								tasks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tasks.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // Library of functions used in the app | ||||
| // ------------------------------------ | ||||
|  | ||||
| const {google}  = require('googleapis'); | ||||
|  | ||||
| var config = require('./config.js'); | ||||
| var auth   = require('./auth.js'); | ||||
| var page   = require('./page.js'); | ||||
|  | ||||
| function not_found(req, res) { | ||||
|     var pg = page.head("Page Not Found"); | ||||
|     pg += `<p class="content">404 - Page Not Found</p>`; | ||||
|     pg += page.tail(); | ||||
|  | ||||
|     res.status(404).send(pg); | ||||
| } | ||||
|  | ||||
| function home_page(req, res) { | ||||
|     var pg = page.head("Home"); | ||||
|     pg += `<p class="content">Welcome Home</p>`; | ||||
|     pg += page.tail(); | ||||
|  | ||||
|     res.send(pg); | ||||
| } | ||||
|  | ||||
| function tiny_photos(req, res) { | ||||
|     var pg = page.head("Tiny photos"); | ||||
|     pg += `<p class="content">These are the tiny photos in your library</p>`; | ||||
|     pg += page.tail(); | ||||
|  | ||||
|     res.send(pg); | ||||
| } | ||||
|  | ||||
| // Exported functions | ||||
| module.exports = { | ||||
|     not_found: not_found, | ||||
|     home_page: home_page, | ||||
|     tiny_photos: tiny_photos | ||||
| } | ||||
|  | ||||
| // vim: ai ts=4 sts=4 et sw=4 ft=javascript | ||||
		Reference in New Issue
	
	Block a user