Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
03c4340
Added empty API_KEY to .env files
unkn0wnAPI Jan 22, 2026
b87f6de
Added an API endpoint controller and placeholders for some api routes
unkn0wnAPI Jan 22, 2026
9bec3b1
Added API endpoints for getting users, user's calendar and sharing ca…
unkn0wnAPI Jan 22, 2026
5388538
Added API endpoints for getting user details, users calendar details
unkn0wnAPI Jan 22, 2026
f5296f0
Code Linting
unkn0wnAPI Jan 22, 2026
cb54297
Added API endpoints for adding/revoking shared calendar
unkn0wnAPI Jan 22, 2026
ef77b79
Code Linting
unkn0wnAPI Jan 22, 2026
369cbdf
Changes to share API endpoint path, added information to output
unkn0wnAPI Jan 23, 2026
46dc7d5
Changes to API json returns
unkn0wnAPI Jan 23, 2026
1cae500
API Docs: Part 1
unkn0wnAPI Jan 23, 2026
bfafce9
Fixes to API endpoint params and permissions checks
unkn0wnAPI Jan 25, 2026
8ae0764
API Docs: Part 2
unkn0wnAPI Jan 25, 2026
ce2477f
Updated main README.md file to include information and link to API en…
unkn0wnAPI Jan 25, 2026
a2ee5b6
Updated code comments and adjusted user list API endpoint
unkn0wnAPI Jan 25, 2026
d9dca60
Updated API_KEY variable comment
unkn0wnAPI Jan 25, 2026
4cef2af
Add missing request body constraints in docs
unkn0wnAPI Jan 25, 2026
f6b302d
Remove needed check/return as per PR comment no. 1
unkn0wnAPI Jan 28, 2026
4f92ed5
Add users array, as per PR comment no. 2
unkn0wnAPI Jan 28, 2026
7dc6fa2
Remove uneeded data false/null check, as per PR comment no. 3
unkn0wnAPI Jan 28, 2026
0c28377
Changed return HTTP code, as per PR comment no. 4
unkn0wnAPI Jan 28, 2026
d8fc2e9
Added helper function and moved checks to route requirements, as per PR
unkn0wnAPI Jan 28, 2026
9f719b2
Added missing array vars and removed uneeded check, as per PR comment…
unkn0wnAPI Jan 28, 2026
cdd0852
Code Linting
unkn0wnAPI Jan 28, 2026
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
9 changes: 8 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,17 @@ WEBDAV_PUBLIC_DIR='/webdav/public'
# such as /webdav/homes for instance, so that users cannot access other users' homes.
WEBDAV_HOMES_DIR=

# API
# When this variable is not empty, the /api endpoint becomes available.
# This endpoint allows admins to perform certain actions that are normally only available
# via the web dashboard.
# To generate a valid API_KEY you can use the php bin/console api:generate command.
API_KEY=

# Logging path
# By default, it will log in the standard Symfony directory: var/log/prod.log (for production)
# You can use /dev/null here if you want to discard logs entirely
LOG_FILE_PATH="%kernel.logs_dir%/%kernel.environment%.log"

# Trust the immediate proxy for X-Forwarded-* headers including HTTPS detection
SYMFONY_TRUSTED_PROXIES=REMOTE_ADDR
SYMFONY_TRUSTED_PROXIES=REMOTE_ADDR
2 changes: 2 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
DATABASE_URL="mysql://davis:[email protected]:3306/davis_test?serverVersion=10.9.3-MariaDB&charset=utf8mb4"

MAILER_DSN=smtp://localhost:465?encryption=ssl&auth_mode=login&username=&password=

API_KEY=
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@ The main endpoint for CalDAV, WebDAV or CardDAV is at `/dav`.
>
> 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.

## API Endpoint

For user and calendar management there is an API endpoint. See [the API documentation](docs/api/README.md) for more information.

> [!TIP]
>
> The API endpoint requires an environment variable `API_KEY` set to a secret key that you will use in the `X-API-Key` header of your requests to authenticate. You can generate it with `bin/console api:generate`

## Webserver Configuration Examples

### Example Caddy 2 configuration

```
Expand Down
4 changes: 4 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ services:
arguments:
$birthdayReminderOffset: "%birthday_reminder_offset%"

App\Controller\Api\ApiController:
arguments:
$apiKey: '%env(API_KEY)%'

when@dev:
services:
Symfony\Component\HttpKernel\Profiler\Profiler: '@profiler'
Expand Down
28 changes: 28 additions & 0 deletions docs/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Davis API

## Open Endpoints

Open endpoints require no Authentication.

* [Health](health.md) : `GET /api/health`

## Endpoints that require Authentication

Closed endpoints require a valid `X-API-Key` 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.

### User related

Each endpoint displays information related to the User:

* [Get Users](users/all.md) : `GET /api/users`
* [Get User Details](users/details.md) : `GET /api/users/:username`

### Calendars related

Endpoints for viewing and modifying user calendars.

* [Show All User Calendars](calendars/all.md) : `GET /api/calendars/:username`
* [Show User Calendar Details](calendars/details.md) : `GET /api/calendars/:username/:calendar_id`
* [Show User Calendar Shares](calendars/shares.md) : `GET /api/calendars/:username/shares/:calendar_id`
* [Share User Calendar](calendars/share_add.md) : `POST /api/calendars/:username/share/:calendar_id/add`
* [Remove Share User Calendar](calendars/share_remove.md) : `POST /api/calendars/:username/share/:calendar_id/remove`
106 changes: 106 additions & 0 deletions docs/api/calendars/all.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# User Calendars

Gets a list of all available calendars for a specific user.

**URL** : `/api/calendars/:username`

**Method** : `GET`

**Auth required** : YES

**Params constraints**

```
:username -> "[username in plain text]",
```

**URL example**

```json
/api/calendars/jdoe
```

## Success Response

**Code** : `200 OK`

**Content examples**

```json
{
"status": "success",
"data": {
"user_calendars": [
{
"id": 1,
"uri": "default",
"displayname": "Default Calendar",
"description": "Default Calendar for John Doe",
"events": 0,
"notes": 0,
"tasks": 0
}
],
"shared_calendars": [
{
"id": 10,
"uri": "c2152eb0-ada1-451f-bf33-b4a9571ec92e",
"displayname": "Default Calendar",
"description": "Default Calendar for Mark Doe",
"events": 0,
"notes": 0,
"tasks": 0
}
],
"subscriptions": []
}
}
```

Shown when there are no users in Davis:
```json
{
"status": "success",
"data": []
}
```

Shown when user does not have calendars:
```json
{
"status": "success",
"data": {
"user_calendars": [],
"shared_calendars": [],
"subscriptions": []
}
}
```

## Error Response

**Condition** : If 'X-API-Key' is not present or mismatched in headers.

**Code** : `401 UNAUTHORIZED`

**Content** :

```json
{
"status": "error",
"message": "Unauthorized"
}
```

**Condition** : If ':username' is not a valid string containing chars: `a-zA-Z0-9_-`.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Username"
}
```
92 changes: 92 additions & 0 deletions docs/api/calendars/details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# User Calendar Details

Gets a list of all available calendars for a specific user.

**URL** : `/api/calendars/:username/:calendar_id`

**Method** : `GET`

**Auth required** : YES

**Params constraints**

```
:username -> "[username in plain text]",
:calendar_id -> "[numeric id of a calendar owned by the user]",
```

**URL example**

```json
/api/calendars/jdoe/1
```

## Success Response

**Code** : `200 OK`

**Content examples**

```json
{
"status": "success",
"data": {
"id": 1,
"uri": "default",
"displayname": "Default Calendar",
"description": "Default Calendar for Joe Doe",
"events": 0,
"notes": 0,
"tasks": 0
}
}
```

Shown when user has no calendars with the given id:
```json
{
"status": "success",
"data": []
}
```

## Error Response

**Condition** : If 'X-API-Key' is not present or mismatched in headers.

**Code** : `401 UNAUTHORIZED`

**Content** :

```json
{
"status": "error",
"message": "Unauthorized"
}
```

**Condition** : If ':username' is not a valid string containing chars: `a-zA-Z0-9_-`.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Username"
}
```

**Condition** : If ':calendar_id' is not a valid numeric value.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Calendar ID"
}
```
105 changes: 105 additions & 0 deletions docs/api/calendars/share_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Share User Calendar

Shares (or updates write access) a calendar owned by the specified user to another user.

**URL** : `/api/calendars/:username/share/:calendar_id/add`

**Method** : `POST`

**Auth required** : YES

**Params constraints**

```
:username -> "[username in plain text]",
:calendar_id -> "[numeric id of a calendar owned by the user]",
```

** Request Body constraints**
```json
{
"user_id": "[numeric id of the user to remove access]",
"write_access": "[boolean: true to grant write access, false for read-only]"
}
```

**URL example**

```json
/api/calendars/mdoe/share/1/add
```

**Body example**

```json
{
"user_id": "3",
"write_access": true
}
```

## Success Response

**Code** : `200 OK`

**Content examples**

```json
{
"status": "success"
}
```

## Error Response

**Condition** : If 'X-API-Key' is not present or mismatched in headers.

**Code** : `401 UNAUTHORIZED`

**Content** :

```json
{
"status": "error",
"message": "Unauthorized"
}
```

**Condition** : If ':username' is not a valid string containing chars: `a-zA-Z0-9_-`.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Username"
}
```

**Condition** : If ':calendar_id' is not a valid numeric value.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Calendar ID"
}
```

**Condition** : If ':calendar_id' is not for the specified ':username'.

**Code** : `400 BAD REQUEST`

**Content** :

```json
{
"status": "error",
"message": "Invalid Calendar ID/Username"
}
```
Loading