diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9d241b539..f3f787fec 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -71,7 +71,7 @@ review_docs:
- cd docs
- apt-get update
- apt-get install -y graphviz
- - pip install sphinx sphinx_rtd_theme
+ - pip install sphinx sphinx_rtd_theme django-environ django
script:
- ./build_docs.sh
cache:
diff --git a/api/config/settings/common.py b/api/config/settings/common.py
index c98b1b8c6..9f8cfdf50 100644
--- a/api/config/settings/common.py
+++ b/api/config/settings/common.py
@@ -1,13 +1,4 @@
# -*- coding: utf-8 -*-
-"""
-Django settings for funkwhale_api project.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/dev/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/dev/ref/settings/
-"""
from __future__ import absolute_import, unicode_literals
import datetime
@@ -29,6 +20,9 @@ APPS_DIR = ROOT_DIR.path("funkwhale_api")
env = environ.Env()
LOGLEVEL = env("LOGLEVEL", default="info").upper()
+"""
+Default logging level for the Funkwhale processes""" # pylint: disable=W0105
+
LOGGING_CONFIG = None
logging.config.dictConfig(
{
@@ -57,7 +51,10 @@ logging.config.dictConfig(
}
)
-env_file = env("ENV_FILE", default=None)
+ENV_FILE = env_file = env("ENV_FILE", default=None)
+"""
+Path to a .env file to load
+"""
if env_file:
logger.info("Loading specified env file at %s", env_file)
# we have an explicitely specified env file
@@ -85,6 +82,9 @@ else:
FUNKWHALE_PLUGINS_PATH = env(
"FUNKWHALE_PLUGINS_PATH", default="/srv/funkwhale/plugins/"
)
+"""
+Path to a directory containing Funkwhale plugins. These will be imported at runtime.
+"""
sys.path.append(FUNKWHALE_PLUGINS_PATH)
FUNKWHALE_HOSTNAME = None
@@ -99,7 +99,14 @@ if FUNKWHALE_HOSTNAME_PREFIX and FUNKWHALE_HOSTNAME_SUFFIX:
else:
try:
FUNKWHALE_HOSTNAME = env("FUNKWHALE_HOSTNAME")
+ """
+ Hostname of your Funkwhale pod, e.g ``mypod.audio``
+ """
+
FUNKWHALE_PROTOCOL = env("FUNKWHALE_PROTOCOL", default="https")
+ """
+ Protocol end users will use to access your pod, either ``http`` or ``https``.
+ """
except Exception:
FUNKWHALE_URL = env("FUNKWHALE_URL")
_parsed = urlsplit(FUNKWHALE_URL)
@@ -112,6 +119,16 @@ FUNKWHALE_URL = "{}://{}".format(FUNKWHALE_PROTOCOL, FUNKWHALE_HOSTNAME)
FUNKWHALE_SPA_HTML_ROOT = env(
"FUNKWHALE_SPA_HTML_ROOT", default=FUNKWHALE_URL + "/front/"
)
+"""
+URL or path to the Web Application files. Funkwhale needs access to it so that
+it can inject tags relevant to the given page (e.g page title, cover, etc.).
+
+If a URL is specified, the index.html file will be fetched through HTTP. If a path is provided,
+it will be accessed from disk.
+
+Use something like ``/srv/funkwhale/front/dist/`` if the web processes shows request errors related to this.
+"""
+
FUNKWHALE_SPA_HTML_CACHE_DURATION = env.int(
"FUNKWHALE_SPA_HTML_CACHE_DURATION", default=60 * 15
)
@@ -148,7 +165,16 @@ FEDERATION_SERVICE_ACTOR_USERNAME = env(
)
# How many pages to fetch when crawling outboxes and third-party collections
FEDERATION_COLLECTION_MAX_PAGES = env.int("FEDERATION_COLLECTION_MAX_PAGES", default=5)
+"""
+Number of existing pages of content to fetch when discovering/refreshing an actor or channel.
+
+More pages means more content will be loaded, but will require more resources.
+"""
+
ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=[]) + [FUNKWHALE_HOSTNAME]
+"""
+List of allowed hostnames for which the Funkwhale server will answer.
+"""
# APP CONFIGURATION
# ------------------------------------------------------------------------------
@@ -223,12 +249,18 @@ LOCAL_APPS = (
PLUGINS = [p for p in env.list("FUNKWHALE_PLUGINS", default=[]) if p]
+"""
+List of Funkwhale plugins to load.
+"""
if PLUGINS:
logger.info("Running with the following plugins enabled: %s", ", ".join(PLUGINS))
else:
logger.info("Running with no plugins")
ADDITIONAL_APPS = env.list("ADDITIONAL_APPS", default=[])
+"""
+List of Django apps to load in addition to Funkwhale plugins and apps.
+"""
INSTALLED_APPS = (
DJANGO_APPS
+ THIRD_PARTY_APPS
@@ -257,8 +289,11 @@ MIDDLEWARE = tuple(ADDITIONAL_MIDDLEWARES_BEFORE) + (
# DEBUG
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
-DEBUG = env.bool("DJANGO_DEBUG", False)
-
+DJANGO_DEBUG = DEBUG = env.bool("DJANGO_DEBUG", False)
+"""
+Whether to enable debugging info and pages. Never enable this on a production server,
+as it can leak very sensitive information.
+"""
# FIXTURE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
@@ -272,25 +307,70 @@ FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),)
DEFAULT_FROM_EMAIL = env(
"DEFAULT_FROM_EMAIL", default="Funkwhale ".format(FUNKWHALE_HOSTNAME)
)
+"""
+Name and email address used to send system emails.
+Default: ``Funkwhale ``
+
+.. note::
+
+ Both the forms ``Funkwhale `` and
+ ``noreply@yourdomain`` work.
+
+"""
EMAIL_SUBJECT_PREFIX = env("EMAIL_SUBJECT_PREFIX", default="[Funkwhale] ")
+"""
+Subject prefix for system emails.
+"""
SERVER_EMAIL = env("SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
EMAIL_CONFIG = env.email_url("EMAIL_CONFIG", default="consolemail://")
+"""
+SMTP configuration for sending emails. Possible values:
+- ``EMAIL_CONFIG=consolemail://``: output emails to console (the default)
+- ``EMAIL_CONFIG=dummymail://``: disable email sending completely
+
+On a production instance, you'll usually want to use an external SMTP server:
+
+- ``EMAIL_CONFIG=smtp://user@:password@youremail.host:25``
+- ``EMAIL_CONFIG=smtp+ssl://user@:password@youremail.host:465``
+- ``EMAIL_CONFIG=smtp+tls://user@:password@youremail.host:587``
+
+.. note::
+
+ If ``user`` or ``password`` contain special characters (eg.
+ ``noreply@youremail.host`` as ``user``), be sure to urlencode them, using
+ for example the command:
+ ``python3 -c 'import urllib.parse; print(urllib.parse.quote_plus("noreply@youremail.host"))'``
+ (returns ``noreply%40youremail.host``)
+
+"""
vars().update(EMAIL_CONFIG)
# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
+DATABASE_URL = env.db("DATABASE_URL")
+"""
+URL to connect to the PostgreSQL database. Examples:
+
+- ``postgresql://funkwhale@:5432/funkwhale``
+- ``postgresql://:@:/``
+- ``postgresql://funkwhale:passw0rd@localhost:5432/funkwhale_database``
+"""
DATABASES = {
# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
- "default": env.db("DATABASE_URL")
+ "default": DATABASE_URL
}
DATABASES["default"]["ATOMIC_REQUESTS"] = True
-DATABASES["default"]["CONN_MAX_AGE"] = env("DB_CONN_MAX_AGE", default=60 * 5)
-
+DB_CONN_MAX_AGE = DATABASES["default"]["CONN_MAX_AGE"] = env(
+ "DB_CONN_MAX_AGE", default=60 * 5
+)
+"""
+Max time, in seconds, before database connections are closed.
+"""
MIGRATION_MODULES = {
# see https://github.com/jazzband/django-oauth-toolkit/issues/634
# swappable models are badly designed in oauth2_provider
@@ -299,13 +379,6 @@ MIGRATION_MODULES = {
"sites": "funkwhale_api.contrib.sites.migrations",
}
-#
-# DATABASES = {
-# 'default': {
-# 'ENGINE': 'django.db.backends.sqlite3',
-# 'NAME': 'db.sqlite3',
-# }
-# }
# GENERAL CONFIGURATION
# ------------------------------------------------------------------------------
# Local time zone for this installation. Choices can be found here:
@@ -370,31 +443,79 @@ CRISPY_TEMPLATE_PACK = "bootstrap3"
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = env("STATIC_ROOT", default=str(ROOT_DIR("staticfiles")))
-
+"""
+Path were static files should be collected.
+"""
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = env("STATIC_URL", default=FUNKWHALE_URL + "/staticfiles/")
DEFAULT_FILE_STORAGE = "funkwhale_api.common.storage.ASCIIFileSystemStorage"
PROXY_MEDIA = env.bool("PROXY_MEDIA", default=True)
+"""
+Wether to proxy audio files through your reverse proxy. It's recommended to keep this on,
+as a way to enforce access control, however, if you're using S3 storage with :attr:`AWS_QUERYSTRING_AUTH`,
+it's safe to disable it.
+"""
AWS_DEFAULT_ACL = None
AWS_QUERYSTRING_AUTH = env.bool("AWS_QUERYSTRING_AUTH", default=not PROXY_MEDIA)
+"""
+Whether to include signatures in S3 urls, as a way to enforce access-control.
+
+Defaults to the inverse of :attr:`PROXY_MEDIA`.
+"""
+
AWS_S3_MAX_MEMORY_SIZE = env.int(
"AWS_S3_MAX_MEMORY_SIZE", default=1000 * 1000 * 1000 * 20
)
+
AWS_QUERYSTRING_EXPIRE = env.int("AWS_QUERYSTRING_EXPIRE", default=3600)
+"""
+Expiration delay, in seconds, of signatures generated when :attr:`AWS_QUERYSTRING_AUTH` is enabled.
+"""
+
AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID", default=None)
+"""
+Access-key ID for your S3 storage.
+"""
if AWS_ACCESS_KEY_ID:
AWS_ACCESS_KEY_ID = AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")
+ """
+ Secret access key for your S3 storage.
+ """
AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")
+ """
+ Bucket name of your S3 storage.
+ """
AWS_S3_CUSTOM_DOMAIN = env("AWS_S3_CUSTOM_DOMAIN", default=None)
+ """
+ Custom domain to use for your S3 storage.
+ """
AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", default=None)
+ """
+ If you use a S3-compatible storage such as minio, set the following variable to
+ the full URL to the storage server. Example:
+
+ - ``https://minio.mydomain.com``
+ - ``https://s3.wasabisys.com``
+ """
AWS_S3_REGION_NAME = env("AWS_S3_REGION_NAME", default=None)
+ """If you are using Amazon S3 to serve media directly, you will need to specify your region
+ name in order to access files. Example:
+
+ - ``eu-west-2``
+ """
+
AWS_S3_SIGNATURE_VERSION = "s3v4"
AWS_LOCATION = env("AWS_LOCATION", default="")
+ """
+ An optional bucket subdirectory were you want to store the files. This is especially useful
+ if you plan to use share the bucket with other services
+ """
DEFAULT_FILE_STORAGE = "funkwhale_api.common.storage.ASCIIS3Boto3Storage"
+
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = (str(APPS_DIR.path("static")),)
@@ -408,14 +529,25 @@ STATICFILES_FINDERS = (
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = env("MEDIA_ROOT", default=str(APPS_DIR("media")))
-
+"""
+Where media files (such as album covers or audio tracks) should be stored
+on your system? (Ensure this directory actually exists)
+"""
# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = env("MEDIA_URL", default=FUNKWHALE_URL + "/media/")
+"""
+URL where media files are served. The default value should work fine on most
+configurations, but could can tweak this if you are hosting media files on a separate
+domain, or if you host Funkwhale on a non-standard port.
+"""
FILE_UPLOAD_PERMISSIONS = 0o644
ATTACHMENTS_UNATTACHED_PRUNE_DELAY = env.int(
"ATTACHMENTS_UNATTACHED_PRUNE_DELAY", default=3600 * 24
)
+"""
+Delay in seconds before uploaded but unattached attachements are pruned from the system.
+"""
# URL Configuration
# ------------------------------------------------------------------------------
@@ -441,6 +573,14 @@ ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION_ENFORCE = env.bool(
"ACCOUNT_EMAIL_VERIFICATION_ENFORCE", default=False
)
+"""
+Determine wether users need to verify their email address before using the service. Enabling this can be useful
+to reduce spam or bots accounts, however, you'll need to configure a mail server so that your users can receive the
+verification emails, using :attr:`EMAIL_CONFIG`.
+
+Note that regardless of the setting value, superusers created through the command line will never require verification.
+
+"""
ACCOUNT_EMAIL_VERIFICATION = (
"mandatory" if ACCOUNT_EMAIL_VERIFICATION_ENFORCE else "optional"
)
@@ -472,6 +612,10 @@ OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "users.RefreshToken"
# LDAP AUTHENTICATION CONFIGURATION
# ------------------------------------------------------------------------------
AUTH_LDAP_ENABLED = env.bool("LDAP_ENABLED", default=False)
+"""
+Wether to enable LDAP authentication. See :doc:`/installation/ldap` for more information.
+"""
+
if AUTH_LDAP_ENABLED:
# Import the LDAP modules here; this way, we don't need the dependency unless someone
@@ -541,8 +685,22 @@ if AUTH_LDAP_ENABLED:
AUTOSLUG_SLUGIFY_FUNCTION = "slugify.slugify"
CACHE_DEFAULT = "redis://127.0.0.1:6379/0"
+CACHE_URL = env.cache_url("CACHE_URL", default=CACHE_DEFAULT)
+"""
+URL to your redis server. Examples:
+
+- `redis://:/`
+- `redis://127.0.0.1:6379/0`
+- `redis://:password@localhost:6379/0` for password auth (the extra semicolon is important)
+- `redis:///run/redis/redis.sock?db=0` over unix sockets
+
+.. note::
+
+ If you want to use Redis over unix sockets, you'll also need to update :attr:`CELERY_BROKER_URL`
+
+"""
CACHES = {
- "default": env.cache_url("CACHE_URL", default=CACHE_DEFAULT),
+ "default": CACHE_URL,
"local": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "local-cache",
@@ -567,7 +725,7 @@ CACHEOPS_ENABLED = bool(CACHEOPS_DURATION)
if CACHEOPS_ENABLED:
INSTALLED_APPS += ("cacheops",)
- CACHEOPS_REDIS = env("CACHE_URL", default=CACHE_DEFAULT)
+ CACHEOPS_REDIS = CACHE_URL
CACHEOPS_PREFIX = lambda _: "cacheops" # noqa
CACHEOPS_DEFAULTS = {"timeout": CACHEOPS_DURATION}
CACHEOPS = {
@@ -581,6 +739,15 @@ INSTALLED_APPS += ("funkwhale_api.taskapp.celery.CeleryConfig",)
CELERY_BROKER_URL = env(
"CELERY_BROKER_URL", default=env("CACHE_URL", default=CACHE_DEFAULT)
)
+"""
+URL to celery's task broker. Defaults to :attr:`CACHE_URL`, so you shouldn't have to tweak this, unless you want
+to use a different one, or use Redis sockets to connect.
+
+Exemple:
+
+- `redis://127.0.0.1:6379/0`
+- `redis+socket:///run/redis/redis.sock?virtual_host=0`
+"""
# END CELERY
# Location of root django.contrib.admin URL, use {% url 'admin:index' %}
@@ -667,7 +834,11 @@ AUTH_PASSWORD_VALIDATORS = [
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]
-if env.bool("DISABLE_PASSWORD_VALIDATORS", default=False):
+DISABLE_PASSWORD_VALIDATORS = env.bool("DISABLE_PASSWORD_VALIDATORS", default=False)
+"""
+Wether to disable password validators (length, common words, similarity with username…) used during regitration.
+"""
+if DISABLE_PASSWORD_VALIDATORS:
AUTH_PASSWORD_VALIDATORS = []
ACCOUNT_ADAPTER = "funkwhale_api.users.adapters.FunkwhaleAccountAdapter"
CORS_ORIGIN_ALLOW_ALL = True
@@ -705,6 +876,11 @@ REST_FRAMEWORK = {
"NUM_PROXIES": env.int("NUM_PROXIES", default=1),
}
THROTTLING_ENABLED = env.bool("THROTTLING_ENABLED", default=True)
+"""
+Wether to enable throttling (also known as rate-limiting). Leaving this enabled is recommended
+especially on public pods, to improve the quality of service.
+"""
+
if THROTTLING_ENABLED:
REST_FRAMEWORK["DEFAULT_THROTTLE_CLASSES"] = env.list(
"THROTTLE_CLASSES",
@@ -853,7 +1029,16 @@ THROTTLING_RATES = {
"description": "Fetch remote objects",
},
}
+THROTTLING_RATES = THROTTLING_RATES
+"""
+Throttling rates for specific endpoints and features of the app. You can tweak this if you are
+encountering to severe rate limiting issues or, on the contrary, if you want to reduce
+the consumption on some endpoints.
+Example:
+
+- ``signup=5/d,password-reset=2/d,anonymous-reports=5/d``
+"""
BROWSABLE_API_ENABLED = env.bool("BROWSABLE_API_ENABLED", default=False)
if BROWSABLE_API_ENABLED:
@@ -874,24 +1059,48 @@ USE_X_FORWARDED_PORT = True
# Wether we should use Apache, Nginx (or other) headers when serving audio files
# Default to Nginx
REVERSE_PROXY_TYPE = env("REVERSE_PROXY_TYPE", default="nginx")
+"""
+Depending on the reverse proxy used in front of your funkwhale instance,
+the API will use different kind of headers to serve audio files
+
+Allowed values: ``nginx``, ``apache2``
+"""
assert REVERSE_PROXY_TYPE in ["apache2", "nginx"], "Unsupported REVERSE_PROXY_TYPE"
-# Which path will be used to process the internal redirection
-# **DO NOT** put a slash at the end
PROTECT_FILES_PATH = env("PROTECT_FILES_PATH", default="/_protected")
+"""
+Which path will be used to process the internal redirection to the reverse proxy
+**DO NOT** put a slash at the end.
+You shouldn't have to tweak this.
+"""
-# use this setting to tweak for how long you want to cache
-# musicbrainz results. (value is in seconds)
MUSICBRAINZ_CACHE_DURATION = env.int("MUSICBRAINZ_CACHE_DURATION", default=300)
-
-# Use this setting to change the musicbrainz hostname, for instance to
-# use a mirror. The hostname can also contain a port number (so, e.g.,
-# "localhost:5000" is a valid name to set).
+"""
+How long to cache MusicBrainz results, in seconds
+"""
MUSICBRAINZ_HOSTNAME = env("MUSICBRAINZ_HOSTNAME", default="musicbrainz.org")
+"""
+Use this setting to change the musicbrainz hostname, for instance to
+use a mirror. The hostname can also contain a port number.
+Example:
+
+- ``mymusicbrainz.mirror``
+- ``localhost:5000``
+
+"""
# Custom Admin URL, use {% url 'admin:index' %}
ADMIN_URL = env("DJANGO_ADMIN_URL", default="^api/admin/")
+"""
+Path to the Django admin area.
+
+Exemples:
+
+- `^api/admin/`
+- `^api/mycustompath/`
+
+"""
CSRF_USE_SESSIONS = True
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
@@ -899,6 +1108,7 @@ SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# XXX: deprecated, see #186
PLAYLISTS_MAX_TRACKS = env.int("PLAYLISTS_MAX_TRACKS", default=250)
+
ACCOUNT_USERNAME_BLACKLIST = [
"funkwhale",
"library",
@@ -923,24 +1133,71 @@ ACCOUNT_USERNAME_BLACKLIST = [
"shared_inbox",
"actor",
] + env.list("ACCOUNT_USERNAME_BLACKLIST", default=[])
-
+"""
+List of usernames that will be unavailable during registration.
+"""
EXTERNAL_REQUESTS_VERIFY_SSL = env.bool("EXTERNAL_REQUESTS_VERIFY_SSL", default=True)
+"""
+Wether to enforce HTTPS certificates verification when doing outgoing HTTP requests (typically with federation).
+Disabling this is not recommended.
+"""
EXTERNAL_REQUESTS_TIMEOUT = env.int("EXTERNAL_REQUESTS_TIMEOUT", default=10)
+"""
+Default timeout for external requests.
+"""
# XXX: deprecated, see #186
API_AUTHENTICATION_REQUIRED = env.bool("API_AUTHENTICATION_REQUIRED", True)
MUSIC_DIRECTORY_PATH = env("MUSIC_DIRECTORY_PATH", default=None)
-# on Docker setup, the music directory may not match the host path,
-# and we need to know it for it to serve stuff properly
+"""
+The path on your server where Funkwhale can import files using :ref:`in-place import
+`. It must be readable by the webserver and Funkwhale
+api and worker processes.
+
+On docker installations, we recommend you use the default of ``/music``
+for this value. For non-docker installation, you can use any absolute path.
+``/srv/funkwhale/data/music`` is a safe choice if you don't know what to use.
+
+.. note:: This path should not include any trailing slash
+
+.. warning::
+
+ You need to adapt your :ref:`reverse-proxy configuration` to
+ serve the directory pointed by ``MUSIC_DIRECTORY_PATH`` on
+ ``/_protected/music`` URL.
+
+"""
MUSIC_DIRECTORY_SERVE_PATH = env(
"MUSIC_DIRECTORY_SERVE_PATH", default=MUSIC_DIRECTORY_PATH
)
+"""
+Default: :attr:`MUSIC_DIRECTORY_PATH`
+
+When using Docker, the value of :attr:`MUSIC_DIRECTORY_PATH` in your containers
+may differ from the real path on your host. Assuming you have the following directive
+in your :file:`docker-compose.yml` file::
+
+ volumes:
+ - /srv/funkwhale/data/music:/music:ro
+
+Then, the value of :attr:`MUSIC_DIRECTORY_SERVE_PATH` should be
+``/srv/funkwhale/data/music``. This must be readable by the webserver.
+
+On non-docker setup, you don't need to configure this setting.
+
+.. note:: This path should not include any trailing slash
+
+"""
# When this is set to default=True, we need to reenable migration music/0042
# to ensure data is populated correctly on existing pods
MUSIC_USE_DENORMALIZATION = env.bool("MUSIC_USE_DENORMALIZATION", default=False)
+
USERS_INVITATION_EXPIRATION_DAYS = env.int(
"USERS_INVITATION_EXPIRATION_DAYS", default=14
)
+"""
+Expiration delay in days, for user invitations.
+"""
VERSATILEIMAGEFIELD_RENDITION_KEY_SETS = {
"square": [
@@ -964,40 +1221,84 @@ ACTOR_KEY_ROTATION_DELAY = env.int("ACTOR_KEY_ROTATION_DELAY", default=3600 * 48
SUBSONIC_DEFAULT_TRANSCODING_FORMAT = (
env("SUBSONIC_DEFAULT_TRANSCODING_FORMAT", default="mp3") or None
)
-
+"""
+Default format for transcoding when using Subsonic API.
+"""
# extra tags will be ignored
TAGS_MAX_BY_OBJ = env.int("TAGS_MAX_BY_OBJ", default=30)
+"""
+Maximum number of tags that can be associated with an object. Extra tags will be ignored.
+"""
FEDERATION_OBJECT_FETCH_DELAY = env.int(
"FEDERATION_OBJECT_FETCH_DELAY", default=60 * 24 * 3
)
-
+"""
+Number of minutes before a remote object will be automatically refetched when accessed in the UI.
+"""
MODERATION_EMAIL_NOTIFICATIONS_ENABLED = env.bool(
"MODERATION_EMAIL_NOTIFICATIONS_ENABLED", default=True
)
+"""
+Whether to enable email notifications to moderators and pods admins.
+"""
FEDERATION_AUTHENTIFY_FETCHES = True
FEDERATION_SYNCHRONOUS_FETCH = env.bool("FEDERATION_SYNCHRONOUS_FETCH", default=True)
FEDERATION_DUPLICATE_FETCH_DELAY = env.int(
"FEDERATION_DUPLICATE_FETCH_DELAY", default=60 * 50
)
-# Delay in days after signup before we show the "support us" messages
+"""
+Delay, in seconds, between two manual fetch of the same remote object.
+"""
INSTANCE_SUPPORT_MESSAGE_DELAY = env.int("INSTANCE_SUPPORT_MESSAGE_DELAY", default=15)
+"""
+Delay in days after signup before we show the "support your pod" message
+"""
FUNKWHALE_SUPPORT_MESSAGE_DELAY = env.int("FUNKWHALE_SUPPORT_MESSAGE_DELAY", default=15)
+"""
+Delay in days after signup before we show the "support Funkwhale" message
+"""
# XXX Stable release: remove
USE_FULL_TEXT_SEARCH = env.bool("USE_FULL_TEXT_SEARCH", default=True)
MIN_DELAY_BETWEEN_DOWNLOADS_COUNT = env.int(
"MIN_DELAY_BETWEEN_DOWNLOADS_COUNT", default=60 * 60 * 6
)
+"""
+Minimum required period, in seconds, for two downloads of the same track by the same IP
+or user to be recorded in statistics.
+"""
MARKDOWN_EXTENSIONS = env.list("MARKDOWN_EXTENSIONS", default=["nl2br", "extra"])
+"""
+List of markdown extensions to enable.
+Cf ``_
+"""
LINKIFIER_SUPPORTED_TLDS = ["audio"] + env.list("LINKINFIER_SUPPORTED_TLDS", default=[])
+"""
+Additional TLDs to support with our markdown linkifier.
+"""
EXTERNAL_MEDIA_PROXY_ENABLED = env.bool("EXTERNAL_MEDIA_PROXY_ENABLED", default=True)
-
-# By default, only people who subscribe to a podcast RSS will have access to it
-# switch to "instance" or "everyone" to change that
+"""
+Wether to proxy attachment files hosted on third party pods and and servers. Keeping
+this to true is recommended, to reduce leaking browsing information of your users, and
+reduce the bandwidth used on remote pods.
+"""
PODCASTS_THIRD_PARTY_VISIBILITY = env("PODCASTS_THIRD_PARTY_VISIBILITY", default="me")
+"""
+By default, only people who subscribe to a podcast RSS will have access to their episodes.
+switch to "instance" or "everyone" to change that.
+
+Changing it only affect new podcasts.
+"""
PODCASTS_RSS_FEED_REFRESH_DELAY = env.int(
"PODCASTS_RSS_FEED_REFRESH_DELAY", default=60 * 60 * 24
)
+"""
+Delay in seconds between to fetch of RSS feeds. Reducing this mean you'll receive new episodes faster,
+but will require more resources.
+"""
# maximum items loaded through XML feed
PODCASTS_RSS_FEED_MAX_ITEMS = env.int("PODCASTS_RSS_FEED_MAX_ITEMS", default=250)
+"""
+Maximum number of RSS items to load in each podcast feed.
+"""
diff --git a/docs/Dockerfile b/docs/Dockerfile
index 1de9a3ede..0d868d5b2 100644
--- a/docs/Dockerfile
+++ b/docs/Dockerfile
@@ -1,5 +1,5 @@
FROM python:3.6
RUN apt-get update && apt-get install -y graphviz
-RUN pip install sphinx livereload sphinx_rtd_theme
+RUN pip install sphinx livereload sphinx_rtd_theme django-environ django
WORKDIR /app/docs
diff --git a/docs/admin/configuration.rst b/docs/admin/configuration.rst
index b3f206378..c2bbd5f9f 100644
--- a/docs/admin/configuration.rst
+++ b/docs/admin/configuration.rst
@@ -1,13 +1,18 @@
Instance configuration
======================
-General configuration is achieved using two type of settings.
+General configuration is achieved using two type of settings:
+:ref:`environment variables ` and
+:ref:`instance settings `.
+
+.. _environment-variables:
Environment variables
---------------------
Those are located in your ``.env`` file, which you should have created
-during installation.
+during installation. A full list of available variables can be seen
+:ref:`below `.
Options from this file are heavily commented, and usually target lower level
and technical aspects of your instance, such as database credentials.
@@ -33,7 +38,7 @@ and technical aspects of your instance, such as database credentials.
Instance settings
-----------------
-Those settings are stored in database and do not require a restart of your
+These settings are stored in the database and do not require a restart of your
instance after modification. They typically relate to higher level configuration,
such your instance description, signup policy and so on.
@@ -42,7 +47,7 @@ you have the required permissions. The URL is ``/manage/settings``, and
you will also find a link to this page in the sidebar.
If you plan to use acoustid and external imports
-(e.g. with the youtube backends), you should edit the corresponding
+(e.g. with the YouTube backends), you should edit the corresponding
settings in this interface.
.. note::
@@ -58,113 +63,114 @@ settings in this interface.
Configuration reference
-----------------------
-.. _setting-ACCOUNT_EMAIL_VERIFICATION_ENFORCE:
+Pod
+^^^
-``ACCOUNT_EMAIL_VERIFICATION_ENFORCE``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. autodata:: config.settings.common.FUNKWHALE_HOSTNAME
+ :annotation:
+.. autodata:: config.settings.common.FUNKWHALE_PROTOCOL
-Determine wether users need to verify their email address before using the service. Enabling this can be useful
-to reduce spam or bots accounts, however, you'll need to configure a SMTP server so that your users can receive the
-verification emails.
+Database and redis
+^^^^^^^^^^^^^^^^^^
-Note that regardless of the setting value, superusers created through the command line will never require verification.
+.. autodata:: config.settings.common.DATABASE_URL
+ :annotation:
+.. autodata:: config.settings.common.DB_CONN_MAX_AGE
+.. autodata:: config.settings.common.CACHE_URL
+ :annotation:
+.. autodata:: config.settings.common.CELERY_BROKER_URL
+ :annotation:
-Default: ``false``
+Accounts and registration
+^^^^^^^^^^^^^^^^^^^^^^^^^
-.. _setting-EMAIL_CONFIG:
+.. autodata:: config.settings.common.ACCOUNT_EMAIL_VERIFICATION_ENFORCE
+ :annotation:
+.. autodata:: config.settings.common.USERS_INVITATION_EXPIRATION_DAYS
+ :annotation:
+.. autodata:: config.settings.common.DISABLE_PASSWORD_VALIDATORS
+ :annotation:
+.. autodata:: config.settings.common.ACCOUNT_USERNAME_BLACKLIST
+ :annotation:
+.. autodata:: config.settings.common.AUTH_LDAP_ENABLED
+ :annotation:
-``EMAIL_CONFIG``
-^^^^^^^^^^^^^^^^
+Media storage and serving
+^^^^^^^^^^^^^^^^^^^^^^^^^
-Determine how emails are sent.
+.. autodata:: config.settings.common.MEDIA_URL
+ :annotation: = https://mypod.audio/media/
+.. autodata:: config.settings.common.MEDIA_ROOT
+ :annotation: = /srv/funkwhale/data/media
+.. autodata:: config.settings.common.PROXY_MEDIA
+ :annotation: = true
+.. autodata:: config.settings.common.EXTERNAL_MEDIA_PROXY_ENABLED
+.. autodata:: config.settings.common.ATTACHMENTS_UNATTACHED_PRUNE_DELAY
+ :annotation: = true
+.. autodata:: config.settings.common.REVERSE_PROXY_TYPE
+.. autodata:: config.settings.common.PROTECT_FILES_PATH
-Default: ``consolemail://``
+Audio acquisition
+^^^^^^^^^^^^^^^^^
-Possible values:
+.. autodata:: config.settings.common.MUSIC_DIRECTORY_PATH
+.. autodata:: config.settings.common.MUSIC_DIRECTORY_SERVE_PATH
-- ``consolemail://``: Output sent emails to stdout
-- ``dummymail://``: Completely discard sent emails
-- ``smtp://user:password@youremail.host:25``: Send emails via SMTP via youremail.host on port 25, without encryption, authenticating as user "user" with password "password"
-- ``smtp+ssl://user:password@youremail.host:465``: Send emails via SMTP via youremail.host on port 465, using SSL encryption, authenticating as user "user" with password "password"
-- ``smtp+tls://user:password@youremail.host:587``: Send emails via SMTP via youremail.host on port 587, using TLS encryption, authenticating as user "user" with password "password"
+S3 Storage
+^^^^^^^^^^
-.. note::
+.. autodata:: config.settings.common.AWS_QUERYSTRING_AUTH
+.. autodata:: config.settings.common.AWS_QUERYSTRING_EXPIRE
+.. autodata:: config.settings.common.AWS_ACCESS_KEY_ID
+.. autodata:: config.settings.common.AWS_SECRET_ACCESS_KEY
+.. autodata:: config.settings.common.AWS_STORAGE_BUCKET_NAME
+.. autodata:: config.settings.common.AWS_S3_CUSTOM_DOMAIN
+.. autodata:: config.settings.common.AWS_S3_ENDPOINT_URL
+.. autodata:: config.settings.common.AWS_S3_REGION_NAME
+.. autodata:: config.settings.common.AWS_LOCATION
- If ``user`` or ``password`` contain special characters (eg.
- ``noreply@youremail.host`` as ``user``), be sure to urlencode them, using
- for example the command:
- ``python3 -c 'import urllib.parse; print(urllib.parse.quote_plus("noreply@youremail.host"))'``
- (returns ``noreply%40youremail.host``)
+API configuration
+^^^^^^^^^^^^^^^^^
+.. autodata:: config.settings.common.THROTTLING_ENABLED
+.. autodata:: config.settings.common.THROTTLING_RATES
+.. autodata:: config.settings.common.ADMIN_URL
+.. autodata:: config.settings.common.EXTERNAL_REQUESTS_VERIFY_SSL
+.. autodata:: config.settings.common.EXTERNAL_REQUESTS_TIMEOUT
-.. _setting-DEFAULT_FROM_EMAIL:
+Federation
+^^^^^^^^^^
-``DEFAULT_FROM_EMAIL``
-^^^^^^^^^^^^^^^^^^^^^^
+.. autodata:: config.settings.common.FEDERATION_OBJECT_FETCH_DELAY
+.. autodata:: config.settings.common.FEDERATION_DUPLICATE_FETCH_DELAY
-The email address to use to send email.
+Metadata
+^^^^^^^^
-Default: ``Funkwhale ``
+.. autodata:: config.settings.common.TAGS_MAX_BY_OBJ
+.. autodata:: config.settings.common.MUSICBRAINZ_HOSTNAME
+.. autodata:: config.settings.common.MUSICBRAINZ_CACHE_DURATION
-.. note::
+Channels and podcasts
+^^^^^^^^^^^^^^^^^^^^^
- Both the forms ``Funkwhale `` and
- ``noreply@yourdomain`` work.
+.. autodata:: config.settings.common.PODCASTS_RSS_FEED_REFRESH_DELAY
+.. autodata:: config.settings.common.PODCASTS_RSS_FEED_MAX_ITEMS
+.. autodata:: config.settings.common.PODCASTS_THIRD_PARTY_VISIBILITY
+Subsonic
+^^^^^^^^
-.. _setting-MUSIC_DIRECTORY_PATH:
+.. autodata:: config.settings.common.SUBSONIC_DEFAULT_TRANSCODING_FORMAT
-``MUSIC_DIRECTORY_PATH``
-^^^^^^^^^^^^^^^^^^^^^^^^
+Other settings
+^^^^^^^^^^^^^^
-Default: ``None``
-
-The path on your server where Funkwhale can import files using :ref:`in-place import
-`. It must be readable by the webserver and Funkwhale
-api and worker processes.
-
-On docker installations, we recommend you use the default of ``/music``
-for this value. For non-docker installation, you can use any absolute path.
-``/srv/funkwhale/data/music`` is a safe choice if you don't know what to use.
-
-.. note:: This path should not include any trailing slash
-
-.. warning::
-
- You need to adapt your :ref:`reverse-proxy configuration` to
- serve the directory pointed by ``MUSIC_DIRECTORY_PATH`` on
- ``/_protected/music`` URL.
-
-.. _setting-MUSIC_DIRECTORY_SERVE_PATH:
-
-``MUSIC_DIRECTORY_SERVE_PATH``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Default: :ref:`setting-MUSIC_DIRECTORY_PATH`
-
-When using Docker, the value of :ref:`setting-MUSIC_DIRECTORY_PATH` in your containers
-may differ from the real path on your host. Assuming you have the following directive
-in your :file:`docker-compose.yml` file::
-
- volumes:
- - /srv/funkwhale/data/music:/music:ro
-
-Then, the value of :ref:`setting-MUSIC_DIRECTORY_SERVE_PATH` should be
-``/srv/funkwhale/data/music``. This must be readable by the webserver.
-
-On non-docker setup, you don't need to configure this setting.
-
-.. note:: This path should not include any trailing slash
-
-.. _setting-REVERSE_PROXY_TYPE:
-
-``REVERSE_PROXY_TYPE``
-^^^^^^^^^^^^^^^^^^^^^^
-
-Default: ``nginx``
-
-The type of reverse-proxy behind which Funkwhale is served. Either ``apache2``
-or ``nginx``. This is only used if you are using in-place import.
+.. autodata:: config.settings.common.INSTANCE_SUPPORT_MESSAGE_DELAY
+.. autodata:: config.settings.common.FUNKWHALE_SUPPORT_MESSAGE_DELAY
+.. autodata:: config.settings.common.MIN_DELAY_BETWEEN_DOWNLOADS_COUNT
+.. autodata:: config.settings.common.MARKDOWN_EXTENSIONS
+.. autodata:: config.settings.common.LINKIFIER_SUPPORTED_TLDS
User permissions
----------------
@@ -194,7 +200,7 @@ to users at ``/api/admin/users/user/``.
Front-end settings
------------------
-We offer a basic mechanism to customize the behaviour and look and feel of Funkwhale's Web UI.
+We offer a basic mechanism to customize the behavior and look and feel of Funkwhale's Web UI.
To use any of the options below, you will need to create a custom JSON configuration file and serve it
on ``https://yourinstanceurl/settings.json``.
@@ -296,7 +302,7 @@ On nginx, add the following snippet to your vhost config::
alias /srv/funkwhale/custom;
}
-On apache, use the following one::
+On apache, use the following::
Alias /custom /srv/funkwhale/custom
diff --git a/docs/conf.py b/docs/conf.py
index 64fcfc8e0..ae278c5e2 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -26,6 +26,16 @@ sys.path.insert(0, os.path.abspath("../api"))
import funkwhale_api # NOQA
+FUNKWHALE_CONFIG = {
+ "FUNKWHALE_URL": "mypod.funkwhale",
+ "FUNKWHAL_PROTOCOL": "https",
+ "DATABASE_URL": "postgres://localhost:5432/db",
+ "AWS_ACCESS_KEY_ID": 'my_access_key',
+ "AWS_SECRET_ACCESS_KEY": 'my_secret_key',
+ "AWS_STORAGE_BUCKET_NAME": 'my_bucket',
+}
+for key, value in FUNKWHALE_CONFIG.items():
+ os.environ[key] = value
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@@ -35,8 +45,9 @@ import funkwhale_api # NOQA
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ["sphinx.ext.graphviz"]
-
+extensions = ["sphinx.ext.graphviz", "sphinx.ext.autodoc"]
+autodoc_mock_imports = ["celery", "django_auth_ldap", "ldap"]
+add_module_names = False
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
diff --git a/docs/serve.py b/docs/serve.py
index 28e5020e6..dfc12ebfc 100644
--- a/docs/serve.py
+++ b/docs/serve.py
@@ -6,5 +6,5 @@ call(["python", "-m", "sphinx", ".", "/tmp/_build"])
from livereload import Server, shell
server = Server()
-server.watch(".", shell("python -m sphinx . /tmp/_build"))
+server.watch("..", shell("python -m sphinx . /tmp/_build"))
server.serve(root="/tmp/_build/", liveport=35730, port=8001, host="0.0.0.0")