Fix for Evolution CardDav/CalDav
They seem to make `GET` requests with `body`, which isn't allowed by the spec and causes Deno to fail. This prevents/ignores that. It also makes the default `docker-compose.yml` "safer" by not exposing the database and container. Finally, it removes a couple of unmaintained "one-click-deploy" buttons and simplifies documentation.
This commit is contained in:
@@ -1,43 +0,0 @@
|
|||||||
spec:
|
|
||||||
name: bewcloud
|
|
||||||
envs:
|
|
||||||
- key: BASE_URL
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${app.PUBLIC_URL}
|
|
||||||
services:
|
|
||||||
- name: app
|
|
||||||
dockerfile_path: Dockerfile
|
|
||||||
git:
|
|
||||||
branch: main
|
|
||||||
http_port: 8000
|
|
||||||
instance_count: 1
|
|
||||||
instance_size_slug: basic-xs
|
|
||||||
routes:
|
|
||||||
- path: /
|
|
||||||
health_check:
|
|
||||||
http_path: /
|
|
||||||
source_dir: /
|
|
||||||
envs:
|
|
||||||
- key: POSTGRESQL_HOST
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${db.HOSTNAME}
|
|
||||||
- key: POSTGRESQL_USER
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${db.USERNAME}
|
|
||||||
- key: POSTGRESQL_PASSWORD
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${db.PASSWORD}
|
|
||||||
- key: POSTGRESQL_DBNAME
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${db.DATABASE}
|
|
||||||
- key: POSTGRESQL_PORT
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ${db.PORT}
|
|
||||||
- key: POSTGRESQL_CAFILE
|
|
||||||
scope: RUN_AND_BUILD_TIME
|
|
||||||
value: ''
|
|
||||||
databases:
|
|
||||||
- name: db
|
|
||||||
engine: PG
|
|
||||||
production: false
|
|
||||||
version: '17'
|
|
||||||
39
README.md
39
README.md
@@ -10,10 +10,6 @@ If you're looking for the mobile app, it's at [`bewcloud-mobile`](https://github
|
|||||||
|
|
||||||
## Self-host it!
|
## Self-host it!
|
||||||
|
|
||||||
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/bewcloud/bewcloud)
|
|
||||||
|
|
||||||
[](https://render.com/deploy?repo=https://github.com/bewcloud/bewcloud)
|
|
||||||
|
|
||||||
[-51a4fb?style=for-the-badge)](https://buy.stripe.com/eVa01HgQk0Ap0eseVz)
|
[-51a4fb?style=for-the-badge)](https://buy.stripe.com/eVa01HgQk0Ap0eseVz)
|
||||||
|
|
||||||
[-51a4fb?style=for-the-badge)](https://buy.stripe.com/fZu8wOb5RfIydj56FA1gs0J)
|
[-51a4fb?style=for-the-badge)](https://buy.stripe.com/fZu8wOb5RfIydj56FA1gs0J)
|
||||||
@@ -21,27 +17,28 @@ If you're looking for the mobile app, it's at [`bewcloud-mobile`](https://github
|
|||||||
Or on your own machine, start with these commands:
|
Or on your own machine, start with these commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ mkdir data-files data-radicale # local directories for storing user-uploaded files and radicale data
|
mkdir data-files data-radicale radicale-config # local directories for storing user-uploaded files, radicale data, and radicale config (these last two are necessary only if you're using CalDav/CardDav/Contacts)
|
||||||
$ 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):
|
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)
|
- [`docker-compose.yml`](/docker-compose.yml)
|
||||||
- [`.env.sample`](/.env.sample) and save it as `.env`
|
- [`.env.sample`](/.env.sample) and save it as `.env`
|
||||||
- [`bewcloud.config.sample.ts`](/bewcloud.config.sample.ts) and save it as `bewcloud.config.ts`
|
- [`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/Contacts)
|
- [`radicale-config/config`](/radicale-config/config) and save it as `radicale-config/config` (necessary only if you're using CalDav/CardDav/Contacts)
|
||||||
|
|
||||||
Finally, run these commands:
|
Finally, run these commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ docker compose up -d # makes the app available at http://localhost:8000
|
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)
|
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)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If you run into permission issues, you can try running `sudo chown -R 1993:1993 data-files` to fix them.
|
||||||
|
>
|
||||||
|
> `1993:1993` above 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.
|
||||||
|
|
||||||
If you're interested in building/contributing, check the [Development section below](#development).
|
If you're interested in building/contributing, check the [Development section below](#development).
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
@@ -71,23 +68,23 @@ These are the amazing entities or individuals who are sponsoring this project fo
|
|||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ docker compose -f docker-compose.dev.yml up # (optional) runs docker with postgres, locally
|
docker compose -f docker-compose.dev.yml up # (optional) runs docker with postgres, locally
|
||||||
$ make migrate-db # runs any missing database migrations
|
make migrate-db # runs any missing database migrations
|
||||||
$ make start # runs the app
|
make start # runs the app
|
||||||
$ make format # formats the code
|
make format # formats the code
|
||||||
$ make test # runs tests
|
make test # runs tests
|
||||||
```
|
```
|
||||||
|
|
||||||
### Other less-used commands
|
### Other less-used commands
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ make exec-db # runs psql inside the postgres container, useful for running direct development queries like `DROP DATABASE "bewcloud"; CREATE DATABASE "bewcloud";`
|
make exec-db # runs psql inside the postgres container, useful for running direct development queries like `DROP DATABASE "bewcloud"; CREATE DATABASE "bewcloud";`
|
||||||
$ make build # generates all static files for production deploy
|
make build # generates all static files for production deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
- Routes defined at `routes/`.
|
- Routes are defined at `routes/`.
|
||||||
- Static files are defined at `static/`.
|
- Static files are defined at `static/`.
|
||||||
- Frontend-only components are defined at `components/`.
|
- Frontend-only components are defined at `components/`.
|
||||||
- Isomorphic components are defined at `islands/`.
|
- Isomorphic components are defined at `islands/`.
|
||||||
@@ -101,7 +98,7 @@ Just push to the `main` branch.
|
|||||||
|
|
||||||
## How does Contacts/CardDav and Calendar/CalDav work?
|
## How does Contacts/CardDav and Calendar/CalDav work?
|
||||||
|
|
||||||
CalDav/CardDav is now available since [v2.3.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0), using [Radicale](https://radicale.org/v3.html) via Docker, which is already _very_ efficient (and battle-tested). The client for CardDav is available since [v2.4.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0) and for CalDav is not yet implemented. [Check this tag/release for custom-made server and clients where it was all mostly working, except for many edge cases](https://github.com/bewcloud/bewcloud/releases/tag/v0.0.1-self-made-carddav-caldav).
|
CalDav/CardDav is now available since [v2.3.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0), using [Radicale](https://radicale.org/v3.html) via Docker, which is already _very_ efficient (and battle-tested). The "Contacts" client for CardDav is available since [v2.4.0](https://github.com/bewcloud/bewcloud/releases/tag/v2.3.0) and for CalDav is not yet implemented. [Check this tag/release for custom-made server and clients where it was all mostly working, except for many edge cases](https://github.com/bewcloud/bewcloud/releases/tag/v0.0.1-self-made-carddav-caldav).
|
||||||
|
|
||||||
In order to share a calendar, you can either have a shared user, or you can symlink the calendar to the user's own calendar (simply `ln -s /<absolute-path-to-data-radicale>/collections/collection-root/<owner-user-id>/<calendar-to-share> /<absolute-path-to-data-radicale>/collections/collection-root/<user-id-to-share-with>/`).
|
In order to share a calendar, you can either have a shared user, or you can symlink the calendar to the user's own calendar (simply `ln -s /<absolute-path-to-data-radicale>/collections/collection-root/<owner-user-id>/<calendar-to-share> /<absolute-path-to-data-radicale>/collections/collection-root/<user-id-to-share-with>/`).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
website:
|
website:
|
||||||
image: ghcr.io/bewcloud/bewcloud:v2.4.5
|
image: ghcr.io/bewcloud/bewcloud:v2.4.6
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 127.0.0.1:8000:8000
|
- 127.0.0.1:8000:8000
|
||||||
@@ -21,8 +21,9 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- bewcloud-db:/var/lib/postgresql/data
|
- bewcloud-db:/var/lib/postgresql/data
|
||||||
ports:
|
# NOTE: uncomment below only if you need to connect to the database from outside the container
|
||||||
- 127.0.0.1:5432:5432
|
# ports:
|
||||||
|
# - 127.0.0.1:5432:5432
|
||||||
ulimits:
|
ulimits:
|
||||||
memlock:
|
memlock:
|
||||||
soft: -1
|
soft: -1
|
||||||
@@ -32,6 +33,7 @@ services:
|
|||||||
# NOTE: If you don't want to use the CardDav/CalDav servers, you can comment/remove this service.
|
# NOTE: If you don't want to use the CardDav/CalDav servers, you can comment/remove this service.
|
||||||
radicale:
|
radicale:
|
||||||
image: tomsquest/docker-radicale:3.5.4.0
|
image: tomsquest/docker-radicale:3.5.4.0
|
||||||
|
# NOTE: uncomment below only if you need to connect to the CardDav/CalDav servers from outside the container
|
||||||
# ports:
|
# ports:
|
||||||
# - 127.0.0.1:5232:5232
|
# - 127.0.0.1:5232:5232
|
||||||
init: true
|
init: true
|
||||||
|
|||||||
36
render.yaml
36
render.yaml
@@ -1,36 +0,0 @@
|
|||||||
services:
|
|
||||||
- type: web
|
|
||||||
name: bewcloud
|
|
||||||
env: docker
|
|
||||||
plan: starter
|
|
||||||
healthCheckPath: /
|
|
||||||
envVars:
|
|
||||||
- key: BASE_URL
|
|
||||||
fromService:
|
|
||||||
name: bewcloud
|
|
||||||
type: web
|
|
||||||
property: host
|
|
||||||
- key: POSTGRESQL_HOST
|
|
||||||
fromDatabase:
|
|
||||||
name: bewcloud
|
|
||||||
property: host
|
|
||||||
- key: POSTGRESQL_USER
|
|
||||||
fromDatabase:
|
|
||||||
name: bewcloud
|
|
||||||
property: user
|
|
||||||
- key: POSTGRESQL_PASSWORD
|
|
||||||
fromDatabase:
|
|
||||||
name: bewcloud
|
|
||||||
property: password
|
|
||||||
- key: POSTGRESQL_DBNAME
|
|
||||||
fromDatabase:
|
|
||||||
name: bewcloud
|
|
||||||
property: database
|
|
||||||
- key: POSTGRESQL_PORT
|
|
||||||
fromDatabase:
|
|
||||||
name: bewcloud
|
|
||||||
property: port
|
|
||||||
|
|
||||||
databases:
|
|
||||||
- name: bewcloud
|
|
||||||
plan: basic-256mb
|
|
||||||
@@ -31,11 +31,16 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
|||||||
const requestBodyText = await request.clone().text();
|
const requestBodyText = await request.clone().text();
|
||||||
|
|
||||||
// Remove the `/caldav/` prefix from the hrefs in the request
|
// Remove the `/caldav/` prefix from the hrefs in the request
|
||||||
const parsedRequestBodyText = requestBodyText.replaceAll('<href>/caldav/', `<href>/`).replaceAll(
|
let parsedRequestBodyText = requestBodyText.replaceAll('<href>/caldav/', `<href>/`).replaceAll(
|
||||||
':href>/caldav/',
|
':href>/caldav/',
|
||||||
`:href>/`,
|
`:href>/`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// The spec doesn't allow a body for GET or HEAD requests (and Deno fails if you try)
|
||||||
|
if (request.method === 'GET' || request.method === 'HEAD') {
|
||||||
|
parsedRequestBodyText = '';
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(`${calendarConfig.calDavUrl}/${path}`, {
|
const response = await fetch(`${calendarConfig.calDavUrl}/${path}`, {
|
||||||
headers: {
|
headers: {
|
||||||
...Object.fromEntries(request.headers.entries()),
|
...Object.fromEntries(request.headers.entries()),
|
||||||
|
|||||||
@@ -31,11 +31,16 @@ export const handler: Handler<Data, FreshContextState> = async (request, context
|
|||||||
const requestBodyText = await request.clone().text();
|
const requestBodyText = await request.clone().text();
|
||||||
|
|
||||||
// Remove the `/carddav/` prefix from the hrefs in the request
|
// Remove the `/carddav/` prefix from the hrefs in the request
|
||||||
const parsedRequestBodyText = requestBodyText.replaceAll('<href>/carddav/', `<href>/`).replaceAll(
|
let parsedRequestBodyText = requestBodyText.replaceAll('<href>/carddav/', `<href>/`).replaceAll(
|
||||||
':href>/carddav/',
|
':href>/carddav/',
|
||||||
`:href>/`,
|
`:href>/`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// The spec doesn't allow a body for GET or HEAD requests (and Deno fails if you try)
|
||||||
|
if (request.method === 'GET' || request.method === 'HEAD') {
|
||||||
|
parsedRequestBodyText = '';
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(`${contactsConfig.cardDavUrl}/${path}`, {
|
const response = await fetch(`${contactsConfig.cardDavUrl}/${path}`, {
|
||||||
headers: {
|
headers: {
|
||||||
...Object.fromEntries(request.headers.entries()),
|
...Object.fromEntries(request.headers.entries()),
|
||||||
|
|||||||
Reference in New Issue
Block a user