Implement Hitobito event retrieval endpoints
- Dominant language
- PHP
- Stars
- 156
- Forks
- 72
- Avg merge
- 12h 43m
- Merged PRs (30d)
- 203
Description
The following endpoints are added, which allow retrieving events from Hitobito. Only events that the user manages are returned (that the user is `Lagerleiter:in` of).
## List Events
```jsonc
// GET /api/hitobito//events
// Response
{
"_links": {},
"totalItems": 5,
"_embedded": {
"items": [
{
"_links": {},
"_embedded": {},
"id": 1234,
"name": "Test Lager",
"isImported": false // whether the event was already imported into eCamp
}
// ...
]
}
}
```
### Implementation
1. Retrieve / verify access token
- See https://github.com/ecamp/ecamp3/issues/10400
2. Retrieve events from the Hitobito API:
```
GET /api/events
?include=participation.roles
&filter[event][after_or_on][eq]=
&filter[participations.participant_id]=
&filter[participations.participant_type][eq]=Person
&fields[events]=name
&fields[event_participations]=event_id,active
&fields[event_roles]=participation_id,type
&page[size]=100
```
> The `fields[event_participations], fields[events]=name, fields[event_roles]=type` params limit the fields that are returned, only including the specified fields. By default all fields of participations, events and event_roles would be returned, which results in a larger response body.
Example Response:
```jsonc
{
"data": [
// event where the user does not have an active participation
{
"id": "1044",
"type": "events",
"attributes": {
"name": "Templager_"
},
"relationships": {
// ...
"participations": {
"data": []
}
// ...
}
},
// event where the user has an active participation
{
"id": "2064",
"type": "events",
"attributes": {
"name": "SoLa 2050"
},
"relationships": {
// ...
"participations": {
"data": [
{
"type": "event_participations",
"id": "14668"
},
{
"type": "event_participations",
"id": "14665"
}
]
}
// ...
}
},
],
"included": [
{
"id": "14668",
"type": "event_participations",
"relationships": {
"event": {
"meta": {
"included": false
}
},
"participant": {
"meta": {
"included": false
}
},
"roles": {
"data": [
{
"type": "event_roles",
"id": "17996"
}
]
}
}
},
{
"id": "17996",
"type": "event_roles",
"attributes": {
"type": "Event::Camp::Role::Leader"
},
"relationships": {
"participation": {
"meta": {
"included": false
}
}
}
}
],
"links": {
// ...
},
"meta": {}
}
```
3. Perform the following steps on the retrieved data
1. Retrieve all included participations (`attributes.active = true`) and where **one of** the corresponding roles has `attributes.type = "Event::Camp::Role::Leader | Event::Role::Leader | Event::Course::Role::Leader"`
2. Look up the corresponding event, add the event `id` and `attributes.name` to result array
4. For every event, check if there is a corresponding camp and mark `isImported` accordingly
5. Return all gathered events
> Implementation Note: Make sure that the role that identifies a user as a leader of an event (for MiData `Event::Camp::Role::Leader`) is configurable per different Hitobito provider, so that new supported instance (i.e. CeviDB) can be easily added in the future.
> Optimally we would directly query the event name / filter the role when calling the api, but this is seemingly unsupported by Hitobito.
> There is a filter option to directly remove participations with certain roles (`filter[participations.roles.type][eq]=...`). However this currently results in an error on the Hitobito-side, so the filtering is performed manually in extractEvents. See comments on this issue for more details.
## Get Event
```jsonc
// GET /api/hitobito//events/
// Response
{
"id": 1234,
"name": "Lumos + Iltis",
"motto": "Kartoffelbauer und Nudelkönigin",
"location": "Hardstrasse 201, 8005 Zürich",
"dates": [
{
"label": "Politsche Ausrichtung der TN",
"startAt": "2026-01-01T00:01:00+01:00",
"finishAt": "2026-12-31T23:59:00+01:00"
}
],
"isImported": false
}
```
### Implementation
1. Retrieve / verify access token
- See https://github.com/ecamp/ecamp3/issues/10400
2. Check that the user has access to the specified event
1. See https://github.com/ecamp/ecamp3/issues/10419
3. Retrieve the event from Hitobito
```
GET /api/events/?include=dates
```
Example Response:
```jsonc
{
"data": {
"id": "2611",
"type": "events",
"attributes": {
"group_ids": [
1503,
1517
],
"type": "Event::Camp",
"kind_id": null,
"name": "Lumos + Iltis",
"description": null,
"application_conditions": null,
"motto": "Kartoffelbauer und Nudelkönigin",
"cost": "190'000.00",
"location": "Hardstrasse 201, 8005 Zürich",
"application_opening_at": null,
"application_closing_at": null,
"application_contact_id": null,
"external_application_link": null,
"maximum_participants": null,
"created_at": "2025-08-06T16:05:38+02:00",
"updated_at": "2026-07-27T13:04:13+02:00",
"advisor_id": null
},
"relationships": {
// ...
"dates": {
"data": [
{
"type": "dates",
"id": "3739"
}
]
},
}
},
"included": [
{
"id": "3739",
"type": "dates",
"attributes": {
"event_id": 2611,
"label": "Politsche Ausrichtung der TN",
"location": "Zürich",
"start_at": "2026-01-01T00:01:00+01:00",
"finish_at": "2026-12-31T23:59:00+01:00"
},
"relationships": {
"event": {
"meta": {
"included": false
}
}
}
}
],
"meta": {}
}
```
4. Check if there is a corresponding camp and mark `isImported` accordingly
5. Respond with the event as specified above
Contributor guide
Assessment
This issue has not been assessed yet.