Skip to content

Commit d6f8d54

Browse files
authored
[FEAT] Add (limited) API endpoint (#237)
1 parent 09a26f1 commit d6f8d54

25 files changed

Lines changed: 2720 additions & 4 deletions

.env

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,17 @@ WEBDAV_PUBLIC_DIR='/webdav/public'
9090
# such as /webdav/homes for instance, so that users cannot access other users' homes.
9191
WEBDAV_HOMES_DIR=
9292

93+
# API
94+
# When this variable is not empty, the /api endpoint becomes available.
95+
# This endpoint allows admins to perform certain actions that are normally only available
96+
# via the web dashboard.
97+
# To generate a valid API_KEY you can use the php bin/console api:generate command.
98+
API_KEY=
99+
93100
# Logging path
94101
# By default, it will log in the standard Symfony directory: var/log/prod.log (for production)
95102
# You can use /dev/null here if you want to discard logs entirely
96103
LOG_FILE_PATH="%kernel.logs_dir%/%kernel.environment%.log"
97104

98105
# Trust the immediate proxy for X-Forwarded-* headers including HTTPS detection
99-
SYMFONY_TRUSTED_PROXIES=REMOTE_ADDR
106+
SYMFONY_TRUSTED_PROXIES=REMOTE_ADDR

.env.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
88
DATABASE_URL="mysql://davis:davis@127.0.0.1:3306/davis_test?serverVersion=10.9.3-MariaDB&charset=utf8mb4"
99

1010
MAILER_DSN=smtp://localhost:465?encryption=ssl&auth_mode=login&username=&password=
11+
12+
API_KEY=change_me

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@ The main endpoint for CalDAV, WebDAV or CardDAV is at `/dav`.
329329
>
330330
> For shared hosting, the `symfony/apache-pack` is included and provides a standard `.htaccess` file in the public directory so redirections should work out of the box.
331331
332+
## API Endpoint
333+
334+
For user and calendar management there is an API endpoint. See [the API documentation](docs/api/README.md) for more information.
335+
336+
> [!TIP]
337+
>
338+
> The API endpoint requires an environment variable `API_KEY` set to a secret key that you will use in the `X-Davis-API-Token` header of your requests to authenticate. You can generate it with `bin/console api:generate`
339+
340+
## Webserver Configuration Examples
341+
332342
### Example Caddy 2 configuration
333343
334344
```

config/packages/security.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ security:
88
dev:
99
pattern: ^/(_(profiler|wdt)|css|images|js)/
1010
security: false
11+
api_v1:
12+
pattern: ^/api/v1
13+
stateless: true
14+
custom_authenticators:
15+
- App\Security\ApiKeyAuthenticator
1116
main:
1217
lazy: true
1318
custom_authenticators:
@@ -16,6 +21,7 @@ security:
1621
logout:
1722
path: app_logout
1823
target: dashboard
24+
1925

2026
access_control:
2127
- { path: ^/$, roles: PUBLIC_ACCESS }
@@ -24,3 +30,5 @@ security:
2430
- { path: ^/users, roles: ROLE_ADMIN, allow_if: "'%env(default:default_admin_auth_bypass:ADMIN_AUTH_BYPASS)%' === 'true'" }
2531
- { path: ^/calendars, roles: ROLE_ADMIN, allow_if: "'%env(default:default_admin_auth_bypass:ADMIN_AUTH_BYPASS)%' === 'true'" }
2632
- { path: ^/adressbooks, roles: ROLE_ADMIN, allow_if: "'%env(default:default_admin_auth_bypass:ADMIN_AUTH_BYPASS)%' === 'true'" }
33+
- { path: ^/api/v1/health$, roles: PUBLIC_ACCESS }
34+
- { path: ^/api, roles: IS_AUTHENTICATED }

config/services.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ services:
7878
arguments:
7979
$birthdayReminderOffset: "%birthday_reminder_offset%"
8080

81+
App\Security\ApiKeyAuthenticator:
82+
arguments:
83+
$apiKey: "%env(API_KEY)%"
84+
8185
when@dev:
8286
services:
8387
Symfony\Component\HttpKernel\Profiler\Profiler: '@profiler'

docs/api/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Davis API
2+
3+
## API Version 1
4+
5+
### Open Endpoints
6+
7+
Open endpoints require no Authentication.
8+
9+
* [Health](v1/health.md) : `GET /api/v1/health`
10+
11+
### Endpoints that require Authentication
12+
13+
Closed endpoints require a valid `X-Davis-API-Token` to be included in the header of the request. Token needs to be configured in .env file (as a environment variable `API_KEY`) and can be generated using `php bin/console api:generate` command.
14+
15+
When `API_KEY` is not set, the API endpoints are disabled and will return a 500 error if accessed.
16+
17+
#### User related
18+
19+
Each endpoint displays information related to the User:
20+
21+
* [Get Users](v1/users/all.md) : `GET /api/v1/users`
22+
* [Get User Details](v1/users/details.md) : `GET /api/v1/users/:username`
23+
24+
#### Calendars related
25+
26+
Endpoints for viewing and modifying user calendars.
27+
28+
* [Show All User Calendars](v1/calendars/all.md) : `GET /api/v1/calendars/:username`
29+
* [Show User Calendar Details](v1/calendars/details.md) : `GET /api/v1/calendars/:username/:calendar_id`
30+
* [Create User Calendar](v1/calendars/create.md) : `POST /api/v1/calendars/:username/create`
31+
* [Edit User Calendar](v1/calendars/edit.md) : `POST /api/v1/calendars/:username/:calendar_id/edit`
32+
* [Delete User Calendar](v1/calendars/delete.md) : `POST /api/v1/calendars/:username/:calendar_id/delete`
33+
* [Show User Calendar Shares](v1/calendars/shares.md) : `GET /api/v1/calendars/:username/shares/:calendar_id`
34+
* [Share User Calendar](v1/calendars/share_add.md) : `POST /api/v1/calendars/:username/share/:calendar_id/add`
35+
* [Remove Share User Calendar](v1/calendars/share_remove.md) : `POST /api/v1/calendars/:username/share/:calendar_id/remove`

docs/api/v1/calendars/all.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# User Calendars
2+
3+
Gets a list of all available calendars for a specific user.
4+
5+
**URL** : `/api/v1/calendars/:username`
6+
7+
**Method** : `GET`
8+
9+
**Auth required** : YES
10+
11+
**Params constraints**
12+
13+
```
14+
:username -> "[username in plain text]",
15+
```
16+
17+
**URL example**
18+
19+
```json
20+
/api/v1/calendars/jdoe
21+
```
22+
23+
## Success Response
24+
25+
**Code** : `200 OK`
26+
27+
**Notes**: The `events`, `notes`, and `tasks` fields return a count (number) if the component is enabled for the calendar, or `null` if the component is disabled.
28+
29+
**Content examples**
30+
31+
```json
32+
{
33+
"status": "success",
34+
"data": {
35+
"user_calendars": [
36+
{
37+
"id": 1,
38+
"uri": "default",
39+
"displayname": "Default Calendar",
40+
"events": 0,
41+
"notes": null,
42+
"tasks": null
43+
}
44+
],
45+
"shared_calendars": [
46+
{
47+
"id": 10,
48+
"uri": "c2152eb0-ada1-451f-bf33-b4a9571ec92e",
49+
"displayname": "Default Calendar",
50+
"events": 0,
51+
"notes": null,
52+
"tasks": null
53+
}
54+
],
55+
"subscriptions": []
56+
},
57+
"timestamp": "2026-01-23T15:01:33+01:00"
58+
}
59+
```
60+
61+
Shown when user does not have calendars:
62+
```json
63+
{
64+
"status": "success",
65+
"data": {
66+
"user_calendars": [],
67+
"shared_calendars": [],
68+
"subscriptions": []
69+
},
70+
"timestamp": "2026-01-23T15:01:33+01:00"
71+
}
72+
```
73+
74+
## Error Response
75+
76+
**Condition** : If 'X-Davis-API-Token' is not present or mismatched in headers.
77+
78+
**Code** : `401 UNAUTHORIZED`
79+
80+
**Content** :
81+
82+
```json
83+
{
84+
"message": "No API token provided",
85+
"timestamp": "2026-01-23T15:01:33+01:00"
86+
}
87+
```
88+
89+
or
90+
91+
```json
92+
{
93+
"message": "Invalid API token",
94+
"timestamp": "2026-01-23T15:01:33+01:00"
95+
}
96+
```
97+
98+
**Condition** : If user is not found.
99+
100+
**Code** : `404 NOT FOUND`
101+
102+
**Content** :
103+
104+
```json
105+
{
106+
"status": "error",
107+
"message": "User Not Found",
108+
"timestamp": "2026-01-23T15:01:33+01:00"
109+
}
110+
```

0 commit comments

Comments
 (0)