Skip to content

Commit 4b16887

Browse files
authored
Merge pull request #5 from ioet/feature/send-slack-notifications-on-midnight-notifications
Feature/send slack notifications on midnight notifications
2 parents bfe0c91 + d5d47e7 commit 4b16887

File tree

13 files changed

+303
-40
lines changed

13 files changed

+303
-40
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
AutomaticClockOuts/.env
12
bin
23
obj
34
csx

.idea/codeStyles/codeStyleConfig.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

AutomaticClockOuts/clock_out.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const CosmosClient = require("@azure/cosmos").CosmosClient;
2+
const config = require("./config");
3+
const TimeEntry = require('./time_entry');
4+
const axios = require('axios');
5+
const MsalClient = require('./msal_client')
6+
7+
const doClockOut = async (context, timer) => {
8+
context.log(`I am going to check how many entries were not clocked out ${new Date()}`);
9+
const {endpoint, key, databaseId, containerId, slackWebHook} = config;
10+
const client = new CosmosClient({endpoint, key});
11+
const database = client.database(databaseId);
12+
const container = database.container(containerId);
13+
const response = await MsalClient.findUsersInMS();
14+
const users = response.data.value;
15+
16+
const QUERY_WITHOUT_END_DATE =
17+
"SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)"
18+
19+
const {resources: entries} = await container.items
20+
.query({query: QUERY_WITHOUT_END_DATE})
21+
.fetchAll();
22+
23+
context.log(`Checking for time-entries that need to be clocked out`);
24+
let totalClockOutsExecuted = 0;
25+
const usersWithClockOut = []
26+
await Promise.all(entries.map(async (timeEntryAsJson) => {
27+
const timeEntry = new TimeEntry(timeEntryAsJson)
28+
if (timeEntry.needsToBeClockedOut()) {
29+
usersWithClockOut.push(findUser(users, timeEntry.timeEntry.owner_id))
30+
timeEntryAsJson.end_date = timeEntry.getTimeToClockOut()
31+
await container.item(timeEntryAsJson.id, timeEntryAsJson.tenant_id).replace(timeEntryAsJson)
32+
totalClockOutsExecuted++
33+
}
34+
}));
35+
if(totalClockOutsExecuted > 0){
36+
axios.post(slackWebHook,
37+
{
38+
"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- ')}`
39+
}
40+
)
41+
.then(function (response) {
42+
// console.log(response);
43+
})
44+
.catch(function (error) {
45+
context.log(error);
46+
});
47+
}
48+
context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`);
49+
}
50+
51+
const findUser = (users, id) => {
52+
const user = users.find( user => user.objectId === id)
53+
return user.displayName
54+
}
55+
56+
module.exports = { doClockOut };

AutomaticClockOuts/config.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
const config = {
2-
endpoint: "https://time-tracker-db.documents.azure.com:443/",
3-
key: process.env["COSMOS_DB_KEY"],
2+
endpoint: "xxx",
3+
key: "xxx",
44
databaseId: "time-tracker-db",
55
containerId: "time_entry",
6-
partitionKey: { kind: "Hash", paths: ["/category"] }
6+
partitionKey: { kind: "Hash", paths: ["/category"] },
7+
clientId: "xxx",
8+
authority: "xxx",
9+
clientSecret: "xxx",
10+
slackWebHook: "xxx"
711
};
812

913
module.exports = config;

AutomaticClockOuts/index.js

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
const CosmosClient = require("@azure/cosmos").CosmosClient;
2-
const moment = require("moment")
32
const config = require("./config");
43
const TimeEntry = require('./time_entry');
4+
const axios = require('axios');
5+
const MsalClient = require('./msal_client');
6+
const ClockOut = require('./clock_out');
57

68
module.exports = async function (context, myTimer) {
7-
8-
context.log(`I am going to check how many entries were not clocked out ${new Date()}`);
9-
const {endpoint, key, databaseId, containerId} = config;
10-
const client = new CosmosClient({endpoint, key});
11-
const database = client.database(databaseId);
12-
const container = database.container(containerId);
13-
14-
const QUERY_WITHOUT_END_DATE =
15-
"SELECT * FROM c WHERE (NOT IS_DEFINED(c.end_date) OR IS_NULL(c.end_date) = true) AND IS_DEFINED(c.start_date)"
16-
17-
const {resources: entries} = await container.items
18-
.query({query: QUERY_WITHOUT_END_DATE})
19-
.fetchAll();
20-
21-
context.log(`Checking for time-entries that need to be clocked out`);
22-
let totalClockOutsExecuted = 0;
23-
await Promise.all(entries.map(async (timeEntryAsJson) => {
24-
const timeEntry = new TimeEntry(timeEntryAsJson)
25-
if (timeEntry.needsToBeClockedOut()) {
26-
context.log(`I am going to clock out ${JSON.stringify(timeEntryAsJson.id)}`);
27-
timeEntryAsJson.end_date = timeEntry.getTimeToClockOut()
28-
await container.item(timeEntryAsJson.id, timeEntryAsJson.tenant_id).replace(timeEntryAsJson)
29-
totalClockOutsExecuted++
30-
}
31-
}));
32-
context.log(`I just clocked out ${totalClockOutsExecuted} entries, thanks are not needed...`);
9+
await ClockOut.doClockOut(context, myTimer)
3310
};

AutomaticClockOuts/msal_client.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const axios = require("axios")
2+
const msal = require('@azure/msal-node');
3+
const config = require("./config");
4+
5+
const findUsersInMS = async() => {
6+
const {clientId, authority, clientSecret} = config;
7+
const endpoint = 'https://graph.windows.net/ioetec.onmicrosoft.com'
8+
const configuration = {
9+
auth: {
10+
clientId: clientId,
11+
authority: authority,
12+
clientSecret: clientSecret
13+
}
14+
};
15+
16+
const cca = new msal.ConfidentialClientApplication(configuration);
17+
const clientCredentialRequest = {
18+
scopes: ['https://graph.windows.net/.default'],
19+
};
20+
const response = await cca.acquireTokenByClientCredential(clientCredentialRequest)
21+
const token = response.accessToken
22+
return axios.get(`${endpoint}/users?api-version=1.6&$select=displayName,otherMails,objectId`,
23+
{ 'headers': { 'Authorization': token } })
24+
}
25+
26+
module.exports = { findUsersInMS };
27+

0 commit comments

Comments
 (0)