From 263cdf544aeaead5c2f90fee84a62450c11195ce Mon Sep 17 00:00:00 2001 From: Bruno Bernardino Date: Wed, 27 Aug 2025 14:57:19 +0100 Subject: [PATCH] Fix for initial/clean Radicale setup This fixes a problem with the contacts app displaying an error on a clean install, due to the fact that `tsdav`'s address book listing didn't ask for a main address first, so Radicale wouldn't create the user directory. It also upgrades `deno`'s version. --- .dvmrc | 2 +- Dockerfile | 2 +- README.md | 24 +++++++++++++++++------- docker-compose.yml | 2 +- lib/models/contacts.ts | 27 ++++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/.dvmrc b/.dvmrc index 79a6144..59aa62c 100644 --- a/.dvmrc +++ b/.dvmrc @@ -1 +1 @@ -2.4.4 +2.4.5 diff --git a/Dockerfile b/Dockerfile index 34314d0..3d5d754 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM denoland/deno:ubuntu-2.4.4 +FROM denoland/deno:ubuntu-2.4.5 EXPOSE 8000 diff --git a/README.md b/README.md index cca6455..6231d11 100644 --- a/README.md +++ b/README.md @@ -18,21 +18,31 @@ If you're looking for the mobile app, it's at [`bewcloud-mobile`](https://github [![Buy managed cloud (1 month)](https://img.shields.io/badge/Buy%20managed%20cloud%20(1%20month)-51a4fb?style=for-the-badge)](https://buy.stripe.com/fZu8wOb5RfIydj56FA1gs0J) -Or on your own machine: - -Download/copy [`docker-compose.yml`](/docker-compose.yml), [`.env.sample`](/.env.sample) as `.env`, [`bewcloud.config.sample.ts`](/bewcloud.config.sample.ts) as `bewcloud.config.ts`, and [`radicale-config/config`](/radicale-config/config) as `radicale-config/config` (if you're using CalDav/CardDav). - -> [!NOTE] -> `1993:1993` below comes from deno's [docker image](https://github.com/denoland/deno_docker/blob/2abfe921484bdc79d11c7187a9d7b59537457c31/ubuntu.dockerfile#L20-L22) where `1993` is the default user id in it. It might change in the future since I don't control it. +Or on your own machine, start with these commands: ```sh $ mkdir data-files data-radicale # local directories for storing user-uploaded files and radicale data $ sudo chown -R 1993:1993 data-files # solves permission-related issues in the container with uploading files +``` + +> [!NOTE] +> `1993:1993` below comes from deno's [docker image](https://github.com/denoland/deno_docker/blob/2abfe921484bdc79d11c7187a9d7b59537457c31/ubuntu.dockerfile#L20-L22) where `1993` is the default user id in it. It might change in the future since I don't control it. + +Now, download/copy the following configuration files (and tweak their contents as necessary, though no changes should yield a working — but very unsafe — setup): + +- [`docker-compose.yml`](/docker-compose.yml) +- [`.env.sample`](/.env.sample) and save it as `.env` +- [`bewcloud.config.sample.ts`](/bewcloud.config.sample.ts) and save it as `bewcloud.config.ts` +- [`radicale-config/config`](/radicale-config/config) and save it as `radicale-config/config` (if you're using CalDav/CardDav) + +Finally, run these commands: + +```sh $ docker compose up -d # makes the app available at http://localhost:8000 $ docker compose run --rm website bash -c "cd /app && make migrate-db" # initializes/updates the database (only needs to be executed the first time and on any data updates) ``` -Alternatively, check the [Development section below](#development). +If you're interested in building/contributing, check the [Development section below](#development). > [!IMPORTANT] > Even with signups disabled (`config.auth.allowSignups=false`), the first signup will work and become an admin. diff --git a/docker-compose.yml b/docker-compose.yml index fc93dd8..a7add64 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: website: - image: ghcr.io/bewcloud/bewcloud:v2.4.3 + image: ghcr.io/bewcloud/bewcloud:v2.4.4 restart: always ports: - 127.0.0.1:8000:8000 diff --git a/lib/models/contacts.ts b/lib/models/contacts.ts index 0ccca51..a3ae6f8 100644 --- a/lib/models/contacts.ts +++ b/lib/models/contacts.ts @@ -135,7 +135,32 @@ export class ContactModel { ): Promise { const client = await getClient(userId); - const davAddressBooks: DAVObject[] = await client.fetchAddressBooks(); + let davAddressBooks: DAVObject[] = []; + + try { + davAddressBooks = await client.fetchAddressBooks(); + } catch (_error) { + // It's possible the user doesn't exist in Radicale yet, so try creating it by doing a simple PROPFIND request for the main addressbook's address (Radicale will automatically create the user) + const userUrl = `${contactsConfig.cardDavUrl}/${userId}/`; + + const xmlBody = ` + + + + +`; + + await fetch(userUrl, { + method: 'PROPFIND', + headers: { + 'Content-Type': 'application/xml; charset=utf-8', + 'X-Remote-User': userId, + }, + body: xmlBody, + }); + + davAddressBooks = await client.fetchAddressBooks(); + } const addressBooks: AddressBook[] = davAddressBooks.map((davAddressBook) => { const uid = davAddressBook.url.split('/').filter(Boolean).pop()!;