sign up works
This commit is contained in:
parent
42389fe7ac
commit
9bb18a6cca
16 changed files with 154 additions and 121 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
auth.sqlite3
|
||||||
|
|
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"noauth",
|
||||||
|
"noscript",
|
||||||
|
"stylesheet",
|
||||||
|
"tauth",
|
||||||
|
"TCOMMON"
|
||||||
|
]
|
||||||
|
}
|
10
config.py
10
config.py
|
@ -1,8 +1,4 @@
|
||||||
ALLOW_NEW_USERS = True
|
ALLOW_NEW_USERS = True
|
||||||
DEBUG = True
|
|
||||||
ENABLED_APPLICATIONS = {
|
tCOMMON_URL_INTERNAL = "http://localhost:8888"
|
||||||
"search": False,
|
tCOMMON_TOKEN = "Secret tCommon-specific token"
|
||||||
"music": False,
|
|
||||||
"messages": False,
|
|
||||||
"info": False
|
|
||||||
}
|
|
||||||
|
|
6
tauth/apps.py
Normal file
6
tauth/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class DBConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "tauth"
|
23
tauth/migrations/0001_initial.py
Normal file
23
tauth/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.0.7 on 2024-12-21 04:40
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0012_alter_user_first_name_max_length'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TUser',
|
||||||
|
fields=[
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
tauth/migrations/__init__.py
Normal file
0
tauth/migrations/__init__.py
Normal file
6
tauth/models.py
Normal file
6
tauth/models.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class TUser(models.Model):
|
||||||
|
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
|
@ -1,12 +1,25 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from config import DEBUG # noqa: F401
|
import requests
|
||||||
|
|
||||||
|
from config import tCOMMON_TOKEN, tCOMMON_URL_INTERNAL
|
||||||
|
|
||||||
|
config = requests.get(f"{tCOMMON_URL_INTERNAL}/api/initialize/", params={
|
||||||
|
"token": tCOMMON_TOKEN
|
||||||
|
}, allow_redirects=False).json()
|
||||||
|
|
||||||
|
if not config["success"]:
|
||||||
|
raise ImportError("tCommon token doesn't match")
|
||||||
|
|
||||||
|
if not config["services"]["auth"]:
|
||||||
|
raise ImportError("tAuth isn't registered in tCommon")
|
||||||
|
|
||||||
|
DEBUG = config["debug"]
|
||||||
|
SECRET_KEY = config["services"]["auth"]["token"]
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
SECRET_KEY = "django-insecure--h3t*!a-h+(m7537)oxl9&fpjsin)#ht(5e!8w^5%ea1@f84u1"
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
"django.contrib.admin",
|
"django.contrib.admin",
|
||||||
|
@ -15,6 +28,7 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
"tauth.apps.DBConfig"
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -52,7 +66,7 @@ WSGI_APPLICATION = "tauth.wsgi.application"
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
"NAME": BASE_DIR / "db.sqlite3",
|
"NAME": BASE_DIR / "auth.sqlite3",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block card %}
|
{% block body %}
|
||||||
<h1>Hmm. That doesn't look right.</h1>
|
<h1>Hmm. That doesn't look right.</h1>
|
||||||
Make sure the URL is correct and try again.
|
Make sure the URL is correct and try again.
|
||||||
<small>(Error 404 - Page not found)</small>
|
<small>(Error 404 - Page not found)</small>
|
||||||
|
|
|
@ -8,21 +8,14 @@
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<meta name="pronouns" content="she/her">
|
<meta name="pronouns" content="she/her">
|
||||||
|
|
||||||
|
<link rel="icon" href="{{ config.services.common.url.pub }}/favicon/dark/{{ accent }}/">
|
||||||
|
<link rel="icon" href="{{ config.services.common.url.pub }}/favicon/light/{{ accent }}/" media="(prefers-color-scheme: light)">
|
||||||
|
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
|
|
||||||
<style>
|
<link rel="stylesheet" href="{{ config.services.common.url.pub }}/static/css/base.css?v={{ config.version_str }}">
|
||||||
{% include "css/base.css" %}
|
<style>html { --accent: var(--{{ accent }}); }</style>
|
||||||
{% block head_css %}{% endblock %}
|
<script src="{{ config.services.common.url.pub }}/static/js/theme.js?v={{ config.version_str }}"></script>
|
||||||
|
|
||||||
html {
|
|
||||||
--accent: var(--{{ accent }});
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
{% include "js/theme.js" %}
|
|
||||||
{% block head_js %}{% endblock %}
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/* Colors */
|
|
||||||
html { --rosewater: #f5e0dc; --flamingo: #f2cdcd; --pink: #f5c2e7; --mauve: #cba6f7; --red: #f38ba8; --maroon: #eba0ac; --peach: #fab387; --yellow: #f9e2af; --green: #a6e3a1; --teal: #94e2d5; --sky: #89dceb; --sapphire: #74c7ec; --blue: #89b4fa; --lavender: #b4befe; --text: #cdd6f4; --subtext1: #bac2de; --subtext0: #a6adc8; --overlay2: #9399b2; --overlay1: #7f849c; --overlay0: #6c7086; --surface2: #585b70; --surface1: #45475a; --surface0: #313244; --base: #1e1e2e; --mantle: #181825; --crust: #11111b; --base-low-op: #1e1e2ed0 }
|
|
||||||
html[data-light] { --rosewater: #dc8a78; --flamingo: #dd7878; --pink: #ea76cb; --mauve: #8839ef; --red: #d20f39; --maroon: #e64553; --peach: #fe640b; --yellow: #df8e1d; --green: #40a02b; --teal: #179299; --sky: #04a5e5; --sapphire: #209fb5; --blue: #1e66f5; --lavender: #7287fd; --text: #4c4f69; --subtext1: #5c5f77; --subtext0: #6c6f85; --overlay2: #7c7f93; --overlay1: #8c8fa1; --overlay0: #9ca0b0; --surface2: #acb0be; --surface1: #bcc0cc; --surface0: #ccd0da; --base: #eff1f5; --mantle: #e6e9ef; --crust: #dce0e8; --base-low-op: #eff1f5b0}
|
|
||||||
|
|
||||||
/* Font */
|
|
||||||
@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 400; font-display: block; src: url("/static/font/DejaVuSans.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 700; font-display: block; src: url("/static/font/DejaVuSans-Bold.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: 'DejaVu Sans'; font-style: italic; font-weight: 400; font-display: block; src: url("/static/font/DejaVuSans-Oblique.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: 'DejaVu Sans'; font-style: italic; font-weight: 700; font-display: block; src: url("/static/font/DejaVuSans-BoldOblique.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 200; font-display: block; src: url("/static/font/DejaVuSans-ExtraLight.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: "Ubuntu Mono"; font-style: normal; font-weight: 400; font-display: block; src: url("/static/font/UbuntuMono-Regular.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: "Ubuntu Mono"; font-style: italic; font-weight: 400; font-display: block; src: url("/static/font/UbuntuMono-Italic.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: "Ubuntu Mono"; font-style: normal; font-weight: 700; font-display: block; src: url("/static/font/UbuntuMono-Bold.ttf") format("truetype"); }
|
|
||||||
@font-face { font-family: "Ubuntu Mono"; font-style: italic; font-weight: 700; font-display: block; src: url("/static/font/UbuntuMono-BoldItalic.ttf") format("truetype"); }
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
width: 100vw;
|
|
||||||
min-height: 100vh;
|
|
||||||
overflow-x: hidden;
|
|
||||||
background-color: var(--base);
|
|
||||||
color: var(--text);
|
|
||||||
font-family: "DejaVu Sans";
|
|
||||||
/* background-image: linear-gradient(
|
|
||||||
135deg,
|
|
||||||
var(--base) 25%,
|
|
||||||
var(--mantle) 25%,
|
|
||||||
var(--mantle) 50%,
|
|
||||||
var(--base) 50%,
|
|
||||||
var(--base) 75%,
|
|
||||||
var(--mantle) 75%
|
|
||||||
);
|
|
||||||
background-size: 20px 20px;
|
|
||||||
background-repeat: repeat; */
|
|
||||||
}
|
|
||||||
|
|
||||||
code, pre {
|
|
||||||
font-family: "Ubuntu Mono"
|
|
||||||
}
|
|
||||||
|
|
||||||
small, i {
|
|
||||||
color: var(--subtext0);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: var(--accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link,
|
|
||||||
a:visited {
|
|
||||||
color: var(--accent);
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container {
|
|
||||||
text-align: center;
|
|
||||||
padding: 10px;
|
|
||||||
width: calc(100vw - 20px);
|
|
||||||
max-width: calc(100vw - 20px);
|
|
||||||
}
|
|
6
tauth/templates/index.html
Normal file
6
tauth/templates/index.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>Welcome back, {{ username }}!</h1>
|
||||||
|
tAuth
|
||||||
|
{% endblock %}
|
|
@ -1,30 +0,0 @@
|
||||||
let _themeMM = matchMedia("(prefers-color-scheme: light)");
|
|
||||||
let light, useAutoTheme;
|
|
||||||
// {% if theme == "auto" %}
|
|
||||||
light = _themeMM.matches;
|
|
||||||
useAutoTheme = true;
|
|
||||||
// {% else %}
|
|
||||||
// {% if theme == "light" %}
|
|
||||||
light = true;
|
|
||||||
// {% else %}
|
|
||||||
light = false;
|
|
||||||
// {% endif %}
|
|
||||||
useAutoTheme = false;
|
|
||||||
// {% endif %}
|
|
||||||
|
|
||||||
function setTheme() {
|
|
||||||
if (light) {
|
|
||||||
document.documentElement.setAttribute("data-light", "");
|
|
||||||
} else {
|
|
||||||
document.documentElement.removeAttribute("data-light");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_themeMM.addEventListener("change", function() {
|
|
||||||
if (useAutoTheme) {
|
|
||||||
light = _themeMM.matches;
|
|
||||||
setTheme();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTheme();
|
|
|
@ -4,12 +4,30 @@
|
||||||
<h1>Sign Up</h1>
|
<h1>Sign Up</h1>
|
||||||
<div>tAuth</div>
|
<div>tAuth</div>
|
||||||
<p>
|
<p>
|
||||||
<form>
|
<form method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<p>
|
<p>
|
||||||
<div><input required type="text" pattern="[a-z0-9A-Z_][a-z0-9A-Z_\-]{0,30}[a-z0-9A-Z_]" placeholder="Username"></div>
|
<div><input name="username" id="username" required type="text" pattern="[a-z0-9A-Z_][a-z0-9A-Z_\-]{0,28}[a-z0-9A-Z_]" maxlength="30" placeholder="Username"></div>
|
||||||
<div><small>2-30 characters, <code>A-Z</code>, <code>0-9</code>, <code>_</code>, and <code>-</code>. Can't start or end with a <code>-</code></small></div>
|
<label for="username"><small>
|
||||||
|
<ul class="left inline-block">
|
||||||
|
<li><b>2-30</b> characters</li>
|
||||||
|
<li><b>A-Z</b>, <b>0-9</b>, <b>underscores</b>, and <b>hyphens</b> accepted.</li>
|
||||||
|
<li>Can't start or end with a <b>hyphen</b></li>
|
||||||
|
<li>Case <b>insensitive</b></li>
|
||||||
|
</ul>
|
||||||
|
</small></label>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<div><input name="password" id="password" required type="password" placeholder="Password" maxlength="100"></div>
|
||||||
|
<label for="password"><small>
|
||||||
|
<ul class="left inline-block">
|
||||||
|
<li><b>6+</b> characters</li>
|
||||||
|
<li>Must include a <b>letter</b>, <b>number</b>, and <b>special character</b></li>
|
||||||
|
<li>Can't include your <b>username</b></li>
|
||||||
|
</ul>
|
||||||
|
</small></label>
|
||||||
|
</p>
|
||||||
|
<p><input type="submit" value="Sign Up"></p>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,6 +4,8 @@ from django.core.handlers.wsgi import WSGIRequest
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
|
|
||||||
|
from tauth.settings import config
|
||||||
|
|
||||||
COLORS = ["rosewater", "flamingo", "pink", "mauve", "red", "maroon", "peach", "yellow", "green", "teal", "sky", "sapphire", "blue", "lavender"]
|
COLORS = ["rosewater", "flamingo", "pink", "mauve", "red", "maroon", "peach", "yellow", "green", "teal", "sky", "sapphire", "blue", "lavender"]
|
||||||
|
|
||||||
def render_template(
|
def render_template(
|
||||||
|
@ -17,7 +19,8 @@ def render_template(
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
c = {
|
c = {
|
||||||
"theme": "auto",
|
"theme": "auto",
|
||||||
"accent": random.choice(COLORS)
|
"accent": random.choice(COLORS),
|
||||||
|
"config": config
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, val in context.items():
|
for key, val in context.items():
|
||||||
|
|
|
@ -1,19 +1,67 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.contrib.auth import login as set_auth
|
||||||
|
from django.contrib.auth import logout as remove_auth
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.core.handlers.wsgi import WSGIRequest
|
from django.core.handlers.wsgi import WSGIRequest
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
|
||||||
from config import ALLOW_NEW_USERS
|
from config import ALLOW_NEW_USERS
|
||||||
|
from tauth.models import TUser
|
||||||
|
|
||||||
from .helper import render_template
|
from .helper import render_template
|
||||||
|
|
||||||
|
|
||||||
def index(request: WSGIRequest) -> HttpResponse:
|
def index(request: WSGIRequest) -> HttpResponse:
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
return render_template(
|
||||||
|
request, "index.html",
|
||||||
|
username=request.user.get_username()
|
||||||
|
)
|
||||||
return render_template(
|
return render_template(
|
||||||
request, "noauth/index.html",
|
request, "noauth/index.html",
|
||||||
new_users=ALLOW_NEW_USERS
|
new_users=ALLOW_NEW_USERS
|
||||||
)
|
)
|
||||||
|
|
||||||
def signup(request: WSGIRequest) -> HttpResponse:
|
def signup(request: WSGIRequest) -> HttpResponse:
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
return HttpResponseRedirect("/")
|
||||||
|
|
||||||
if ALLOW_NEW_USERS:
|
if ALLOW_NEW_USERS:
|
||||||
|
if request.method == "POST":
|
||||||
|
username = (request.POST.get("username") or "").lower().strip()
|
||||||
|
password = (request.POST.get("password") or "")
|
||||||
|
error = None
|
||||||
|
|
||||||
|
if len(username) < 2 or len(username) > 30 or not re.match("^[a-z0-9_][a-z0-9_\\-]{0,28}[a-z0-9_]$", username):
|
||||||
|
error = "Invalid username"
|
||||||
|
|
||||||
|
elif len(password) < 6 or len(password) > 100 or not (any([i.isalpha() for i in password]) and any([i.isnumeric() for i in password]) and any([not i.isalnum() for i in password])):
|
||||||
|
error = "Invalid password"
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
u = User.objects.create_user(
|
||||||
|
username=username,
|
||||||
|
password=password
|
||||||
|
)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
error = "Username already in use"
|
||||||
|
else:
|
||||||
|
TUser.objects.create(user=u)
|
||||||
|
|
||||||
|
set_auth(request, u)
|
||||||
|
return HttpResponseRedirect("/")
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
request, "noauth/signup.html",
|
||||||
|
title="Sign Up",
|
||||||
|
error=error,
|
||||||
|
repopulate={
|
||||||
|
"username": username
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
request, "noauth/signup.html",
|
request, "noauth/signup.html",
|
||||||
title="Sign Up"
|
title="Sign Up"
|
||||||
|
|
Loading…
Reference in a new issue