DJOK_USER_TYPE
This commit is contained in:
parent
45f846d679
commit
2331e605a9
36
README.md
36
README.md
@ -21,6 +21,9 @@ If you are using this library as a baseline, there are a few steps you'll need t
|
|||||||
2. **Recommended:** run `uv run pre-commit install`
|
2. **Recommended:** run `uv run pre-commit install`
|
||||||
3. Read through the various sections below to familiarize yourself with the setup.
|
3. Read through the various sections below to familiarize yourself with the setup.
|
||||||
A few of the libraries may require additional setup, documented under the **You:** steps below.
|
A few of the libraries may require additional setup, documented under the **You:** steps below.
|
||||||
|
4. Replace this README & the LICENSE file with those appropriate to your project.
|
||||||
|
(**Caution**: Since this repository is licensed CC-0, failure to do so would mean licensing your code in the same way, likely not what you want.)
|
||||||
|
5. Before starting, you will need to choose which kind of user account you want. See `DJOK_USER_TYPE` below.
|
||||||
|
|
||||||
## File System Layout
|
## File System Layout
|
||||||
|
|
||||||
@ -121,3 +124,36 @@ Augment's django's built in `auth` with commonly-needed views for signup, email
|
|||||||
- `/accounts/signup`
|
- `/accounts/signup`
|
||||||
- `/accounts/login/code`
|
- `/accounts/login/code`
|
||||||
- `/accounts/password/reset`
|
- `/accounts/password/reset`
|
||||||
|
|
||||||
|
## DJOK_USER_TYPE
|
||||||
|
|
||||||
|
Should be set to either:
|
||||||
|
|
||||||
|
- `username` - Standard username/password login w/ optional email.
|
||||||
|
- `email` - Standard email/password login, username is set to email.
|
||||||
|
Comes with allauth-powered token-based login as well.
|
||||||
|
|
||||||
|
This must be set **before** running initial DB migrations.
|
||||||
|
|
||||||
|
Once set, you can run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
just dj makemigrations accounts
|
||||||
|
just dj migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
Changing once the application is live will require careful planning and custom data migration.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Adding New Types:
|
||||||
|
|
||||||
|
rm db.sqlite3
|
||||||
|
rm -rf apps/accounts/migrations/
|
||||||
|
|
||||||
|
just createsuperuser
|
||||||
|
# visit https://localhost:8000/djadmin/ & login
|
||||||
|
# visit https://localhost:8000/accounts/logout/
|
||||||
|
# visit https://localhost:8000/accounts/signup/
|
||||||
|
# visit https://localhost:8000/accounts/logout/
|
||||||
|
# visit https://localhost:8000/accounts/login/
|
||||||
|
-->
|
||||||
|
0
apps/__init__.py
Normal file
0
apps/__init__.py
Normal file
0
apps/accounts/__init__.py
Normal file
0
apps/accounts/__init__.py
Normal file
10
apps/accounts/admin.py
Normal file
10
apps/accounts/admin.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserAdmin(BaseUserAdmin):
|
||||||
|
list_display = ["is_active", "username", "full_name", "is_staff", "is_superuser"]
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(User, UserAdmin)
|
79
apps/accounts/models.py
Normal file
79
apps/accounts/models.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.models import (
|
||||||
|
AbstractBaseUser,
|
||||||
|
PermissionsMixin,
|
||||||
|
UnicodeUsernameValidator,
|
||||||
|
UserManager,
|
||||||
|
)
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
USERNAME_REQUIRED = settings.DJOK_USER_TYPE == "username"
|
||||||
|
EMAIL_REQUIRED = settings.DJOK_USER_TYPE == "email"
|
||||||
|
if not (USERNAME_REQUIRED or EMAIL_REQUIRED):
|
||||||
|
raise ValueError("Must set DJOK_USER_TYPE")
|
||||||
|
|
||||||
|
|
||||||
|
class OkUserManager(UserManager):
|
||||||
|
def create_superuser(self, **kwargs):
|
||||||
|
if "username" not in kwargs:
|
||||||
|
kwargs["username"] = kwargs["email"]
|
||||||
|
super().create_superuser(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class User(AbstractBaseUser, PermissionsMixin):
|
||||||
|
"""
|
||||||
|
A modification of the built-in Django user that:
|
||||||
|
- switches first_name & last_name for username & full_name
|
||||||
|
- keeps other admin-compliant options
|
||||||
|
"""
|
||||||
|
|
||||||
|
username_validator = UnicodeUsernameValidator()
|
||||||
|
|
||||||
|
email = models.EmailField(_("email address"), unique=EMAIL_REQUIRED, default="")
|
||||||
|
username = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
unique=True,
|
||||||
|
validators=[username_validator] if USERNAME_REQUIRED else [],
|
||||||
|
default="",
|
||||||
|
)
|
||||||
|
full_name = models.CharField(_("full name"), max_length=150, blank=True)
|
||||||
|
is_staff = models.BooleanField(
|
||||||
|
_("staff status"),
|
||||||
|
default=False,
|
||||||
|
help_text=_("Designates whether the user can log into this admin site."),
|
||||||
|
)
|
||||||
|
is_active = models.BooleanField(
|
||||||
|
_("active"),
|
||||||
|
default=True,
|
||||||
|
help_text=_(
|
||||||
|
"Designates whether this user should be treated as active. "
|
||||||
|
"Unselect this instead of deleting accounts."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
|
||||||
|
|
||||||
|
objects = OkUserManager()
|
||||||
|
|
||||||
|
EMAIL_FIELD = "email"
|
||||||
|
USERNAME_FIELD = "username" if USERNAME_REQUIRED else "email"
|
||||||
|
REQUIRED_FIELDS = []
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("user")
|
||||||
|
verbose_name_plural = _("users")
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
self.email = self.__class__.objects.normalize_email(self.email)
|
||||||
|
|
||||||
|
def get_short_name(self):
|
||||||
|
return self.username
|
||||||
|
|
||||||
|
def get_full_name(self):
|
||||||
|
return self.full_name
|
||||||
|
|
||||||
|
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||||
|
send_mail(subject, message, from_email, [self.email], **kwargs)
|
@ -67,6 +67,7 @@ INSTALLED_APPS = [
|
|||||||
"allauth.account",
|
"allauth.account",
|
||||||
"django_structlog",
|
"django_structlog",
|
||||||
"django_typer",
|
"django_typer",
|
||||||
|
"apps.accounts",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@ -116,6 +117,8 @@ USE_TZ = True
|
|||||||
|
|
||||||
# Authentication -----
|
# Authentication -----
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = "accounts.User"
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
"allauth.account.auth_backends.AuthenticationBackend",
|
"allauth.account.auth_backends.AuthenticationBackend",
|
||||||
@ -136,21 +139,18 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
DJOK_AUTH_MODE = "username"
|
# DJOK_USER_TYPE is a setting we introduce to pick between
|
||||||
# DJOK_AUTH_MODE is a setting we introduce to pick between
|
|
||||||
# a few common auth patterns.
|
# a few common auth patterns.
|
||||||
#
|
#
|
||||||
# Things other than 'username' currently experimental.
|
# It is also used in accounts/models.py.
|
||||||
#
|
#
|
||||||
# 'username'
|
# WARNING: Changing this setting after initial setup can have
|
||||||
# A username-based email
|
# data-loss consequences.
|
||||||
#
|
|
||||||
# 'email'
|
|
||||||
# This configures django-allauth with reasonably secure defaults
|
|
||||||
# for an email-based account.
|
|
||||||
#
|
|
||||||
# ''
|
|
||||||
#
|
#
|
||||||
|
# See documentation for explanation of options.
|
||||||
|
DJOK_USER_TYPE = "email"
|
||||||
|
|
||||||
|
|
||||||
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
|
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
|
||||||
ACCOUNT_PRESERVE_USERNAME_CASING = False
|
ACCOUNT_PRESERVE_USERNAME_CASING = False
|
||||||
ACCOUNT_LOGIN_BY_CODE_ENABLED = True
|
ACCOUNT_LOGIN_BY_CODE_ENABLED = True
|
||||||
@ -162,7 +162,7 @@ ACCOUNT_USERNAME_BLACKLIST = ["admin"]
|
|||||||
# ACCOUNT_LOGIN_BY_CODE_REQUIRED = False
|
# ACCOUNT_LOGIN_BY_CODE_REQUIRED = False
|
||||||
# ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
|
# ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
|
||||||
|
|
||||||
if DJOK_AUTH_MODE == "email":
|
if DJOK_USER_TYPE == "email":
|
||||||
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||||
ACCOUNT_LOGIN_METHODS = {"email"}
|
ACCOUNT_LOGIN_METHODS = {"email"}
|
||||||
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
|
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
|
||||||
|
Loading…
Reference in New Issue
Block a user