|
|
@ -2,7 +2,9 @@ from datetime import date, datetime |
|
|
|
from app import db |
|
|
|
from flask_login import UserMixin |
|
|
|
from app.models.contents import Content |
|
|
|
from app.models.privs import Group, GroupMember |
|
|
|
from app.models.privs import SpecialPrivilege, Group, GroupMember, \ |
|
|
|
GroupPrivilege |
|
|
|
from config import V5Config |
|
|
|
|
|
|
|
import werkzeug.security |
|
|
|
import app |
|
|
@ -29,6 +31,32 @@ class User(UserMixin, db.Model): |
|
|
|
def __repr__(self): |
|
|
|
return f'<User #{self.id}>' |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def valid_name(name): |
|
|
|
""" |
|
|
|
Checks whether a string is a valid user name. The criteria are: |
|
|
|
1. No whitespace-class character |
|
|
|
2. At least one letter |
|
|
|
3. At least 3 characters and no longer than 32 characters |
|
|
|
|
|
|
|
Possibily other intresting criteria: |
|
|
|
4. Unicode restriction |
|
|
|
""" |
|
|
|
|
|
|
|
if type(name) != str or len(name) < 3 or len(name) > 32: |
|
|
|
return False |
|
|
|
if name in V5Config.FORBIDDEN_USERNAMES: |
|
|
|
return False |
|
|
|
# Reject all Unicode whitespaces. This is important to avoid the most |
|
|
|
# common Unicode tricks! |
|
|
|
if re.search(r'\s', name) is not None: |
|
|
|
return False |
|
|
|
# There must be at least one letter (avoid complete garbage) |
|
|
|
if re.search(r'\w', name) is None: |
|
|
|
return False |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
# Guest: Unregistered user with minimal privileges |
|
|
|
class Guest(User, db.Model): |
|
|
|
__tablename__ = 'guest' |
|
|
@ -77,33 +105,9 @@ class Member(User, db.Model): |
|
|
|
# trophies = db.relationship('Trophy', back_populates='member') |
|
|
|
# tests = db.relationship('Test', back_populates='author') |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def valid_name(name): |
|
|
|
""" |
|
|
|
Checks whether a string is a valid member name. The criteria are: |
|
|
|
1. No whitespace-class character |
|
|
|
2. At least one letter |
|
|
|
3. No longer than 32 characters |
|
|
|
|
|
|
|
Possibily other intresting criteria: |
|
|
|
4. Unicode restriction |
|
|
|
""" |
|
|
|
|
|
|
|
if type(name) != str or len(name) > 32: |
|
|
|
return False |
|
|
|
# Reject all Unicode whitespaces. This is important to avoid the most |
|
|
|
# common Unicode tricks! |
|
|
|
if re.search(r'\s', name) is not None: |
|
|
|
return False |
|
|
|
# There must be at least one letter (avoid complete garbage) |
|
|
|
if re.search(r'\w', name) is None: |
|
|
|
return False |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
def __init__(self, name, email, password): |
|
|
|
"""Register a new user.""" |
|
|
|
if not Member.valid_name(name): |
|
|
|
if not User.valid_name(name): |
|
|
|
raise Exception(f'{name} is not a valid user name') |
|
|
|
|
|
|
|
self.name = name |
|
|
@ -116,7 +120,16 @@ class Member(User, db.Model): |
|
|
|
self.signature = "" |
|
|
|
self.birthday = None |
|
|
|
|
|
|
|
def update(self, data): |
|
|
|
def priv(self, priv): |
|
|
|
"""Check whether the member has the specified privilege.""" |
|
|
|
if SpecialPrivilege.filter(uif=self.id, priv=priv): |
|
|
|
return True |
|
|
|
return False |
|
|
|
# return db.session.query(User, Group, GroupPrivilege).filter( |
|
|
|
# Group.id.in_(User.groups), GroupPrivilege.gid==Group.id, |
|
|
|
# GroupPrivilege.priv==priv).first() is not None |
|
|
|
|
|
|
|
def update(self, **data): |
|
|
|
""" |
|
|
|
Update all or part of the user's metadata. The [data] dictionary |
|
|
|
accepts the following keys: |
|
|
@ -138,7 +151,7 @@ class Member(User, db.Model): |
|
|
|
data = { key: data[key] for key in data if data[key] is not None } |
|
|
|
|
|
|
|
if "name" in data: |
|
|
|
if not Member.valid_name(data["name"]): |
|
|
|
if not User.valid_name(data["name"]): |
|
|
|
raise Exception(f'{data["name"]} is not a valid user name') |
|
|
|
self.name = data["name"] |
|
|
|
|
|
|
|