Make database, oauth, smtp server, mail verificaiton configurable in .env

This commit is contained in:
krek0 2026-05-02 14:18:02 +02:00
parent 3a73bb8887
commit 7fbc81b9e1
8 changed files with 109 additions and 31 deletions

View file

@ -14,3 +14,39 @@ ADMINS=admin:photos-admin@lists.crans.org
# Email address used as sender for server emails # Email address used as sender for server emails
SERVER_EMAIL=photos@crans.org SERVER_EMAIL=photos@crans.org
# Email verification: 'mandatory', 'optional', or 'none'
EMAIL_VERIFICATION=mandatory
# Mail server settings
SMTP_HOST=localhost
SMTP_PORT=25
#SMTP_USER=
#SMTP_PASSWORD=
SMTP_USE_TLS=False
# OAuth2 settings
# Enable OAuth2 login
OAUTH_ENABLED=False
# Disable normal username/password login (requires OAUTH_ENABLED=True)
OAUTH_ONLY=False
# OAuth2 server base URL (e.g. auth.example.com)
#OAUTH_SERVER_URL=
# OAuth2 app credentials
#OAUTH_CLIENT_ID=
#OAUTH_CLIENT_SECRET=
# Button appearance on the login page
#OAUTH_BUTTON_TEXT=Login with OAuth
#OAUTH_BUTTON_IMAGE=
# Space-separated OAuth2 scopes
#OAUTH_SCOPE=openid profile email
# Database engine: 'sqlite' or 'postgres'
DB_ENGINE=sqlite
# PostgreSQL settings (only used when DB_ENGINE=postgres)
#DB_NAME=photo21
#DB_USER=photo21
#DB_PASSWORD=
#DB_HOST=localhost
#DB_PORT=5432

View file

@ -1,3 +1,5 @@
# This file is part of photo21 # This file is part of photo21
# Copyright (C) 2022 Amicale des élèves de l'ENS Paris-Saclay # Copyright (C) 2022 Amicale des élèves de l'ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
default_app_config = "allauth_oauth.apps.AllauthOAuthConfig"

View file

@ -7,15 +7,15 @@ from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
class NoteKfetAccount(ProviderAccount): class OAuthAccount(ProviderAccount):
def to_str(self): def to_str(self):
return self.account.extra_data.get("username") return self.account.extra_data.get("username")
class NoteKfetProvider(OAuth2Provider): class OAuthProvider(OAuth2Provider):
id = "notekfet" id = "oauth"
name = "Note Kfet" name = "OAuth"
account_class = NoteKfetAccount account_class = OAuthAccount
def extract_uid(self, data): def extract_uid(self, data):
return str(data["username"]) return str(data["username"])
@ -39,4 +39,4 @@ class NoteKfetProvider(OAuth2Provider):
return ret return ret
provider_classes = [NoteKfetProvider] provider_classes = [OAuthProvider]

View file

@ -4,6 +4,6 @@
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
from .provider import NoteKfetProvider from .provider import OAuthProvider
urlpatterns = default_urlpatterns(NoteKfetProvider) urlpatterns = default_urlpatterns(OAuthProvider)

View file

@ -10,11 +10,11 @@ from allauth.socialaccount.providers.oauth2.views import (
OAuth2LoginView, OAuth2LoginView,
) )
from .provider import NoteKfetProvider from .provider import OAuthProvider
class NoteKfetOAuth2Adapter(OAuth2Adapter): class OAuthAdapter(OAuth2Adapter):
provider_id = NoteKfetProvider.id provider_id = OAuthProvider.id
def complete_login(self, request, app, token, **kwargs): def complete_login(self, request, app, token, **kwargs):
headers = { headers = {
@ -31,7 +31,7 @@ class NoteKfetOAuth2Adapter(OAuth2Adapter):
@property @property
def domain(self): def domain(self):
return self.settings.get("DOMAIN", "note.crans.org") return self.settings.get("DOMAIN", "")
@property @property
def access_token_url(self): def access_token_url(self):
@ -46,5 +46,5 @@ class NoteKfetOAuth2Adapter(OAuth2Adapter):
return f"https://{self.domain}/api/me/" return f"https://{self.domain}/api/me/"
oauth2_login = OAuth2LoginView.adapter_view(NoteKfetOAuth2Adapter) oauth2_login = OAuth2LoginView.adapter_view(OAuthAdapter)
oauth2_callback = OAuth2CallbackView.adapter_view(NoteKfetOAuth2Adapter) oauth2_callback = OAuth2CallbackView.adapter_view(OAuthAdapter)

View file

@ -56,6 +56,15 @@ SECURE_HSTS_PRELOAD = True
# Application definition # Application definition
OAUTH_ENABLED = config("OAUTH_ENABLED", default=False, cast=bool)
OAUTH_ONLY = config("OAUTH_ONLY", default=False, cast=bool)
OAUTH_CLIENT_ID = config("OAUTH_CLIENT_ID", default="")
OAUTH_CLIENT_SECRET = config("OAUTH_CLIENT_SECRET", default="")
OAUTH_SERVER_URL = config("OAUTH_SERVER_URL", default="")
OAUTH_BUTTON_TEXT = config("OAUTH_BUTTON_TEXT", default="Login with OAuth")
OAUTH_BUTTON_IMAGE = config("OAUTH_BUTTON_IMAGE", default="")
OAUTH_SCOPE = config("OAUTH_SCOPE", default="openid profile email", cast=Csv(delimiter=" "))
INSTALLED_APPS = [ INSTALLED_APPS = [
"django.contrib.admin", "django.contrib.admin",
"django.contrib.admindocs", "django.contrib.admindocs",
@ -69,12 +78,14 @@ INSTALLED_APPS = [
"allauth", "allauth",
"allauth.account", "allauth.account",
"allauth.socialaccount", "allauth.socialaccount",
"allauth_note_kfet",
"crispy_forms", "crispy_forms",
"photologue", "photologue",
"photo21", "photo21",
] ]
if OAUTH_ENABLED:
INSTALLED_APPS += ["allauth_oauth"]
if DEBUG: if DEBUG:
INSTALLED_APPS += ["debug_toolbar",] # For debug and optimisations INSTALLED_APPS += ["debug_toolbar",] # For debug and optimisations
@ -125,6 +136,20 @@ WSGI_APPLICATION = "photo21.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
_db_engine = config("DB_ENGINE", default="sqlite").strip().lower()
if _db_engine == "postgres":
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": config("DB_NAME", default="photo21"),
"USER": config("DB_USER", default="photo21"),
"PASSWORD": config("DB_PASSWORD", default=""),
"HOST": config("DB_HOST", default="localhost"),
"PORT": config("DB_PORT", default="5432"),
}
}
elif _db_engine == "sqlite":
DATABASES = { DATABASES = {
"default": { "default": {
"ENGINE": "django.db.backends.sqlite3", "ENGINE": "django.db.backends.sqlite3",
@ -134,6 +159,8 @@ DATABASES = {
}, },
} }
} }
else:
raise ValueError(f"Unknown DB_ENGINE '{_db_engine}'. Must be 'sqlite' or 'postgres'.")
CACHES = { CACHES = {
"default": { "default": {
@ -221,6 +248,11 @@ if DEBUG:
SERVER_EMAIL = config("SERVER_EMAIL", default="photos@crans.org") SERVER_EMAIL = config("SERVER_EMAIL", default="photos@crans.org")
DEFAULT_FROM_EMAIL = f"Serveur photos <{SERVER_EMAIL}>" DEFAULT_FROM_EMAIL = f"Serveur photos <{SERVER_EMAIL}>"
EMAIL_SUBJECT_PREFIX = "[Serveur photos] " EMAIL_SUBJECT_PREFIX = "[Serveur photos] "
EMAIL_HOST = config("SMTP_HOST", default="localhost")
EMAIL_PORT = config("SMTP_PORT", default=25, cast=int)
EMAIL_HOST_USER = config("SMTP_USER", default="")
EMAIL_HOST_PASSWORD = config("SMTP_PASSWORD", default="")
EMAIL_USE_TLS = config("SMTP_USE_TLS", default=False, cast=bool)
# After login redirect user to transfer page # After login redirect user to transfer page
LOGIN_REDIRECT_URL = "/" LOGIN_REDIRECT_URL = "/"
@ -240,14 +272,21 @@ MESSAGE_TAGS = {
# Allauth configuration ## For the django =< 5.0 # Allauth configuration ## For the django =< 5.0
ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_EMAIL_REQUIRED = True
# ACCOUNT_SIGNUP_FIELDS = ['email*', 'username*', 'password1*', 'password2*'] ## For the django =< 5.0 # ACCOUNT_SIGNUP_FIELDS = ['email*', 'username*', 'password1*', 'password2*'] ## For the django =< 5.0
ACCOUNT_EMAIL_VERIFICATION = "mandatory" ACCOUNT_EMAIL_VERIFICATION = config("EMAIL_VERIFICATION", default="mandatory")
ACCOUNT_AUTHENTICATION_METHOD = "username_email" ACCOUNT_AUTHENTICATION_METHOD = "username_email"
# ACCOUNT_LOGIN_METHODS = {'username', 'email'} # ACCOUNT_LOGIN_METHODS = {'username', 'email'}
ACCOUNT_FORMS = {"signup": "photo21.forms.CustomSignupForm"} ACCOUNT_FORMS = {"signup": "photo21.forms.CustomSignupForm"}
if OAUTH_ENABLED:
SOCIALACCOUNT_ONLY = OAUTH_ONLY
SOCIALACCOUNT_PROVIDERS = { SOCIALACCOUNT_PROVIDERS = {
"notekfet": { "oauth": {
# Fetch user profile "SCOPE": OAUTH_SCOPE,
"SCOPE": ["1_1"], "DOMAIN": OAUTH_SERVER_URL,
"APP": {
"client_id": OAUTH_CLIENT_ID,
"secret": OAUTH_CLIENT_SECRET,
},
}, },
} }

View file

@ -7,3 +7,4 @@ Pillow>=6.0.0
django-debug-toolbar>=3.2.0 django-debug-toolbar>=3.2.0
python-decouple>=3.6 python-decouple>=3.6
whitenoise>=6.0 whitenoise>=6.0
psycopg2>=2.9

View file

@ -27,7 +27,7 @@ deps =
pep8-naming pep8-naming
pyflakes pyflakes
commands = commands =
flake8 allauth_note_kfet photo21 photologue flake8 allauth_oauth photo21 photologue
[flake8] [flake8]
ignore = W503, I100, I101 ignore = W503, I100, I101