Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endpoint to add public-holiday task to every employee #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Timekeeper admin jobs service
## Getting started
### Adding the service to your stack
Add the following snippet to your `docker-compose.yml`
```yml
admin-jobs:
image: redpencil/timekeeper-admin-jobs-service
environment:
PUBLIC_HOLIDAY_TASK: "http://timekeeper.redpencil.io/tasks/xxxx"
```

## Reference
### Configuration
- **PUBLIC_HOLIDAY_TASK**: Task uri of the "public holiday task".

### API
#### POST /populate-public-holidays
Add a "public holiday" task to every employee (part of the employee group) for the specified iso-dates (YYYY-MM-DD). Pass the dates as a json-array in the body.

Returns error for an invalid payload.
Returns status 204 No Content on success.

Example:
`curl -X POST localhost/populate-public-holidays -H 'Content-Type: application/vnd.api+json' -d '["2025-01-01","2025-01-02"]'`

### Scripts
#### add-public-holidays
Pass the dates as a comma-separated list. This will run the same logic as a POST to `/populate-public-holidays`. The service has to be named `admin-jobs` for this script to run!

Example:
`mu script admin-jobs add-public-holiday 2025-01-01,2025-01-02`
50 changes: 50 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { app, errorHandler, sparqlEscapeDate } from 'mu';
import { isValid } from 'date-fns'
import { PUBLIC_HOLIDAY_TASK_URI, SPARQL_PREFIXES, WORK_LOG_RESOURCE_BASE } from './constants';
import { updateSudo } from "@lblod/mu-auth-sudo";

/**
* given a list of dates in iso format (YYYY-MM-DD)
* add a public-holiday work-log (of 8h) to every employee on this date
* Pass the dates as a JSON array in the body (of type `application/vnd.api+json`).
*/
app.post('/populate-public-holidays', async function (req, res) {
const dates = req.body;
if(!dates) next(new Error('No dates found the body of the request.'));
if(!Array.isArray(dates)) next(new Error('Dates passed in the body should be a JSON array.'));
dates.forEach(date => {
if(!isValid) { next(new Error(`${date} is not a valid date string. Use the format YYYY-MM-DD`)); }
})
const query = `${SPARQL_PREFIXES}
INSERT {
GRAPH ?g {
?workLogUri a ical:Vevent ;
mu:uuid ?workLogId ;
ical:duration "PT8H" ;
dct:subject <${PUBLIC_HOLIDAY_TASK_URI}> ;
prov:wasAssociatedWith ?employee ;
ical:dtstart ?date .
}
} WHERE {
VALUES ?date {${dates.map(d => sparqlEscapeDate(d)).join(' ')}}
{
SELECT DISTINCT ?g ?employee WHERE {
<http://mu.semte.ch/user-groups/employee> foaf:member ?employee .
?employee mu:uuid ?employeeId .
BIND(IRI(CONCAT("http://mu.semte.ch/graphs/employees/", ?employeeId)) AS ?g)
}
}
FILTER NOT EXISTS {
?existingWorkLog a ical:Vevent ;
dct:subject <${PUBLIC_HOLIDAY_TASK_URI}> ;
ical:dtstart ?date .
}
BIND (LCASE(STRUUID()) AS ?workLogId)
BIND (URI(CONCAT("${WORK_LOG_RESOURCE_BASE}", ?workLogId)) AS ?workLogUri)
}
`
await updateSudo(query);
res.status(204).send();
});

app.use(errorHandler)
24 changes: 24 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

export const SPARQL_PREFIXES = `
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX ui: <http://www.w3.org/ns/ui#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX wf: <http://www.w3.org/2005/01/wf/flow#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX doap: <http://usefulinc.com/ns/doap#>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX adms: <http://www.w3.org/ns/adms#>
PREFIX ical: <http://www.w3.org/2002/12/cal/ical#>
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
`

export const WORK_LOG_RESOURCE_BASE = "http://timekeeper.redpencil.io/work-logs/"

export const PUBLIC_HOLIDAY_TASK_URI = process.env.PUBLIC_HOLIDAY_TASK;
if (! PUBLIC_HOLIDAY_TASK_URI) {
throw Error("environment variable PUBLIC_HOLIDAY_TASK is mandatory.")
}
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "timekeeper-admin-jobs-service",
"version": "0.1.0",
"description": "Microservice to handle jobs for admins",
"main": "app.js",
"scripts": {
"release": "release-it --no-npm.publish"
},
"author": "redpencil <[email protected]>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/redpencilio/timekeeper-admin-jobs-service.git"
},
"devDependencies": {
"release-it": "^17.10.0"
},
"dependencies": {
"date-fns": "^4.1.0",
"@lblod/mu-auth-sudo": "^0.6.0"
}
}
5 changes: 5 additions & 0 deletions scripts/add-public-holidays/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
echo "add public holidays"
dates="$1"
formatted_dates=$(echo "$dates" | sed 's/,/","/g')
curl -X POST http://admin-jobs/populate-public-holidays -H 'Content-Type: application/vnd.api+json' -d '["'"$formatted_dates"'"]'
18 changes: 18 additions & 0 deletions scripts/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "0.1",
"scripts": [
{
"documentation": {
"command": "add-public-holidays",
"description": "Add the list of dates as public holidays to every employee",
"arguments": ["comma-separated-iso-dates"]
},
"environment": {
"image": "alpine/curl",
"interactive": false,
"script": "add-public-holidays/run.sh",
"join_networks": true
}
}
]
}