Show today's absences in Slack

Before you get started

We are going to use Zapier to create a trigger that will call the Timmi Absences API every morning at 7am and post the day's absent list to Slack.

Note: Some of our clients use similar code with Google Cloud Engine.

Zapier is an online service for automating actions on the web. The principle is very simple: "If action X occurs in application A, then action Y occurs in application B"

zapier-how-to

We will create the following script "If it's 7am, ask Timmi Absences for the day's absent list and post the message to Slack"

Connecting to Zapier

You can connect here: https://zapier.com.

Create a new account or use an existing one.

Zap configuration

 

You need to configure the first step. The "Choose App" button displays a list of available tools. In the "Built-in apps" tab, you can then choose the clock.

You will then be asked to configure your clock. First, ask yourself how often you want the script to run, for example, every day.

 You can then choose what time of day to run the script, and whether or not you want it to run at weekends.

Once this step has been validated, you can test it using the last tab, "Test this Step". For the second step, which is the action step, we choose the "code" application.

 Choose Javascript

In the next step, you can copy this script into the "Code" section, leaving the "Input" section empty.

var urlBase = "https://xxxxxxxxxxx.ilucca.net/api/v3/leavesOfDay"


var appToken = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';


fetch(urlBase, {
"headers": { 

 "Authorization": "lucca application=" + appToken 

 } 

}) 

.then(function (res) {
return res.json();
}).then(function (data) {
  var entries = data.data.items;
var result = [];
for (var i = 0; i <entries.length; i++)="i++)" {="{">
var entry = entries[i];
var res = {
name: entry.user.displayName,
};
if(entry.startsAM && (!entry.endsAM || entry.endsOn != entry.startsOn)) {
res.detail = "all day";
} else if(entry.startsAM && entry.endsAM && entry.endsOn == entry.startsOn) {
res.detail = "this morning";
} else {
res.detail = "this afternoon";
}

if (entry.endsOn !== entry.startsOn) {
var endSp = entry.endsOn.split("T")[0].split("-");
res.detail += " and until " + endSp[2] + "/" + endSp[1] + "/" + endSp[0] + " including";
}
result.push(res);
}
if (result.length === 0) {
result.push({
name: "Person n'",
detail: "today"
});
}
callback(null, result);
}).catch(function (error) {
console.log(error);
});</entries.length;>

To use this script, you need to replace xxxxxxxxxxx in the urlBase variable with the name of your Lucca instance, and you will need to replace the appToken variable xxxxxxxxxxx-xxxxxxxx-xxxxxxxxxxxx with your own. This token can be obtained from the dedicated interface or by contacting the Lucca Help desk.

A paid Zapier account is (sometimes) required to perform this type in zap, otherwise the test may display an Error.

All you have to do now is configure the last action to send the results to one of your Slack channels.

Select the option "send a message to a channel"

For the next step, connect with your Slack login details. Then complete the options, starting with the channel name:

Once you have entered the channel name, you need to enter the message you want to display, as shown in the below example.

All you have to do now is validate this step and run the tests to complete the configuration.

Launching zap

You can start zap by pressing the "OFF" button to switch it to "ON".

Every morning at 7am Slack will give you a list of the day's absentees.

Advanced zap (for experts)

You can configure a zap in 5 steps that will notify the team in a dedicated channel a few days before the absence.

 

In step 2

add 4 Data inputs 

url: https://lucca.ilucca.net/api/v3/leaves?leavePeriod.ownerId=greaterthan,0

appToken:  your token

offsetDays: 2 (= be notified 2 days before)

numberDayMinimum: 0 (= be notified if there is a minimum of 0 consecutive days off)

Add the following code to the code section: 

// Function used to process the result retrieved with the request in order to send the results

var getCleanChannelName = function (channelName) {
channelName = channelName.replace(/\s+/g, '');
channelName = 'absence_' + channelName.toLocaleLowerCase();
return channelName;
}

var sendResult = function (results) {
var res = {};

res.list = [];
res.zapierLimitSize = 25;
if (input.validDepartment) {
res.validDepartmentList = input.validDepartment.toLocaleLowerCase().split(',');
for (var i = 0; i <res.validdepartmentlist.length; i++)="i++)" {="{"></res.validdepartmentlist.length;>
res.validDepartmentList[i] = getCleanChannelName(res.validDepartmentList[i]);
}
console.log(res.validDepartmentList);
}

res.channelExist = function (channelName) {
channelName = channelName.toLocaleLowerCase();
for (var index = 0; index <this.list.length; index++)="index++)" {="{"></this.list.length;>
if (channelName && this.list[index].channel && channelName === this.list[index].channel) {
return true;
}
}
return false;
}

res.channelAdd = function (channelName) {
channelName = channelName.toLocaleLowerCase();
if (channelName && this.list.length
var newElem = {};
newElem.channel = channelName;
newElem.message = '';

this.list.push(newElem);
}
}

res.listAddMessage = function (channelName, message) {
channelName = channelName.toLocaleLowerCase();
if (this.list.length <this.zapierlimitsize) {="{"></this.zapierlimitsize)>
this.channelAdd(channelName);

for (var index = 0; index <this.list.length; index++)="index++)" {="{"></this.list.length;>
if (channelName && this.list[index].channel === channelName) {
this.list[index].message += message;
break;
}
}
}
}

res.listAddMessageFilter = function (channelName, message) {
channelName = channelName.toLocaleLowerCase();
if (this.validDepartmentList === undefined || this.validDepartmentList === "") {
this.listAddMessage(channelName, message);
}
else {
for (var index = 0; index <this.validdepartmentlist.length; index++)="index++)" {="{"></this.validdepartmentlist.length;>
if (this.validDepartmentList[index] === channelName) {
this.listAddMessage(channelName, message);
}
}
}
}

if (results !== undefined) {
for (var i = 0; i <results.length; i++)="i++)" {="{"></results.length;>
if (results[i].numberDay = input.numberDayMinimum) {
if (results[i].numberDay = 2) {
var messageTmp = results[i].name + ': from ' + results[i].detail + '\n';
}
else {
var messageTmp = results[i].name + ' : ' + results[i].detail + '\n';
}
var channelName = getCleanChannelName(results[i].departmentName)

res.listAddMessageFilter(channelName, messageTmp);
}
}
}

callback(null, res.list);
}
var dayDiff = function (d1, d2) {
d1 = d1.getTime() / 86400000;
d2 = d2.getTime() / 86400000;
return new Number(d2 - d1).toFixed(0);
};
var checkIsIn = function (result, name) {
for (var i = 0; i <result.length; i++)="i++)" {="{"></result.length;>
if (result[i] === name) {
return true;
}
}
return false;
};
// Query request file

var request = function (thisDay) {

var results = [];
fetch(input.url + '&date=' + thisDay.todayS + '&fields=isAM,leavePeriod[owner.name,owner.department,endsOn,endsAM,startsOn]', {
'headers': {
'Authorization': 'lucca application=' + input.appToken
}
}).then(function (res) {
return res.json();
}).then(function (data) {
console.log(data);
var leaves = data.data.items;
var hash = {};

// List all absentees at J+input.offsetDays

leaves.map(function (leave) {
var username = leave.leavePeriod.owner.name;
var userleave = hash[username];
if (!userleave) {
userleave = {
morning: false,
afternoon: false,
end: leave.leavePeriod.endsOn.split('T')[0]
};
hash[username] = userleave;
console.log(leave.leavePeriod.startsOn.split('T')[0]);
if (leave.leavePeriod.startsOn.split('T')[0] === thisDay.todayS) {
results.push({
name: username,
leave: userleave,
departmentName: leave.leavePeriod.owner.department.name,
departmentId: leave.leavePeriod.owner.department.id
});
}
}
if (leave.isAM) {
userleave.morning = true;
} else {
userleave.afternoon = true;
}
});

// Create outgoing messages for each absent person

results.map(function (curRes) {
var endSp = curRes.leave.end.split('-');
var endSpDate = new Date(endSp[0], endSp[1] - 1, endSp[2]);
var numberDay = parseInt(dayDiff(thisDay.date, endSpDate)) + 1;

if (curRes.leave.morning && curRes.leave.afternoon) {
curRes.detail = thisDay.formatString;
} else if (curRes.leave.morning) {
curRes.detail = thisDay.formatString + ' morning';
} else {
curRes.detail = thisDay.formatString + ' afternoon';
}

if (curRes.leave.end !== curRes.todayS && numberDay = 2) {
if (numberDay <7) {="{"></7)>
curRes.detail += ' during ' + numberDay;
curRes.detail += numberDay 1? ' days' : ' day';
}
else {
var nbrWeek = (numberDay / 7) 0;
if ((numberDay / 7 - nbrWeek) 0.5) {
nbrWeek += 1;
}

curRes.detail += ' during ' + nbrWeek;
curRes.detail += nbrWeek 1 ? ' weeks' : ' week';
}
curRes.numberDay = numberDay;
}
else {
curRes.numberDay = 0;
}
});

sendResult(results);
}).catch(function (error) {
console.log(error);
});
}
// Initialization file for date variables.

var getNextWorkingDate = function (offsetDays) {

// Create all date variables.

if (!offsetDays) {
return null;
}

var day = new Date();
var nextDay = {};

for (var i = 0; i <offsetdays; i++)="i++)" {="{"></offsetdays;>
day.setDate(day.getDate() + 1);
if (day.toDateString().split(' ')[0] === 'Sat' || day.toDateString().split(' ')[0] === 'Sun') {
day.setDate(day.getDate() + 2);
}
}

var weekDays = {
'Mon': 'Monday',
'Tue': 'Tuesday',
'Wed': 'Wednesday',
'Thu': 'Thursday',
'Fri': 'Friday',
'Sat': 'Saturday',
'Sun': 'Sunday'
};

nextDay.date = day;
nextDay.yearS = '' + day.getFullYear();
nextDay.month = day.getMonth() + 1;
nextDay.monthS = nextDay.month 9 ? '' + nextDay.month : '0' + nextDay.month;
nextDay.dayS = day.getDate() 9 ? '' + day.getDate() : '0' + day.getDate();
nextDay.todayS = nextDay.yearS + '-' + nextDay.monthS + '-' + nextDay.dayS;
nextDay.formatString = weekDays[day.toDateString().split(' ')[0]];
return nextDay;
};

// If the variable input exists, check the value of offsetDays and the value of numberDayMinimum

if (input) {
if (input.offsetDays === undefined || input.offsetDays <0) {="{"></0)>
input.offsetDays = 0;
}

if (input.numberDayMinimum === undefined || input.numberDayMinimum <0) {="{"></0)>
input.numberDayMinimum = 0;
}

// Then initialize the nextDay variable with the next date taken into account
var nextDay = getNextWorkingDate(input.offsetDays);

// Finally, run the query
request(nextDay);
}

Step 3 involves creating a Slack channel

We add a Filter for step 4

Step 5 adds the message to the correct channel.

Page content

Was this article helpful?
0 out of 1 found this helpful