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`
|
||||
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.
|
||||
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
|
||||
|
||||
@ -121,3 +124,36 @@ Augment's django's built in `auth` with commonly-needed views for signup, email
|
||||
- `/accounts/signup`
|
||||
- `/accounts/login/code`
|
||||
- `/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",
|
||||
"django_structlog",
|
||||
"django_typer",
|
||||
"apps.accounts",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -116,6 +117,8 @@ USE_TZ = True
|
||||
|
||||
# Authentication -----
|
||||
|
||||
AUTH_USER_MODEL = "accounts.User"
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
"allauth.account.auth_backends.AuthenticationBackend",
|
||||
@ -136,21 +139,18 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
},
|
||||
]
|
||||
|
||||
DJOK_AUTH_MODE = "username"
|
||||
# DJOK_AUTH_MODE is a setting we introduce to pick between
|
||||
# DJOK_USER_TYPE is a setting we introduce to pick between
|
||||
# a few common auth patterns.
|
||||
#
|
||||
# Things other than 'username' currently experimental.
|
||||
# It is also used in accounts/models.py.
|
||||
#
|
||||
# 'username'
|
||||
# A username-based email
|
||||
#
|
||||
# 'email'
|
||||
# This configures django-allauth with reasonably secure defaults
|
||||
# for an email-based account.
|
||||
#
|
||||
# ''
|
||||
# WARNING: Changing this setting after initial setup can have
|
||||
# data-loss consequences.
|
||||
#
|
||||
# See documentation for explanation of options.
|
||||
DJOK_USER_TYPE = "email"
|
||||
|
||||
|
||||
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
|
||||
ACCOUNT_PRESERVE_USERNAME_CASING = False
|
||||
ACCOUNT_LOGIN_BY_CODE_ENABLED = True
|
||||
@ -162,7 +162,7 @@ ACCOUNT_USERNAME_BLACKLIST = ["admin"]
|
||||
# ACCOUNT_LOGIN_BY_CODE_REQUIRED = False
|
||||
# ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
|
||||
|
||||
if DJOK_AUTH_MODE == "email":
|
||||
if DJOK_USER_TYPE == "email":
|
||||
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
|
||||
ACCOUNT_LOGIN_METHODS = {"email"}
|
||||
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"]
|
||||
|
Loading…
Reference in New Issue
Block a user