Add user signup (has to be enabled via config)
This commit is contained in:
parent
d68eee7bf4
commit
f92ad205d2
9 changed files with 158 additions and 8 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,5 +1,18 @@
|
|||
# Matemat Changelog
|
||||
|
||||
<!-- BEGIN RELEASE v0.2.11 -->
|
||||
## Version 0.2.11
|
||||
|
||||
Feature release
|
||||
|
||||
### Changes
|
||||
|
||||
<!-- BEGIN CHANGES 0.2.11 -->
|
||||
- Feature: Permit user signup
|
||||
<!-- END CHANGES 0.2.11 -->
|
||||
|
||||
<!-- END RELEASE v0.2.11 -->
|
||||
|
||||
<!-- BEGIN RELEASE v0.2.10 -->
|
||||
## Version 0.2.10
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
|
||||
__version__ = '0.2.10'
|
||||
__version__ = '0.2.11'
|
||||
|
|
|
@ -7,6 +7,7 @@ A new pagelet function must be imported here to be automatically loaded when the
|
|||
from .main import main_page
|
||||
from .login import login_page
|
||||
from .logout import logout
|
||||
from .signup import signup
|
||||
from .touchkey import touchkey_page
|
||||
from .buy import buy
|
||||
from .deposit import deposit
|
||||
|
|
|
@ -163,14 +163,14 @@ def handle_admin_change(args: FormsDict, files: FormsDict, db: MatematDatabase):
|
|||
# The user requested to create a new user
|
||||
if change == 'newuser':
|
||||
# Only create a new user if all required properties of the user are present in the request arguments
|
||||
if 'username' not in args or 'email' not in args or 'password' not in args:
|
||||
if 'username' not in args or 'password' not in args:
|
||||
return
|
||||
# Read the properties from the request arguments
|
||||
username = str(args.username)
|
||||
email = str(args.email)
|
||||
# An empty e-mail field should be interpreted as NULL
|
||||
if len(email) == 0:
|
||||
email = None
|
||||
if 'email' in args and len(args.email) > 0:
|
||||
# An empty e-mail field should be interpreted as NULL
|
||||
email = str(args.email)
|
||||
password = str(args.password)
|
||||
is_member = 'ismember' in args
|
||||
is_admin = 'isadmin' in args
|
||||
|
|
|
@ -34,4 +34,5 @@ def main_page():
|
|||
# If no user is logged in, fetch the list of users and render the userlist template
|
||||
users = db.list_users(with_touchkey=True)
|
||||
return template.render('userlist.html',
|
||||
users=users, setupname=config['InstanceName'])
|
||||
users=users, setupname=config['InstanceName'],
|
||||
signup=(config.get('SignupEnabled', '0') == '1'))
|
||||
|
|
93
matemat/webserver/pagelets/signup.py
Normal file
93
matemat/webserver/pagelets/signup.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
import os
|
||||
from shutil import copyfile
|
||||
from io import BytesIO
|
||||
|
||||
import magic
|
||||
from bottle import get, post, redirect, abort, request, FormsDict
|
||||
from PIL import Image
|
||||
|
||||
from matemat.db import MatematDatabase
|
||||
from matemat.db.primitives import User
|
||||
from matemat.webserver import template, session
|
||||
from matemat.webserver.config import get_app_config
|
||||
|
||||
|
||||
def signup_user(args: FormsDict, files: FormsDict, db: MatematDatabase) -> User:
|
||||
config = get_app_config()
|
||||
if 'username' not in args or 'password' not in args or 'password2' not in args:
|
||||
raise ValueError('Required fields missing')
|
||||
username = str(args.username)
|
||||
password = str(args.password)
|
||||
password2 = str(args.password2)
|
||||
if password != password2:
|
||||
raise ValueError('Passwords do not match')
|
||||
email = None
|
||||
if 'email' in args and len(args.email) > 0:
|
||||
email = str(args.email)
|
||||
|
||||
new_user = db.create_user(username, password, email=email, admin=False, member=False)
|
||||
# If a touchkey was provided, set it
|
||||
if 'touchkey' in args and len(args.touchkey) > 0:
|
||||
touchkey = str(args.touchkey)
|
||||
db.change_touchkey(new_user, password, touchkey, verify_password=False)
|
||||
# Finally, set the avatar, if provided
|
||||
if 'avatar' in files:
|
||||
avatar = files.avatar.file.read()
|
||||
if len(avatar) > 0:
|
||||
filemagic: magic.FileMagic = magic.detect_from_content(avatar)
|
||||
if filemagic.mime_type.startswith('image/'):
|
||||
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/')
|
||||
os.makedirs(abspath, exist_ok=True)
|
||||
# Parse the image data
|
||||
image: Image = Image.open(BytesIO(avatar))
|
||||
# Resize the image to 150x150
|
||||
image.thumbnail((150, 150), Image.LANCZOS)
|
||||
# Write the image to the file
|
||||
image.save(os.path.join(abspath, f'{new_user.id}.png'), 'PNG')
|
||||
else:
|
||||
# If a default avatar is set, copy it to the user's avatar path
|
||||
# Create the absolute path of the upload directory
|
||||
abspath: str = os.path.join(os.path.abspath(config['UploadDir']), 'thumbnails/users/')
|
||||
# Derive the individual paths
|
||||
default: str = os.path.join(abspath, 'default.png')
|
||||
userimg: str = os.path.join(abspath, f'{new_user.id}.png')
|
||||
# Copy the default image, if it exists
|
||||
if os.path.exists(default):
|
||||
copyfile(default, userimg, follow_symlinks=True)
|
||||
return new_user
|
||||
|
||||
|
||||
@get('/signup')
|
||||
@post('/signup')
|
||||
def signup():
|
||||
"""
|
||||
The password login mechanism. If called via GET, render the UI template; if called via POST, attempt to log in with
|
||||
the provided credentials (username and passsword).
|
||||
"""
|
||||
config = get_app_config()
|
||||
session_id: str = session.start()
|
||||
# If signup is not enabled, redirect to the main page
|
||||
if config.get('SignupEnabled', '0') != '1':
|
||||
redirect('/')
|
||||
# If a user is already logged in, simply redirect to the main page, showing the product list
|
||||
if session.has(session_id, 'authenticated_user'):
|
||||
redirect('/')
|
||||
# If requested via HTTP POST, read the request arguments and attempt to create a new user
|
||||
if request.method == 'POST':
|
||||
# Connect to the database and create the user
|
||||
with MatematDatabase(config['DatabaseFile']) as db:
|
||||
try:
|
||||
user = signup_user(request.params, request.files, db)
|
||||
except ValueError as e:
|
||||
redirect('/signup')
|
||||
# Set the user ID session variable
|
||||
session.put(session_id, 'authenticated_user', user.id)
|
||||
# Set the authlevel session variable (0 = none, 1 = touchkey, 2 = password login)
|
||||
session.put(session_id, 'authentication_level', 2)
|
||||
# Redirect to the main page, showing the product list
|
||||
redirect('/')
|
||||
elif request.method != 'GET':
|
||||
abort(405, 'Method not allowed')
|
||||
return template.render('signup.html',
|
||||
setupname=config['InstanceName'])
|
|
@ -1,5 +1,5 @@
|
|||
Package: matemat
|
||||
Version: 0.2.10
|
||||
Version: 0.2.11
|
||||
Maintainer: s3lph <account-gitlab-ideynizv@kernelpanic.lol>
|
||||
Section: web
|
||||
Priority: optional
|
||||
|
|
39
templates/signup.html
Normal file
39
templates/signup.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block header %}
|
||||
<h1>Signup</h1>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{# Show a username/password signup form #}
|
||||
<form method="post" action="/signup" id="signupform" enctype="multipart/form-data" accept-charset="UTF-8">
|
||||
<label for="signup-username"><b>Username</b>: </label>
|
||||
<input id="signup-username" type="text" name="username" required="required"/><br/>
|
||||
|
||||
<label for="signup-password"><b>Choose a password</b>: </label>
|
||||
<input id="signup-password" type="password" name="password" required="required"/><br/>
|
||||
|
||||
<label for="signup-password2"><b>Repeat password</b>: </label>
|
||||
<input id="signup-password2" type="password" name="password2" required="required"/><br/>
|
||||
|
||||
<label for="signup-avatar">Upload a profile picture: </label>
|
||||
<input id="signup-avatar" type="file" name="avatar" accept="image/*" /><br/>
|
||||
|
||||
<label for="signup-touchkey">Draw a touchkey (touchscreen login pattern)</label>
|
||||
<br/>
|
||||
<svg id="touchkey-svg" width="400" height="400"></svg>
|
||||
<br/>
|
||||
<input id="signup-touchkey" type="hidden" name="touchkey" value="" />
|
||||
|
||||
<input type="submit" value="Create account">
|
||||
</form>
|
||||
<script src="/static/js/touchkey.js" ></script>
|
||||
<script>
|
||||
initTouchkey(true, 'touchkey-svg', null, 'signup-touchkey');
|
||||
</script>
|
||||
|
||||
{{ super() }}
|
||||
|
||||
{% endblock %}
|
|
@ -23,6 +23,9 @@
|
|||
<br/>
|
||||
{# Link to the password login #}
|
||||
<a href="/login">Password login</a>
|
||||
{% if signup %}
|
||||
<a href="/signup">Create account</a>
|
||||
{% endif %}
|
||||
|
||||
{{ super() }}
|
||||
|
||||
|
|
Loading…
Reference in a new issue