mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-05-21 01:54:23 +00:00
Add docker stuff
This commit is contained in:
parent
c26ad777a2
commit
7d5867854d
102
docker/Dockerfile
Normal file
102
docker/Dockerfile
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#Version 0.4
|
||||||
|
#Davical + apache
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
#Default configuration: hostname: davical.example
|
||||||
|
# user: admin
|
||||||
|
# pass: 12345
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
MAINTAINER https://github.com/datze
|
||||||
|
|
||||||
|
ARG TIME_ZONE "Europe/Rome"
|
||||||
|
ENV TIME_ZONE=$TIME_ZONE
|
||||||
|
|
||||||
|
ARG HOST_NAME "davical.example"
|
||||||
|
ENV HOST_NAME=$HOST_NAME
|
||||||
|
|
||||||
|
|
||||||
|
RUN addgroup -S apache && adduser -S apache -G apache
|
||||||
|
|
||||||
|
# apk
|
||||||
|
RUN apk --update add \
|
||||||
|
sudo \
|
||||||
|
bash \
|
||||||
|
less \
|
||||||
|
sed \
|
||||||
|
apache2 \
|
||||||
|
apache2-utils \
|
||||||
|
apache2-ssl \
|
||||||
|
php7 \
|
||||||
|
php7-apache2 \
|
||||||
|
php7-pgsql \
|
||||||
|
php7-imap \
|
||||||
|
php7-curl \
|
||||||
|
php7-cgi \
|
||||||
|
php7-xml \
|
||||||
|
php7-gettext \
|
||||||
|
php7-iconv \
|
||||||
|
php7-ldap \
|
||||||
|
php7-pdo \
|
||||||
|
php7-pdo_pgsql \
|
||||||
|
php7-calendar \
|
||||||
|
php7-session \
|
||||||
|
git \
|
||||||
|
libcap \
|
||||||
|
# git
|
||||||
|
&& git clone https://gitlab.com/davical-project/awl.git /usr/share/awl/ \
|
||||||
|
&& git clone https://gitlab.com/davical-project/davical.git /usr/share/davical/ \
|
||||||
|
&& rm -rf /usr/share/davical/.git /usr/share/awl/.git/ \
|
||||||
|
&& apk del git
|
||||||
|
|
||||||
|
|
||||||
|
# config files, shell scripts
|
||||||
|
COPY apache2_start.sh /sbin/apache2_start.sh
|
||||||
|
COPY apache.conf /config/apache.conf
|
||||||
|
COPY davical.php /config/davical.php
|
||||||
|
|
||||||
|
# Apache
|
||||||
|
RUN chown -R root:apache /usr/share/davical \
|
||||||
|
&& cd /usr/share/davical/ \
|
||||||
|
&& find ./ -type d -exec chmod u=rwx,g=rx,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -exec chmod u=rw,g=r,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=r,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -name *.php -exec chmod u=rwx,g=rx,o=r '{}' \; \
|
||||||
|
&& chmod o=rx /usr/share/davical \
|
||||||
|
&& chown -R root:apache /usr/share/awl \
|
||||||
|
&& cd /usr/share/awl/ \
|
||||||
|
&& find ./ -type d -exec chmod u=rwx,g=rx,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -exec chmod u=rw,g=r,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=rx,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=r,o=rx '{}' \; \
|
||||||
|
&& chmod o=rx /usr/share/awl \
|
||||||
|
&& mkdir /etc/davical \
|
||||||
|
&& sed -i /CustomLog/s/^/#/ /etc/apache2/httpd.conf \
|
||||||
|
&& sed -i /ErrorLog/s/^/#/ /etc/apache2/httpd.conf \
|
||||||
|
&& sed -i /TransferLog/s/^/#/ /etc/apache2/httpd.conf \
|
||||||
|
&& sed -i /CustomLog/s/^/#/ /etc/apache2/conf.d/ssl.conf \
|
||||||
|
&& sed -i /ErrorLog/s/^/#/ /etc/apache2/conf.d/ssl.conf \
|
||||||
|
&& sed -i /TransferLog/s/^/#/ /etc/apache2/conf.d/ssl.conf \
|
||||||
|
# permissions for shell scripts and config files
|
||||||
|
&& chmod 0755 /sbin/apache2_start.sh \
|
||||||
|
&& chown -R root:apache /etc/davical \
|
||||||
|
&& chmod -R u=rwx,g=rx,o= /etc/davical \
|
||||||
|
&& chown root:apache /config/davical.php \
|
||||||
|
&& chmod u+rwx,g+rx /config/davical.php \
|
||||||
|
&& ln -s /config/apache.conf /etc/apache2/conf.d/davical.conf \
|
||||||
|
&& ln -s /config/davical.php /etc/davical/config.php \
|
||||||
|
# clean-up etc
|
||||||
|
&& rm -rf /var/cache/apk/* \
|
||||||
|
&& mkdir -p /run/apache2 \
|
||||||
|
&& chown -R apache:apache /var/www /run/apache2 /var/log/apache2 /etc/ssl/apache2 \
|
||||||
|
&& rm /etc/apache2/conf.d/ssl.conf
|
||||||
|
|
||||||
|
#SET THE TIMEZONE
|
||||||
|
RUN apk add --update tzdata
|
||||||
|
RUN cp /usr/share/zoneinfo/$TIME_ZONE /etc/localtime
|
||||||
|
RUN echo $TIME_ZONE > /etc/timezone
|
||||||
|
RUN apk del tzdata
|
||||||
|
|
||||||
|
RUN setcap cap_net_bind_service=+epi /usr/sbin/httpd
|
||||||
|
|
||||||
|
USER apache
|
||||||
61
docker/Dockerfile.createdb
Normal file
61
docker/Dockerfile.createdb
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#Version 0.4
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
#Default configuration: hostname: davical.example
|
||||||
|
# user: admin
|
||||||
|
# pass: 12345
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
MAINTAINER https://github.com/datze
|
||||||
|
|
||||||
|
ARG TIME_ZONE "Europe/Rome"
|
||||||
|
ENV TIME_ZONE=$TIME_ZONE
|
||||||
|
|
||||||
|
ARG HOST_NAME "davical.example"
|
||||||
|
ENV HOST_NAME=$HOST_NAME
|
||||||
|
|
||||||
|
|
||||||
|
# apk
|
||||||
|
RUN apk --update add \
|
||||||
|
sudo \
|
||||||
|
bash \
|
||||||
|
less \
|
||||||
|
sed \
|
||||||
|
postgresql \
|
||||||
|
perl \
|
||||||
|
perl-yaml \
|
||||||
|
perl-dbd-pg \
|
||||||
|
perl-dbi \
|
||||||
|
git \
|
||||||
|
# git
|
||||||
|
&& git clone https://gitlab.com/davical-project/awl.git /usr/share/awl/ \
|
||||||
|
&& git clone https://gitlab.com/davical-project/davical.git /usr/share/davical/ \
|
||||||
|
&& rm -rf /usr/share/davical/.git /usr/share/awl/.git/ \
|
||||||
|
&& apk del git
|
||||||
|
|
||||||
|
|
||||||
|
# config files, shell scripts
|
||||||
|
COPY initialize_db.sh /sbin/initialize_db.sh
|
||||||
|
|
||||||
|
RUN cd /usr/share/davical/ \
|
||||||
|
&& find ./ -type d -exec chmod u=rwx,g=rx,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -exec chmod u=rw,g=r,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=r,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -name *.php -exec chmod u=rwx,g=rx,o=r '{}' \; \
|
||||||
|
&& chmod o=rx /usr/share/davical/dba/update-davical-database \
|
||||||
|
&& chmod o=rx /usr/share/davical \
|
||||||
|
&& cd /usr/share/awl/ \
|
||||||
|
&& find ./ -type d -exec chmod u=rwx,g=rx,o=rx '{}' \; \
|
||||||
|
&& find ./ -type f -exec chmod u=rw,g=r,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=rx,o=r '{}' \; \
|
||||||
|
&& find ./ -type f -name *.sh -exec chmod u=rwx,g=r,o=rx '{}' \; \
|
||||||
|
&& chmod o=rx /usr/share/awl \
|
||||||
|
&& mkdir /etc/davical \
|
||||||
|
# permissions for shell scripts and config files
|
||||||
|
&& chmod 0755 /sbin/initialize_db.sh \
|
||||||
|
&& chmod -R u=rwx,g=rx,o= /etc/davical \
|
||||||
|
# clean-up etc
|
||||||
|
&& rm -rf /var/cache/apk/* \
|
||||||
|
&& mkdir /run/postgresql \
|
||||||
|
&& chmod a+w /run/postgresql
|
||||||
|
|
||||||
73
docker/README.md
Normal file
73
docker/README.md
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# DAViCal Docker Container
|
||||||
|
Docker image for a complete [DAViCal](https://www.davical.org/) server (DAViCal + Apache2 + PostgreSQL) on Alpine Linux.
|
||||||
|
The repository on github.org contains example configuration files for DAViCal (as well as the Dockerfile to create the Docker image).
|
||||||
|
|
||||||
|
### About DAViCal
|
||||||
|
[DAViCal](https://www.davical.org/) is a server for shared calendars. It implements the [CalDAV protocol](https://wikipedia.org/wiki/CalDAV) and stores calendars in the [iCalendar format](https://wikipedia.org/wiki/ICalendar).
|
||||||
|
|
||||||
|
List of supported clients: Mozilla Thunderbird/Lightning, Evolution, Mulberry, Chandler, iCal, ...
|
||||||
|
|
||||||
|
**Features**
|
||||||
|
> - DAViCal is Free Software licensed under the General Public License.
|
||||||
|
> - uses an SQL database for storage of event data
|
||||||
|
> - supports backward-compatible access via WebDAV in read-only or read-write mode (not recommended)
|
||||||
|
> - is committed to inter-operation with the widest possible CalDAV client software.
|
||||||
|
>
|
||||||
|
>DAViCal supports basic delegation of read/write access among calendar users, multiple users or clients reading and writing the same calendar entries over time, and scheduling of meetings with free/busy time displayed.
|
||||||
|
(*https://www.davical.org/*)
|
||||||
|
|
||||||
|
### Settings
|
||||||
|
- Exposed Ports: TCP 80 and TCP 443
|
||||||
|
- Exposed Volumes: /config and /var/lib/postgresql/data/
|
||||||
|
- Exposed Variables: TIME_ZONE and HOST_NAME
|
||||||
|
|
||||||
|
On TCP 80 the web server listens with DAViCal on hostname davical.example (set your local host file to point davical.example to 127.0.0.1)
|
||||||
|
|
||||||
|
Exposed environment variables can be overwritten when creating the docker container (eg. docke run -e HOST_NAME='example.com').
|
||||||
|
TIME_ZONE is set by default to "Europe/Rome" but you can set as you prefer according to tzdata (for example to "Europe/Paris" or "Europe/London")
|
||||||
|
HOST_NAME is set by default to "davical.example"
|
||||||
|
|
||||||
|
/config can be mount and must contain a personalized version of all configuration files necessary:
|
||||||
|
|
||||||
|
- apache.conf
|
||||||
|
- davical.php
|
||||||
|
- rsyslog.conf
|
||||||
|
- supervisord.conf
|
||||||
|
|
||||||
|
So you can download the configuration files present in this repository, alter and copy them into a directory to be mounted on /config and the container using them!
|
||||||
|
To use HTTPS on TCP port 433, you need to uncomment the related lines in apache.conf and provide a SSL certificate for your domain in /config.
|
||||||
|
|
||||||
|
/var/lib/postgresql/data contains the database and the directory backups/. In this directory crond every day saves (thanks to /sbin/backup_db) a dump of DAViCal database to backups/davical_backup.tar
|
||||||
|
It is possible to restore the database using a backup: put the backup into the mounted /config, run the container and after the initialization use "docker exec container_name /sbin/restore_db"
|
||||||
|
|
||||||
|
The rsyslog server is configured to collect all logs from apache and postgres into /var/log/messages but you can personalize the configuration altering rsyslog.conf and put it in /config. rsyslog does NOT collect apache access.log (it is disabled)
|
||||||
|
|
||||||
|
The **default admin user** is: *admin* with password: *12345* (you can alter it from the DAViCal gui).
|
||||||
|
|
||||||
|
### Docker examples
|
||||||
|
|
||||||
|
**Simple test**
|
||||||
|
```
|
||||||
|
docker run -d --name davical-test -p 8080:80 datze/davical_https
|
||||||
|
```
|
||||||
|
Creates and runs a DAViCal Docker container which is fully operable on host TCP port 8080. Does not require any further configuration. *Attention! Only for testing! When the container is deleted, all stored calendars are lost!*
|
||||||
|
|
||||||
|
**Simple HTTP mode**
|
||||||
|
```
|
||||||
|
docker run -d --name davical -p 8080:80 -v var/davical/data:/var/lib/postgresql/data datze/davical_https
|
||||||
|
```
|
||||||
|
Creates and runs a DAViCal Docker container with default configurations on host TCP port 8080. The **database files are stored in /var/davical/data**. This is the simplest set-up without loosing calendars when the container is deleted.
|
||||||
|
|
||||||
|
**Full example**
|
||||||
|
```
|
||||||
|
docker run -d --name davical -p 8080:80 -p 8443:443 -v /var/davical/config:/config -v /var/davical/data:/var/lib/postgresql/data -e HOST_NAME='my.example.com' -e TIME_ZONE='Europe/Berlin' datze/davical_https
|
||||||
|
```
|
||||||
|
Creates and runs a DAViCal Docker container which will be accessible on the host system on TCP ports 8080 and 8443 (HTTPS).
|
||||||
|
The time zone is set to Europe/Berlin and the hostname is my.example.com.
|
||||||
|
|
||||||
|
The **config files must be created in /var/davical/config** and the **database files are stored in /var/davical/data**.
|
||||||
|
|
||||||
|
A SSL certificate must be placed in /var/davical/config and referenced in /var/davical/config/apache.conf. (Create a self-signed certificate with something like `openssl req -x509 -newkey rsa:4096 -keyout /var/davical/config/ssl/private.pem -out /var/davical/config/ssl/cert.pem -days 1000`)
|
||||||
|
|
||||||
|
### Credits
|
||||||
|
Based on https://github.com/IridiumXOR/davical and https://hub.docker.com/r/oliveria/davical (no HTTPS, older PG and PHP versions).
|
||||||
59
docker/apache.conf
Normal file
59
docker/apache.conf
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
AddHandler php7-script .php
|
||||||
|
AddType text/html .php
|
||||||
|
ServerName davical.example
|
||||||
|
|
||||||
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||||||
|
|
||||||
|
<VirtualHost *:80 >
|
||||||
|
DocumentRoot /usr/share/davical/htdocs
|
||||||
|
DirectoryIndex index.php index.html
|
||||||
|
|
||||||
|
Alias /images/ /usr/share/davical/htdocs/images/
|
||||||
|
<Directory /usr/share/davical/htdocs/>
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
#Activate RewriteEngine
|
||||||
|
RewriteEngine On
|
||||||
|
# Filter all files that do not exist
|
||||||
|
RewriteCond %{LA-U:REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{LA-U:REQUEST_FILENAME} !-d
|
||||||
|
# and redirect them to our caldav.php
|
||||||
|
RewriteRule ^(.*)$ /caldav.php/$1 [NC,L]
|
||||||
|
|
||||||
|
php_value include_path /usr/share/awl/inc
|
||||||
|
php_value magic_quotes_gpc 0
|
||||||
|
php_value magic_quotes_runtime 0
|
||||||
|
php_value register_globals 0
|
||||||
|
php_value error_reporting "E_ALL & ~E_NOTICE"
|
||||||
|
php_value default_charset "utf-8"
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
#<VirtualHost *:443 >
|
||||||
|
# DocumentRoot /usr/share/davical/htdocs
|
||||||
|
# DirectoryIndex index.php index.html
|
||||||
|
#
|
||||||
|
# Alias /images/ /usr/share/davical/htdocs/images/
|
||||||
|
# <Directory /usr/share/davical/htdocs/>
|
||||||
|
# Require all granted
|
||||||
|
# </Directory>
|
||||||
|
#
|
||||||
|
# #Activate RewriteEngine
|
||||||
|
# RewriteEngine On
|
||||||
|
# # Filter all files that do not exist
|
||||||
|
# RewriteCond %{LA-U:REQUEST_FILENAME} !-f
|
||||||
|
# RewriteCond %{LA-U:REQUEST_FILENAME} !-d
|
||||||
|
# # and redirect them to our caldav.php
|
||||||
|
# RewriteRule ^(.*)$ /caldav.php/$1 [NC,L]
|
||||||
|
#
|
||||||
|
# php_value include_path /usr/share/awl/inc
|
||||||
|
# php_value magic_quotes_gpc 0
|
||||||
|
# php_value magic_quotes_runtime 0
|
||||||
|
# php_value register_globals 0
|
||||||
|
# php_value error_reporting "E_ALL & ~E_NOTICE"
|
||||||
|
# php_value default_charset "utf-8"
|
||||||
|
#
|
||||||
|
# SSLEngine on
|
||||||
|
# SSLCertificateFile "/config/ssl/cert.pem"
|
||||||
|
# SSLCertificateKeyFile "/config/ssl/private.pem"
|
||||||
|
#</VirtualHost>
|
||||||
3
docker/apache2_start.sh
Normal file
3
docker/apache2_start.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
getcap /usr/sbin/httpd && /usr/sbin/httpd -e error -E /var/log/apache2/apache-start.log -DFOREGROUND && tail -f /var/log/apache2/*
|
||||||
7
docker/dav-env
Normal file
7
docker/dav-env
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
ADMIN_PASSWORD=1234
|
||||||
|
DAVICAL_APP_PASSWORD=654321
|
||||||
|
DAVICAL_APP_USER=davical_app
|
||||||
|
DAVICAL_DBA_PASSWORD=123456
|
||||||
|
DAVICAL_DBA_USER=davical_dba
|
||||||
|
DBAOPTS="--dbhost=postgres --dbuser davical_dba --dbpass 123456 "
|
||||||
|
PSQLOPTS="-U davical_dba -h postgres -p 5432 "
|
||||||
467
docker/davical.php
Normal file
467
docker/davical.php
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
<?php
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* These apply everywhere and will need setting *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
$c->domain_name = getenv('HOST_NAME')?:'davical.example';
|
||||||
|
$c->sysabbr = 'davical';
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
********* Mandatory *********
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database connection: DAViCal will attempt to connect to the database by
|
||||||
|
* successively applying connection parameters from the array in
|
||||||
|
* $c->pg_connect.
|
||||||
|
*/
|
||||||
|
//$c->pg_connect[] = "dbname=davical user=davical_app";
|
||||||
|
$c->pg_connect[] = "dbname=davical user=davical_app port=5432 host=postgres password=654321";
|
||||||
|
// $c->pg_connect[] = "dbname=davical user=davical_app port=5433 host=somehost password=mypass";
|
||||||
|
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
********* Desirable *********
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "system_name" is used to specify the authentication realm of the server, as
|
||||||
|
* well as being used as a name to display in various places.
|
||||||
|
* Default: DAViCal CalDAV Server
|
||||||
|
*/
|
||||||
|
$c->system_name = "DAViCal CalDAV Server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If "hide_TODO" is true, then VTODO requested from someone other than the
|
||||||
|
* admin or owner of a calendar will not get an answer. Often these todo are
|
||||||
|
* only relevant to the owner, but in some shared calendar situations they
|
||||||
|
* might not be in which case you should set this to false.
|
||||||
|
* Default: true
|
||||||
|
*/
|
||||||
|
// $c->hide_TODO = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If "readonly_webdav_collections" is true, then calendars accessed via WebDAV
|
||||||
|
* will be read-only. Any changes to them must be applied via CalDAV.
|
||||||
|
*
|
||||||
|
* You may want to set this to false during your initial setup to make it
|
||||||
|
* easier for people to PUT whole calendars as part of the conversion of
|
||||||
|
* their data. After this, it is recommended to turn it off so that clients
|
||||||
|
* which have been misconfigured are readily identifiable.
|
||||||
|
* Default: true
|
||||||
|
*/
|
||||||
|
// $c->readonly_webdav_collections = false;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* ADMIN web Interface *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
/**
|
||||||
|
* Address displayed on the login page to indicate who you should ask if you
|
||||||
|
* have problems logging on. Also for the "From" header of the email sent when
|
||||||
|
* a user has lost his password and clicks on the "Help! I've forgotten my
|
||||||
|
* password" on the login page.
|
||||||
|
*/
|
||||||
|
$c->admin_email ='admin@example.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this to 'true' in order to restrict the /setup.php page (which contains
|
||||||
|
* the entire phpinfo() output) to 'Administrator' users.
|
||||||
|
* Default: false
|
||||||
|
*/
|
||||||
|
$c->restrict_setup_to_admin = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "enable_row_linking" option controls whether javascript is used
|
||||||
|
* to make the entire row clickable in browse lists in the administration
|
||||||
|
* pages. Since this doesn't work in Konqueror you may want to set this
|
||||||
|
* to false if you expect people to be using Konqueror with the DAViCal
|
||||||
|
* administration pages.
|
||||||
|
* Default=true
|
||||||
|
*/
|
||||||
|
// $c->enable_row_linking = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These should be an array of style sheets with a path specified relative
|
||||||
|
* to the root directory. Used for overriding display styles in the admin
|
||||||
|
* interface.
|
||||||
|
* e.g. : $c->local_styles = array('/css/my.css');
|
||||||
|
*/
|
||||||
|
// $c->local_styles = array();
|
||||||
|
// $c->print_styles = array();
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* Caldav Server *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "collections_always_exist" value defines whether a MKCALENDAR
|
||||||
|
* command is needed to create a calendar collection before calendar
|
||||||
|
* resources can be stored in it. You will want to leave this to the
|
||||||
|
* default (true) if people will be using Evolution or Sunbird /
|
||||||
|
* Lightning against this because that software does not support the
|
||||||
|
* creation of calendar collections.
|
||||||
|
* Default: true
|
||||||
|
*/
|
||||||
|
// $c->collections_always_exist = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of a user's "home" calendar. This will be created for each
|
||||||
|
* new user.
|
||||||
|
* Default: 'calendar'
|
||||||
|
*/
|
||||||
|
//$c->home_calendar_name = 'calendar';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of groups / permissions which should be automatically added
|
||||||
|
* for each new user created. This is a crude mechanism which we
|
||||||
|
* will hopefully manage to work out some better approach for in the
|
||||||
|
* future. For now, create an array that looks something like:
|
||||||
|
* array( 9 => 'R', 4 => 'A' )
|
||||||
|
* to create a 'read' relationship to user_no 9 and an 'all' relation
|
||||||
|
* with user_no 4.
|
||||||
|
* Default: none
|
||||||
|
*/
|
||||||
|
// $c->default_relationships = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of the privileges which will be configured for a user by default
|
||||||
|
* from the possible set of real privileges:
|
||||||
|
* 'read', 'write-properties', 'write-content', 'unlock', 'read-acl', 'read-current-user-privilege-set',
|
||||||
|
* 'bind', 'unbind', 'write-acl', 'read-free-busy',
|
||||||
|
* 'schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy',
|
||||||
|
* 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy'
|
||||||
|
*
|
||||||
|
* Or also from these aggregated privileges:
|
||||||
|
* 'write', 'schedule-deliver', 'schedule-send', 'all'
|
||||||
|
*/
|
||||||
|
$c->default_privileges = array('all');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of fields on the usr record which should be set to specific
|
||||||
|
* values when the users are created.
|
||||||
|
* Default: none
|
||||||
|
*/
|
||||||
|
$c->template_usr = array( 'active' => true,
|
||||||
|
'locale' => 'en_EN',
|
||||||
|
'date_format_type' => 'E',
|
||||||
|
'email_ok' => date('Y-m-d')
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, then remote scheduling will be enabled. There is a possibility
|
||||||
|
* of receiving spam events in calendars if enabled, you will at least know
|
||||||
|
* what domain the spam came from as domain key signatures are required for
|
||||||
|
* events to be accepted.
|
||||||
|
*
|
||||||
|
* You probably need to setup Domain Keys for your domain as well as the
|
||||||
|
* appropiate DNS SRV records.
|
||||||
|
*
|
||||||
|
* for example, if DAViCal is installed on cal.example.com you should have
|
||||||
|
* DNS SRV records like this:
|
||||||
|
* _ischedules._tcp.example.com. IN SRV 0 1 443 cal.example.com
|
||||||
|
* _ischedule._tcp.example.com. IN SRV 0 1 80 cal.example.com
|
||||||
|
*
|
||||||
|
* DNS TXT record for signing outbound requests
|
||||||
|
* example:
|
||||||
|
* cal._domainkey.example.com. 86400 IN TXT "k=rsa\; t=s\; p=PUBKEY"
|
||||||
|
* Default: false
|
||||||
|
*/
|
||||||
|
// $c->enable_scheduling = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain Key domain to use when signing outbound scheduling requests, this
|
||||||
|
* is the domain with the public key in a TXT record as shown above.
|
||||||
|
*
|
||||||
|
* TODO: enable domain/signing by per user keys, patches welcome.
|
||||||
|
* Default: none
|
||||||
|
*/
|
||||||
|
// $c->scheduling_dkim_domain = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain Key selector to use when signing outbound scheduling requests.
|
||||||
|
*
|
||||||
|
* TODO: enable selectors/signing by per user keys, patches welcome.
|
||||||
|
* Default: 'cal'
|
||||||
|
*/
|
||||||
|
// $c->scheduling_dkim_selector = 'cal';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Domain Key private key
|
||||||
|
* Required if you want to enable outbound remote server scheduling
|
||||||
|
* Default: none
|
||||||
|
*/
|
||||||
|
// $c->schedule_private_key = 'PRIVATE-KEY-BASE-64-DATA';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External subscription (BIND) minimum refresh interval
|
||||||
|
* Required if you want to enable remote binding ( webcal subscriptions )
|
||||||
|
* Default: none
|
||||||
|
*/
|
||||||
|
// $c->external_refresh = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "support_obsolete_free_busy_property" value controls whether,
|
||||||
|
* during a PROPFIND, the obsolete Scheduling property "calendar-free-busy-set"
|
||||||
|
* is returned. Set the value to true to support the property only if your
|
||||||
|
* client requires it, however note that PROPFIND performance may be
|
||||||
|
* adversely affected if you do so.
|
||||||
|
* Introduced in DAViCal version 1.1.4 in support of Issue #31 Database
|
||||||
|
* Performance Improvements.
|
||||||
|
* Default: false
|
||||||
|
*/
|
||||||
|
// $c->support_obsolete_free_busy_property = false;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* External Authentication Sources *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow specifying another way to control access of the user by authenticating
|
||||||
|
* him against other drivers such has LDAP (the default is the PgSQL DB)
|
||||||
|
* $c->authenticate_hook['call'] should be set to the name of the plugin and must
|
||||||
|
* be a valid function that will be call like this:
|
||||||
|
* call_user_func( $c->authenticate_hook['call'], $username, $password )
|
||||||
|
*
|
||||||
|
* The login mecanism is made in 2 places:
|
||||||
|
* - for the web interface in: index.php that calls DAViCalSession.php that extends
|
||||||
|
* Session.php (from AWL libraries)
|
||||||
|
* - for the caldav client in: caldav.php that calls BasicAuthSession.php
|
||||||
|
* Both Session.php and BasicAuthSession.php check against the
|
||||||
|
* authenticate_hook['call'], although for BasicAuthSession.php this will be for
|
||||||
|
* each page. For Session.php this will only occur during login.
|
||||||
|
*
|
||||||
|
* $c->authenticate_hook['config'] should be set up with any configuration data
|
||||||
|
* needed by the authenticate call for the moment used only in awl/inc/AuthPlugins.php
|
||||||
|
* and he used to authenticate the user should be at least 'password,user_no'
|
||||||
|
* awl/inc/AuthPlugins.php is a sample file not used by showing what could be
|
||||||
|
* a hook
|
||||||
|
*
|
||||||
|
* $c->authenticate_hook['optional'] = true; can be set to try default authentication
|
||||||
|
* as well in case the configured hook should report a failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************/
|
||||||
|
/******* Other AWL hook *********/
|
||||||
|
/********************************/
|
||||||
|
// require_once('auth-functions.php');
|
||||||
|
// $c->authenticate_hook = array(
|
||||||
|
// 'call' => 'AuthExternalAwl',
|
||||||
|
// 'config' => array(
|
||||||
|
// // A PgSQL database connection string for the database containing user records
|
||||||
|
// 'connection' => 'dbname=wrms host=otherhost port=5433 user=general',
|
||||||
|
// // Which columns should be fetched from the database
|
||||||
|
// 'columns' => "user_no, active, email_ok, joined, last_update AS updated, last_used, username, password, fullname, email",
|
||||||
|
// // a WHERE clause to limit the records returned.
|
||||||
|
// 'where' => "active AND org_code=7"
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
|
||||||
|
|
||||||
|
/********************************/
|
||||||
|
/*********** LDAP hook **********/
|
||||||
|
/********************************/
|
||||||
|
/*
|
||||||
|
* For Active Directory go down to the next example.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//$c->authenticate_hook['call'] = 'LDAP_check';
|
||||||
|
//$c->authenticate_hook['config'] = array(
|
||||||
|
// 'host' => 'www.tennaxia.net', //host name of your LDAP Server
|
||||||
|
// 'port' => '389', //port
|
||||||
|
|
||||||
|
/* For the initial bind to be anonymous leave bindDN and passDN
|
||||||
|
commented out */
|
||||||
|
// DN to bind to this server enabling to perform request
|
||||||
|
// 'bindDN'=> 'cn=manager,cn=internal,dc=tennaxia,dc=net',
|
||||||
|
// Password of the previous bindDN to bind to this server enabling to perform request
|
||||||
|
// 'passDN'=> 'xxxxxxxx',
|
||||||
|
|
||||||
|
// 'protocolVersion' => '3', //Version of LDAP protocol to use
|
||||||
|
// 'baseDNUsers'=> 'dc=tennaxia,dc=net', //where to look at valid user
|
||||||
|
// 'filterUsers' => 'objectClass=kolabInetOrgPerson', //filter which must validate a user according to RFC4515, i.e. surrounded by brackets
|
||||||
|
// 'baseDNGroups' => 'ou=divisions,dc=tennaxia,dc=net', //where to look for groups
|
||||||
|
// 'filterGroups' => 'objectClass=groupOfUniqueNames', //filter with same rules as filterUsers
|
||||||
|
/** /!\ "username" should be set and "updated" must be set **/
|
||||||
|
// 'mapping_field' => array("username" => "uid",
|
||||||
|
// "updated" => "modifyTimestamp",
|
||||||
|
// "fullname" => "cn" ,
|
||||||
|
// "email" =>"mail"
|
||||||
|
// ), //used to create the user based on his ldap properties
|
||||||
|
// 'group_mapping_field' => array("username" => "cn",
|
||||||
|
// "updated" => "modifyTimestamp",
|
||||||
|
// "fullname" => "cn" ,
|
||||||
|
// "members" =>"memberUid"
|
||||||
|
// ), //used to create the group based on the ldap properties
|
||||||
|
/** used to set default value for all users, will be overcharged by ldap if defined also in mapping_field **/
|
||||||
|
// 'default_value' => array("date_format_type" => "E","locale" => "fr_FR"),
|
||||||
|
/** foreach key set start and length in the string provided by ldap
|
||||||
|
example for openLDAP timestamp : 20070503162215Z **/
|
||||||
|
// 'format_updated'=> array('Y' => array(0,4),'m' => array(4,2),'d'=> array(6,2),'H' => array(8,2),'M'=>array(10,2),'S' => array(12,2)),
|
||||||
|
// 'startTLS' => 'yes', // Require that TLS is used for LDAP?
|
||||||
|
// If ldap_start_tls is not working, it is probably
|
||||||
|
// because php wants to validate the server's
|
||||||
|
// certificate. Try adding "TLS_REQCERT never" to the
|
||||||
|
// ldap configuration file that php uses (e.g. /etc/ldap.conf
|
||||||
|
// or /etc/ldap/ldap.conf). Of course, this lessens security!
|
||||||
|
// 'scope' => 'subtree', // Search scope to use, defaults to subtree.
|
||||||
|
// // Allowed values: base, onelevel, subtree.
|
||||||
|
//
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// /* If there is some user you do not want to sync from LDAP, put their username in this list */
|
||||||
|
// $c->do_not_sync_from_ldap = array( 'admin' => true );
|
||||||
|
//
|
||||||
|
//include('drivers_ldap.php');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the following LDAP example if you are using Active Directory
|
||||||
|
*
|
||||||
|
* You will need to change host, passDN and DOMAIN in bindDN
|
||||||
|
* and baseDNUsers.
|
||||||
|
*/
|
||||||
|
//$c->authenticate_hook['call'] = 'LDAP_check';
|
||||||
|
//$c->authenticate_hook['config'] = array(
|
||||||
|
// 'host' => 'ldap://ldap.example.net',
|
||||||
|
// 'bindDN' => 'auth@DOMAIN',
|
||||||
|
// 'passDN' => 'secret',
|
||||||
|
// 'baseDNUsers' => 'dc=DOMAIN,dc=local',
|
||||||
|
// 'protocolVersion' => 3,
|
||||||
|
// 'optReferrals' => 0,
|
||||||
|
// 'filterUsers' => '(&(objectcategory=person)(objectclass=user)(givenname=*))',
|
||||||
|
// 'mapping_field' => array("username" => "uid",
|
||||||
|
// "fullname" => "cn" ,
|
||||||
|
// "email" => "mail"),
|
||||||
|
// 'default_value' => array("date_format_type" => "E","locale" => "en_NZ"),
|
||||||
|
// 'format_updated' => array('Y' => array(0,4),'m' => array(4,2),'d'=> array(6,2),'H' => array(8,2),'M'=>array(10,2),'S' => array(12,2))
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// /* If there is some user you do not want to sync from LDAP, put their username in this list */
|
||||||
|
// $c->do_not_sync_from_ldap = array( 'admin' => true );
|
||||||
|
//
|
||||||
|
//include('drivers_ldap.php');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication against PAM using the Squid helper script.
|
||||||
|
*/
|
||||||
|
//$c->authenticate_hook = array(
|
||||||
|
// 'call' => 'SQUID_PAM_check',
|
||||||
|
// 'config' => array( 'script' => '/usr/bin/pam_auth', 'email_base' => 'example.com' )
|
||||||
|
// );
|
||||||
|
//include('drivers_squid_pam.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication against PAM/system password database using pwauth.
|
||||||
|
*/
|
||||||
|
//$c->authenticate_hook = array('call' => 'PWAUTH_PAM_check',
|
||||||
|
// 'config' => array('path' => '/usr/sbin/pwauth',
|
||||||
|
// 'email_base' => 'example.com'));
|
||||||
|
//include('drivers_pwauth_pam.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default locale will be "en_NZ";
|
||||||
|
* If you are in a non-English locale, you can set the default_locale
|
||||||
|
* configuration to one of the supported locales.
|
||||||
|
*
|
||||||
|
* Supported Locales (at present, see: "select * from supported_locales ;" for a full list)
|
||||||
|
*
|
||||||
|
* "de_DE", "en_NZ", "es_AR", "fr_FR", "nl_NL", "ru_RU"
|
||||||
|
*
|
||||||
|
* If you want locale support you probably know more about configuring it than me, but
|
||||||
|
* at this stage it should be noted that all translations are UTF-8, and pages are
|
||||||
|
* served as UTF-8, so you will need to ensure that the UTF-8 versions of these locales
|
||||||
|
* are supported on your system.
|
||||||
|
*
|
||||||
|
* People interested in providing new translations are directed to the Wiki:
|
||||||
|
* http://wiki.davical.org/w/Translating_DAViCal
|
||||||
|
*/
|
||||||
|
$c->default_locale = "it_IT";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default will be $_SERVER['SERVER_NAME'];
|
||||||
|
* This is used to construct URLs which are passed in the answers to the client. You may
|
||||||
|
* want to force this to a specific domain in responses if your system is accessed by
|
||||||
|
* multiple names, otherwise you probably won't need to change it.
|
||||||
|
*/
|
||||||
|
// $c->domain_name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as a fallback for the TZID of an event where one is not supplied as part
|
||||||
|
* of a VEVENT. The local (server) time zone will be used as a default.
|
||||||
|
*/
|
||||||
|
// $c->local_tzid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Many people want this, but it may be a security issue for you, so it is
|
||||||
|
* disabled by default. If you enable it, then confidential / private events
|
||||||
|
* will be visible to the 'organizer' or 'attendee' lists. The reason that
|
||||||
|
* this becomes a security issue is that this identification needs to be based
|
||||||
|
* on the user's e-mail address. The user's e-mail address is generally
|
||||||
|
* something which they can set, so they could change it to be the address of
|
||||||
|
* an attendee of a meeting and then would be able to read the meeting.
|
||||||
|
*
|
||||||
|
* Without this, the only person who can view/change PRIVATE or CONFIDENTIAL
|
||||||
|
* events in a calendar is someone with full administrative rights to the calendar
|
||||||
|
* usually the owner.
|
||||||
|
*
|
||||||
|
* If the only person that devious is your sysadmin then you probably already
|
||||||
|
* enabled this option...
|
||||||
|
*/
|
||||||
|
// $c->allow_get_email_visibility = false;
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* Push Notification Server *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This enable XMPP PubSub push notifications to clients that request them.
|
||||||
|
* N.B. this will publish urls for ALL updates and does NOT restrict
|
||||||
|
* subscription permissions on the jabber server! That means anyone with
|
||||||
|
* read access to the pubsub tree of your jabber server can watch for updates,
|
||||||
|
* they will only see URL's to the updated entries not the calendar data.
|
||||||
|
*
|
||||||
|
* Only tested with ejabberd 2.0.x
|
||||||
|
*/
|
||||||
|
|
||||||
|
// $c->notifications_server = array( 'host' => $_SERVER['SERVER_NAME'], // jabber server hostname
|
||||||
|
// 'jid' => 'user@example.com', // user(JID) to login/ publish as 'password' => '', // password for above account
|
||||||
|
// // 'debug_jid' => 'otheruser@example.com' // send a copy of all publishes to this jid
|
||||||
|
// );
|
||||||
|
// include ( 'pubsub.php' );
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* Detailed Metrics *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This enables a /metrics.php URL containing detailed metrics about the
|
||||||
|
* operation of DAViCal. Ideally you will be running memcache if you are
|
||||||
|
* interested in keeping metrics, but there is a simple metrics collection
|
||||||
|
* available to you without running memcache.
|
||||||
|
*
|
||||||
|
* Note that there is currently no way of enabling metrics via memcache
|
||||||
|
* without memcache being enabled for all of DAViCal.
|
||||||
|
*/
|
||||||
|
$c->metrics_style = 'counters'; // Just the simple counter-based metrics
|
||||||
|
// $c->metrics_style = 'memcache'; // Only the metrics using memcache
|
||||||
|
// $c->metrics_style = 'both'; // Both styles of metrics
|
||||||
|
// $c->metrics_collectors = array('127.0.0.1'); // Restrict access to only this IP address
|
||||||
|
$c->metrics_require_user = 'admin'; // Restrict access to only connections authenticating as this user
|
||||||
|
|
||||||
|
|
||||||
49
docker/docker-compose.yml
Normal file
49
docker/docker-compose.yml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
|
||||||
|
davical:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
TIME_ZONE: Europe/Paris
|
||||||
|
ports:
|
||||||
|
- "8050:80"
|
||||||
|
env_file: dav-env
|
||||||
|
# volumes:
|
||||||
|
# - /var/davical/config:/config:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
createdb:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
entrypoint: ["/sbin/apache2_start.sh"]
|
||||||
|
|
||||||
|
createdb:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.createdb
|
||||||
|
args:
|
||||||
|
TIME_ZONE: Europe/Paris
|
||||||
|
env_file: dav-env
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
entrypoint: ["/sbin/initialize_db.sh"]
|
||||||
|
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: eorihasdfasdf
|
||||||
|
DAVICAL_DBA_PASSWORD: 123456
|
||||||
|
DAVICAL_APP_PASSWORD: 654321
|
||||||
|
volumes:
|
||||||
|
- ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD-SHELL", "psql -U postgres -c 'select 1'|grep -q 1" ]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 1s
|
||||||
|
retries: 30
|
||||||
|
|
||||||
7
docker/docker-entrypoint-initdb.d/init-user-db.sh
Normal file
7
docker/docker-entrypoint-initdb.d/init-user-db.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
CREATE ROLE davical_dba CREATEDB LOGIN password '${DAVICAL_DBA_PASSWORD}' ;
|
||||||
|
CREATE ROLE davical_app LOGIN password '${DAVICAL_APP_PASSWORD}';
|
||||||
|
EOSQL
|
||||||
15
docker/initialize_db.sh
Normal file
15
docker/initialize_db.sh
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#CHECK IF THE DAVICAL DATABASE EXISTS, OTHERWISE INITIALIZE IT
|
||||||
|
echo "postgres:5432:*:davical_dba:${DAVICAL_DBA_PASSWORD}" > ~/.pgpass
|
||||||
|
chmod 600 ~/.pgpass
|
||||||
|
|
||||||
|
INITIALIZED_DB=$(psql -U davical_dba -h postgres -p 5432 -d template1 -c "\l" | grep -c davical)
|
||||||
|
if [[ $INITIALIZED_DB == 0 ]]; then
|
||||||
|
/usr/share/davical/dba/create-database.sh davical ${ADMIN_PASSWORD}
|
||||||
|
fi
|
||||||
|
unset INITIALIZED_DB
|
||||||
|
|
||||||
|
#UPDATE ALWAYS THE DATABASE
|
||||||
|
/usr/share/davical/dba/update-davical-database ${DBAOPTS} --dbhost postgres --dbuser "${DAVICAL_DBA_USER}" --dbname "davical" --appuser "${DAVICAL_APP_USER}"
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user