From 4c8f3d6a9710fcb6b0b2604c8c756b787bfaf226 Mon Sep 17 00:00:00 2001 From: Rene Enriquez Date: Sun, 20 Sep 2020 02:40:01 -0500 Subject: [PATCH 1/4] sending slack messages on clock out --- .gitignore | 1 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/vcs.xml | 6 + AutomaticClockOuts/clock_out.js | 51 ++++++ AutomaticClockOuts/config.js | 5 +- AutomaticClockOuts/index.js | 66 ++++---- AutomaticClockOuts/msal_client.js | 28 ++++ AutomaticClockOuts/package-lock.json | 170 +++++++++++++++++++- AutomaticClockOuts/package.json | 6 +- AutomaticClockOuts/readme.md | 11 +- AutomaticClockOuts/test/clock_out.spec.js | 12 ++ AutomaticClockOuts/test/index.spec.js | 0 AutomaticClockOuts/test/msal_client.spec.js | 17 ++ 13 files changed, 340 insertions(+), 38 deletions(-) create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/vcs.xml create mode 100644 AutomaticClockOuts/clock_out.js create mode 100644 AutomaticClockOuts/msal_client.js create mode 100644 AutomaticClockOuts/test/clock_out.spec.js delete mode 100644 AutomaticClockOuts/test/index.spec.js create mode 100644 AutomaticClockOuts/test/msal_client.spec.js diff --git a/.gitignore b/.gitignore index 4c799eb..fd06b40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +AutomaticClockOuts/.env bin obj csx diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/AutomaticClockOuts/clock_out.js b/AutomaticClockOuts/clock_out.js new file mode 100644 index 0000000..2f6c871 --- /dev/null +++ b/AutomaticClockOuts/clock_out.js @@ -0,0 +1,51 @@ +const CosmosClient = require("@azure/cosmos").CosmosClient; +const config = require("./config"); +const TimeEntry = require('./time_entry'); +const axios = require('axios'); +const MsalClient = require('./msal_client') + +const doClockOut = async (context, timer) => { + context.log(`I am going to check how many entries were not clocked out ${new Date()}`); + const {endpoint, key, databaseId, containerId, azureEndpoint} = config; + const client = new CosmosClient({endpoint, key}); + const database = client.database(databaseId); + const container = database.container(containerId); + const response = await MsalClient.findUsersInMS(); + const users = response.data.value; + + const QUERY_WITHOUT_END_DATE = + "SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)" + + const {resources: entries} = await container.items + .query({query: QUERY_WITHOUT_END_DATE}) + .fetchAll(); + + context.log(`Checking for time-entries that need to be clocked out`); + let totalClockOutsExecuted = 0; + await Promise.all(entries.map(async (timeEntryAsJson) => { + const timeEntry = new TimeEntry(timeEntryAsJson) + if (timeEntry.needsToBeClockedOut()) { + context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson)}`); + timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() + console.log(`I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`) + axios.post('https://hooks.slack.com/services/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', + {"text": `I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`} + ) + .then(function (response) { + console.log(response); + }) + .catch(function (error) { + console.log(error); + }); + console.log(JSON.stringify(timeEntry)) + totalClockOutsExecuted++ + } + })); + context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`); +} + +const findUser = (users, id) => { + return users.find( user => user.objectId === id) +} + +module.exports = { doClockOut }; diff --git a/AutomaticClockOuts/config.js b/AutomaticClockOuts/config.js index 09eb6f8..181eabd 100644 --- a/AutomaticClockOuts/config.js +++ b/AutomaticClockOuts/config.js @@ -3,7 +3,10 @@ const config = { key: process.env["COSMOS_DB_KEY"], databaseId: "time-tracker-db", containerId: "time_entry", - partitionKey: { kind: "Hash", paths: ["/category"] } + partitionKey: { kind: "Hash", paths: ["/category"] }, + client_id: process.env["MS_CLIENT_ID"], + authority: process.env["MS_AUTHORITY"], + clientSecret: process.env["MS_CLIENT_SECRET"] }; module.exports = config; diff --git a/AutomaticClockOuts/index.js b/AutomaticClockOuts/index.js index 155c030..eea97e5 100644 --- a/AutomaticClockOuts/index.js +++ b/AutomaticClockOuts/index.js @@ -1,33 +1,45 @@ const CosmosClient = require("@azure/cosmos").CosmosClient; -const moment = require("moment") const config = require("./config"); const TimeEntry = require('./time_entry'); +const axios = require('axios'); +const MsalClient = require('./msal_client'); +const ClockOut = require('./clock_out'); module.exports = async function (context, myTimer) { - - context.log(`I am going to check how many entries were not clocked out ${new Date()}`); - const {endpoint, key, databaseId, containerId} = config; - const client = new CosmosClient({endpoint, key}); - const database = client.database(databaseId); - const container = database.container(containerId); - - const QUERY_WITHOUT_END_DATE = - "SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)" - - const {resources: entries} = await container.items - .query({query: QUERY_WITHOUT_END_DATE}) - .fetchAll(); - - context.log(`Checking for time-entries that need to be clocked out`); - let totalClockOutsExecuted = 0; - await Promise.all(entries.map(async (timeEntryAsJson) => { - const timeEntry = new TimeEntry(timeEntryAsJson) - if (timeEntry.needsToBeClockedOut()) { - context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson.id)}`); - timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() - await container.item(timeEntryAsJson.id, timeEntryAsJson.tenant_id).replace(timeEntryAsJson) - totalClockOutsExecuted++ - } - })); - context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`); + context.log('starting.....................') + await ClockOut.doClockOut(context, myTimer) + // context.log(`I am going to check how many entries were not clocked out ${new Date()}`); + // const {endpoint, key, databaseId, containerId, azureEndpoint} = config; + // const client = new CosmosClient({endpoint, key}); + // const database = client.database(databaseId); + // const container = database.container(containerId); + // const users = await MsalClient.findUsersInMS(); + // + // const QUERY_WITHOUT_END_DATE = + // "SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)" + // + // const {resources: entries} = await container.items + // .query({query: QUERY_WITHOUT_END_DATE}) + // .fetchAll(); + // + // context.log(`Checking for time-entries that need to be clocked out`); + // let totalClockOutsExecuted = 0; + // await Promise.all(entries.map(async (timeEntryAsJson) => { + // const timeEntry = new TimeEntry(timeEntryAsJson) + // if (timeEntry.needsToBeClockedOut()) { + // context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson)}`); + // timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() + // axios.post('https://hooks.slack.com/services/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', + // {"text": `Hey, we clocked-out for you yesterday at midnight, please make sure to update your entered data`} + // ) + // .then(function (response) { + // console.log(response); + // }) + // .catch(function (error) { + // console.log(error); + // }); + // totalClockOutsExecuted++ + // } + // })); + // context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`); }; diff --git a/AutomaticClockOuts/msal_client.js b/AutomaticClockOuts/msal_client.js new file mode 100644 index 0000000..1a7c595 --- /dev/null +++ b/AutomaticClockOuts/msal_client.js @@ -0,0 +1,28 @@ +const axios = require("axios") +const msal = require('@azure/msal-node'); + +const findUsersInMS = async() => { + const endpoint = 'https://graph.windows.net/ioetec.onmicrosoft.com' + const config = { + auth: { + clientId: process.env["MS_CLIENT_ID"], + authority: process.env["MS_AUTHORITY"], + clientSecret: process.env["MS_CLIENT_SECRET"] + } + }; + + console.log('---------------------------------------------') + console.log(JSON.stringify(config)) + + const cca = new msal.ConfidentialClientApplication(config); + const clientCredentialRequest = { + scopes: ['https://graph.windows.net/.default'], + }; + const response = await cca.acquireTokenByClientCredential(clientCredentialRequest) + const token = response.accessToken + return axios.get(`${endpoint}/users?api-version=1.6&$select=displayName,otherMails,objectId`, + { 'headers': { 'Authorization': token } }) +} + +module.exports = { findUsersInMS }; + diff --git a/AutomaticClockOuts/package-lock.json b/AutomaticClockOuts/package-lock.json index 6deb375..0cc7627 100644 --- a/AutomaticClockOuts/package-lock.json +++ b/AutomaticClockOuts/package-lock.json @@ -21,6 +21,58 @@ "uuid": "^3.3.2" } }, + "@azure/msal-common": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-1.2.0.tgz", + "integrity": "sha512-5MjxcUoalIxGo29MBHCdwMo6HCsCBt25HDkg+Du7x6nG7Y3NAUb9jM8oibLTth9iIRDaWYVvLfxnpXTKwBGs+A==", + "requires": { + "debug": "^4.1.1" + } + }, + "@azure/msal-node": { + "version": "1.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.0.0-alpha.5.tgz", + "integrity": "sha512-DkoEmnGy+PF5UZbViuLrO8qJVKRBftIojEP3xf8ck6q/vjOY18NUGXxrcKkRXfhRmTe4P2mRGCFuiil8+12IbA==", + "requires": { + "@azure/msal-common": "^1.2.0", + "axios": "^0.19.2", + "debug": "^4.1.1", + "jsonwebtoken": "^8.5.1" + }, + "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "@babel/code-frame": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", @@ -395,6 +447,14 @@ "yargs": "^15.4.1" } }, + "axios": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -466,6 +526,11 @@ "fill-range": "^7.0.1" } }, + "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=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -859,12 +924,25 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "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" + } + }, "emittery": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.1.tgz", @@ -912,11 +990,6 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1005,6 +1078,11 @@ "path-exists": "^4.0.0" } }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1360,6 +1438,42 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1412,6 +1526,41 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", @@ -1607,6 +1756,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "msal": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/msal/-/msal-1.4.0.tgz", + "integrity": "sha512-NTxMFQh6t5g2QWMlvZTWTxL1bmcqiCv0cs2lxTHhUbWEuxWCfvaVRZfjxN8i+T0VltVVGaVIdML8QEoBnlbaSw==", + "requires": { + "tslib": "^1.9.3" + } + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -2093,8 +2250,7 @@ "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==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "semaphore": { "version": "1.1.0", diff --git a/AutomaticClockOuts/package.json b/AutomaticClockOuts/package.json index fb21eb7..e04938c 100644 --- a/AutomaticClockOuts/package.json +++ b/AutomaticClockOuts/package.json @@ -8,7 +8,11 @@ }, "dependencies": { "@azure/cosmos": "3.5.2", - "moment": "^2.27.0" + "@azure/msal-node": "^1.0.0-alpha.5", + "axios": "^0.20.0", + "dotenv": "^8.2.0", + "moment": "^2.27.0", + "msal": "^1.4.0" }, "author": "", "license": "ISC", diff --git a/AutomaticClockOuts/readme.md b/AutomaticClockOuts/readme.md index f53fc63..ae88d19 100644 --- a/AutomaticClockOuts/readme.md +++ b/AutomaticClockOuts/readme.md @@ -29,5 +29,12 @@ func azure functionapp publish time-tracker-azure-functions ``` NOTE: -Don't forget to set up the env variable `COSMOS_DB_KEY`, check the pinned -message in our slack channel to get this value +Don't forget to set the following environment variables to make this app work: + +```sh +COSMOS_DB_KEY +MS_CLIENT_ID +MS_AUTHORITY +MS_CLIENT_SECRET +``` +Check the pinned message in our slack channel to get these values diff --git a/AutomaticClockOuts/test/clock_out.spec.js b/AutomaticClockOuts/test/clock_out.spec.js new file mode 100644 index 0000000..d3b954a --- /dev/null +++ b/AutomaticClockOuts/test/clock_out.spec.js @@ -0,0 +1,12 @@ +const test = require('ava'); +const ClockOut = require('../clock_out') + +test('do clock out', async t => { + // const users = await MsalClient.findUsersInMS() + const log = (text) => console.log(text) + const context = { + log + } + // await ClockOut.doClockOut(context, null) + t.truthy(2>1) +}) diff --git a/AutomaticClockOuts/test/index.spec.js b/AutomaticClockOuts/test/index.spec.js deleted file mode 100644 index e69de29..0000000 diff --git a/AutomaticClockOuts/test/msal_client.spec.js b/AutomaticClockOuts/test/msal_client.spec.js new file mode 100644 index 0000000..2fe4ca6 --- /dev/null +++ b/AutomaticClockOuts/test/msal_client.spec.js @@ -0,0 +1,17 @@ +const test = require('ava'); +const MsalClient = require('../msal_client') + +test('Response contains ioet.com since users has it as part their emails', async t => { + const users = + // { + // data: { + // value: 'foo@ioet.com' + // } + // } + await MsalClient.findUsersInMS() + + console.log('---------------------------value') + console.log(users.data.value) + + t.truthy(JSON.stringify(users.data.value).includes("ioet.com")) +}) From 3b4754bf1a9acd6408d05fa3326415a84eb2e17f Mon Sep 17 00:00:00 2001 From: Rene Enriquez Date: Sun, 20 Sep 2020 02:43:51 -0500 Subject: [PATCH 2/4] fix issue with slack webhook --- AutomaticClockOuts/clock_out.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomaticClockOuts/clock_out.js b/AutomaticClockOuts/clock_out.js index 2f6c871..4b42459 100644 --- a/AutomaticClockOuts/clock_out.js +++ b/AutomaticClockOuts/clock_out.js @@ -28,7 +28,7 @@ const doClockOut = async (context, timer) => { context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson)}`); timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() console.log(`I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`) - axios.post('https://hooks.slack.com/services/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', + axios.post(process.env["SLACK_WEBHOOK"], {"text": `I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`} ) .then(function (response) { From e1a6813f9aab638d8adf24f3e208be78984c7c9d Mon Sep 17 00:00:00 2001 From: Rene Enriquez Date: Mon, 21 Sep 2020 23:37:09 -0500 Subject: [PATCH 3/4] send slack message on clock out --- AutomaticClockOuts/clock_out.js | 31 +++++++++++++++++------------ AutomaticClockOuts/index.js | 35 --------------------------------- 2 files changed, 18 insertions(+), 48 deletions(-) diff --git a/AutomaticClockOuts/clock_out.js b/AutomaticClockOuts/clock_out.js index 4b42459..1a46240 100644 --- a/AutomaticClockOuts/clock_out.js +++ b/AutomaticClockOuts/clock_out.js @@ -22,30 +22,35 @@ const doClockOut = async (context, timer) => { context.log(`Checking for time-entries that need to be clocked out`); let totalClockOutsExecuted = 0; + const usersWithClockOut = [] await Promise.all(entries.map(async (timeEntryAsJson) => { const timeEntry = new TimeEntry(timeEntryAsJson) if (timeEntry.needsToBeClockedOut()) { - context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson)}`); + usersWithClockOut.push(findUser(users, timeEntry.timeEntry.owner_id)) timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() - console.log(`I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`) - axios.post(process.env["SLACK_WEBHOOK"], - {"text": `I am doing it for you ${JSON.stringify(findUser(users, timeEntry.owner_id))}`} - ) - .then(function (response) { - console.log(response); - }) - .catch(function (error) { - console.log(error); - }); - console.log(JSON.stringify(timeEntry)) + await container.item(timeEntryAsJson.id, timeEntryAsJson.tenant_id).replace(timeEntryAsJson) totalClockOutsExecuted++ } })); + if(totalClockOutsExecuted > 0){ + axios.post(process.env["SLACK_WEBHOOK"], + { + "text": `Hey guys, I did a clock out for you. \nVisit https://timetracker.ioet.com/ and set the right end time for your entries :pls: \n- ${usersWithClockOut.join('\n- ')}` + } + ) + .then(function (response) { + // console.log(response); + }) + .catch(function (error) { + context.log(error); + }); + } context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`); } const findUser = (users, id) => { - return users.find( user => user.objectId === id) + const user = users.find( user => user.objectId === id) + return user.displayName } module.exports = { doClockOut }; diff --git a/AutomaticClockOuts/index.js b/AutomaticClockOuts/index.js index eea97e5..22de912 100644 --- a/AutomaticClockOuts/index.js +++ b/AutomaticClockOuts/index.js @@ -6,40 +6,5 @@ const MsalClient = require('./msal_client'); const ClockOut = require('./clock_out'); module.exports = async function (context, myTimer) { - context.log('starting.....................') await ClockOut.doClockOut(context, myTimer) - // context.log(`I am going to check how many entries were not clocked out ${new Date()}`); - // const {endpoint, key, databaseId, containerId, azureEndpoint} = config; - // const client = new CosmosClient({endpoint, key}); - // const database = client.database(databaseId); - // const container = database.container(containerId); - // const users = await MsalClient.findUsersInMS(); - // - // const QUERY_WITHOUT_END_DATE = - // "SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)" - // - // const {resources: entries} = await container.items - // .query({query: QUERY_WITHOUT_END_DATE}) - // .fetchAll(); - // - // context.log(`Checking for time-entries that need to be clocked out`); - // let totalClockOutsExecuted = 0; - // await Promise.all(entries.map(async (timeEntryAsJson) => { - // const timeEntry = new TimeEntry(timeEntryAsJson) - // if (timeEntry.needsToBeClockedOut()) { - // context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson)}`); - // timeEntryAsJson.end_date = timeEntry.getTimeToClockOut() - // axios.post('https://hooks.slack.com/services/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', - // {"text": `Hey, we clocked-out for you yesterday at midnight, please make sure to update your entered data`} - // ) - // .then(function (response) { - // console.log(response); - // }) - // .catch(function (error) { - // console.log(error); - // }); - // totalClockOutsExecuted++ - // } - // })); - // context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`); }; From d5d47e7c8dd62f4268e55a8b92737104c18e7ef7 Mon Sep 17 00:00:00 2001 From: Rene Enriquez Date: Wed, 23 Sep 2020 22:51:43 -0500 Subject: [PATCH 4/4] send slack message --- AutomaticClockOuts/clock_out.js | 4 ++-- AutomaticClockOuts/config.js | 11 ++++++----- AutomaticClockOuts/msal_client.js | 15 +++++++-------- AutomaticClockOuts/test/msal_client.spec.js | 11 +---------- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/AutomaticClockOuts/clock_out.js b/AutomaticClockOuts/clock_out.js index 1a46240..9807267 100644 --- a/AutomaticClockOuts/clock_out.js +++ b/AutomaticClockOuts/clock_out.js @@ -6,7 +6,7 @@ const MsalClient = require('./msal_client') const doClockOut = async (context, timer) => { context.log(`I am going to check how many entries were not clocked out ${new Date()}`); - const {endpoint, key, databaseId, containerId, azureEndpoint} = config; + const {endpoint, key, databaseId, containerId, slackWebHook} = config; const client = new CosmosClient({endpoint, key}); const database = client.database(databaseId); const container = database.container(containerId); @@ -33,7 +33,7 @@ const doClockOut = async (context, timer) => { } })); if(totalClockOutsExecuted > 0){ - axios.post(process.env["SLACK_WEBHOOK"], + axios.post(slackWebHook, { "text": `Hey guys, I did a clock out for you. \nVisit https://timetracker.ioet.com/ and set the right end time for your entries :pls: \n- ${usersWithClockOut.join('\n- ')}` } diff --git a/AutomaticClockOuts/config.js b/AutomaticClockOuts/config.js index 181eabd..2bdab84 100644 --- a/AutomaticClockOuts/config.js +++ b/AutomaticClockOuts/config.js @@ -1,12 +1,13 @@ const config = { - endpoint: "https://time-tracker-db.documents.azure.com:443/", - key: process.env["COSMOS_DB_KEY"], + endpoint: "xxx", + key: "xxx", databaseId: "time-tracker-db", containerId: "time_entry", partitionKey: { kind: "Hash", paths: ["/category"] }, - client_id: process.env["MS_CLIENT_ID"], - authority: process.env["MS_AUTHORITY"], - clientSecret: process.env["MS_CLIENT_SECRET"] + clientId: "xxx", + authority: "xxx", + clientSecret: "xxx", + slackWebHook: "xxx" }; module.exports = config; diff --git a/AutomaticClockOuts/msal_client.js b/AutomaticClockOuts/msal_client.js index 1a7c595..332cb5b 100644 --- a/AutomaticClockOuts/msal_client.js +++ b/AutomaticClockOuts/msal_client.js @@ -1,20 +1,19 @@ const axios = require("axios") const msal = require('@azure/msal-node'); +const config = require("./config"); const findUsersInMS = async() => { + const {clientId, authority, clientSecret} = config; const endpoint = 'https://graph.windows.net/ioetec.onmicrosoft.com' - const config = { + const configuration = { auth: { - clientId: process.env["MS_CLIENT_ID"], - authority: process.env["MS_AUTHORITY"], - clientSecret: process.env["MS_CLIENT_SECRET"] + clientId: clientId, + authority: authority, + clientSecret: clientSecret } }; - console.log('---------------------------------------------') - console.log(JSON.stringify(config)) - - const cca = new msal.ConfidentialClientApplication(config); + const cca = new msal.ConfidentialClientApplication(configuration); const clientCredentialRequest = { scopes: ['https://graph.windows.net/.default'], }; diff --git a/AutomaticClockOuts/test/msal_client.spec.js b/AutomaticClockOuts/test/msal_client.spec.js index 2fe4ca6..0717be1 100644 --- a/AutomaticClockOuts/test/msal_client.spec.js +++ b/AutomaticClockOuts/test/msal_client.spec.js @@ -2,16 +2,7 @@ const test = require('ava'); const MsalClient = require('../msal_client') test('Response contains ioet.com since users has it as part their emails', async t => { - const users = - // { - // data: { - // value: 'foo@ioet.com' - // } - // } - await MsalClient.findUsersInMS() - - console.log('---------------------------value') - console.log(users.data.value) + const users = await MsalClient.findUsersInMS() t.truthy(JSON.stringify(users.data.value).includes("ioet.com")) })