The project aims to create a standalone application for automated integration between Harvest time tracking tool and Slack messaging system that will notify all configured team users about the amount of time they've spent on each project according to their Harvest timesheet.
To download the application, check it out with git. Next thing to do is installing all dependencies with the npm node packages manager tool.
$ cd /path/to/project
$ npm installNext thing to do is preparing the config file. The file must be located in the repository root and named config.json A template file is stored in config.dist.json. The file is divided into sections containing particular configuration options for the application middlewares. To get the Slack <-> Harvest part communicate, the most important thing is to set up the credentials for both services properly.
The application is written 100% in Node.JS and at this point consists of three blocks:
- the cron-like time schedule that sends notification messages to slack users,
- a simple HTTP API to trigger notifications (single user and all users notifications, management report),
- a Slack Command API endpoint that manages Harvest timer setup.
###HARVEST configuration
For the moment, harvest communication may be only set up using an account. To have a complete list of projects in all user notifications, an account with access to prefferably all available projects, users and clients should be used. Mandatory parameters in the configuration object are subdomain, email and password.
"harvest": {
"subdomain": "example_harvest_domain",
"email": "XXXXX@neverbland.com",
"password": "XXXXXXXXXXXXXXX"
}
###SLACK configuration
The Slack part uses a simple incoming WebHook that needs to be created within the Slack application itself (See https://api.slack.com/incoming-webhooks). The only mandatory parameter that need to be set is endpoint which is the webhook endpoint. The configuration below contains additional params which are overriding the default settings for the webhook. All params available for the webhook can be used except channel, which will always be overridden by slack username of the user that receives the notifications.
"slack": {
"username": "Harvest",
"icon_url": "https://avatars0.githubusercontent.com/u/43635?v=3&s=200",
"endpoint": "XXXXXXXXXXXXXX"
}
The users section contains the mapping of all available users Harvest ID -> Slack username map. Only these users will be available for notification.
"users": {
"123456": "slack_name"
}
##CRON
For the moment the application is able to:
-
notify defined users at the configured time every work day (monday - friday). The time is defined in the
cron.notifysection of the config file and uses the same timezone as the machine the app is running on. For the configuration below, the app will automatically send notifications every working day at16:30. If acron.notify.cronTimevalue is provided in the config, this value will be used instead of the hour and minutes settings -
refresh (preload) the information about timesheet related entries (clients and projects) according to cron time provided in
cron.preload.cronTimesection -
send periodical report notifications on Slack management channel defined in
cron.report.channelsetting according to cron time provided incron.report.cronTimesection -
send reminder messages via Slack to people who have no timers running according to
cron.remind.cronTimesetting.
"cron": {
"notify": {
"hour": "16",
"munutes": "30",
"cronTime": "00 30 16 * * 1-5" // Optional, instead of hour/minutes
},
"preload": {
"cronTime": "00 00 7-20 * * 1-5"
},
"report": {
"reportTitle": "Weekly activity report",
"channel": "#channel_name",
"cronTime": "00 00 20 * * 5"
}
}
If any of the section for cron settings are not provided, the cron job will not be set up.
##API
The API provides given endpoints:
-
http|https://your.domain.you/notify-allNotifies all users present in the users config providing information about their started tasks. -
http|https://your.domain.you/notify-user/user_idNotifies user given byuser_idwhich represents either Harvest user ID or Slack username about her/his started tasks. -
http|https://your.domain.you/notify-managementNotifies management channel provided in thechannelproperty of thePOSTrequest. -
http|https://your.domain.you/remind-allTriggers notifications to users wo have no tasks started on Harvest.
The notify-all and notify-user are actions names; this will be useful when creating authorization token.
###API configuration
The api.auth section of the config file contains settings for the authorization parameters. There are two built in methods of authorization:
-
Static token method - will be used if an
api.auth.tokensetting is present. The incoming requests will be checked if they contain aPOSTvalue with the nametokenand if the value matches theapi.auth.tokenvalue. -
Dynamic token method - will be used if an
api.auth.secretsetting is present. To validate the request and grant access, aPOSTpayload must contain a token and a seed. The token is generated with anSHA1hash of the same secret as provided in the application config file, seed and the action name from the URL (see above) joined by |.
Example PHP implementation of the token generation:
<?php
$url = "http://some-domain.com/notify-all";
$secret = "thisisthesecret"; // Same secret as in the config file
$seed = generateRandomSeed(10); // Eg. method that generates random string
$token = sha1(implode("|", array(
$secret,
$seed,
"notify-all"
)));##Harvest timer management
The app provides an endpoint for a Slack slash command that enables management of the Harvest day entries directly from Slack. The command needs to be configured according to Slack slash command configuration guide https://api.slack.com/slash-commands. The timer management, in the most advanced case, works as a dialogue between the user (via Slack UI) and the server.
###Command syntax
The command syntax contains the configured slack command name (e.g. /timer) and following action name. Available actions:
-
statusshows the Harvest client, project and task name for the current user task. This is a single step task that doesn't follow a dialogue with the server. -
projectslists out all currently available projects with the client names. -
stopstops the work for the task that is currently running for given user. This is a single step task that doesn't follow a dialogue with the server. -
remindchecks all users timelines and sends slack reminder message to all users who have empty day entries timelines. Accepts one additional parameter, which is the userId (either slack name or harvest id). -
startaims to start a task. As an additional param, a project/client name can be provided. This will trigger a dialogue with the server that can be stopped at any point. -
updateallows user to update her/his number of hours for given day entry. As an additional param, a project/client name can be provided. This will trigger a dialogue with the server that can be stopped at any point.
###Examples Command:
/timer status
Example output:
You are currently working on
NEVERBLAND - Internal - Admin
Command:
/timer projects
Example output:
Available projects
1. Test Client - Test Project
2. Test Client - Test Project 2
Command:
/timer stop
Example output:
Successfully stopped the timer for
NEVERBLAND - Internal - Admin
Command:
/timer remind
Example output:
Notified given users:
some_user1
some_user2
Dialogue command 1:
/timer start neverb
Example dialogue output:
Choose the awesome project you are working on today!
1. NEVERBLAND - Project 1
2. NEVERBLAND - Project 2
3. NEVERBLAND - Project 3
4. NEVERBLAND - Project 4
Just type the number to choose it or write 'no' to quit the timer setup
Dialogue command 2:
/timer 2
Example dialogue output:
Cool, love that project!
What task are you on?
1. Admin
2. Backend
3. Bug Fixing
4. Design
5. Frontend
6. Support
Just type the number to choose it or write 'no' if you picked the wrong project.
Dialogue command 3:
/timer 2
Example dialogue output:
Successfully created and started an entry for
NEVERBLAND - Project 2 - Backend
Dialogue command 1:
/timer update neverb
Example dialogue output:
Choose which entry you want to update!
1. NEVERBLAND - Project 1 - Task 1 (02:25)
2. NEVERBLAND - Project 2 - Task 3 (01:30)
Just type the number to choose it or write 'no' to quit the timer setup
Dialogue command 2:
/timer 2
Example dialogue output:
Cool, please provide a time to set for
NEVERBLAND - Project 2 - Task 3 (01:30)
Just type /timer followed by a valid time format (HH:mm or number of seconds) or write /timer no to quit the timer setup
Dialogue command 3:
/timer 02:30
Example dialogue output:
Successfully updated the time for
NEVERBLAND - Project 2 - Task 3 (01:30)
to 02:30