flaschengeist/flaschengeist/models/user.py

119 lines
3.9 KiB
Python

from flask import url_for
from typing import Optional
from datetime import date, datetime
from sqlalchemy.orm.collections import attribute_mapped_collection
from ..database import db
from . import ModelSerializeMixin, UtcDateTime
association_table = db.Table(
"user_x_role",
db.Column("user_id", db.Integer, db.ForeignKey("user.id")),
db.Column("role_id", db.Integer, db.ForeignKey("role.id")),
)
role_permission_association_table = db.Table(
"role_x_permission",
db.Column("role_id", db.Integer, db.ForeignKey("role.id")),
db.Column("permission_id", db.Integer, db.ForeignKey("permission.id")),
)
class Permission(db.Model, ModelSerializeMixin):
__tablename__ = "permission"
name: str = db.Column(db.String(30), unique=True)
_id = db.Column("id", db.Integer, primary_key=True)
class Role(db.Model, ModelSerializeMixin):
__tablename__ = "role"
id: int = db.Column(db.Integer, primary_key=True)
name: str = db.Column(db.String(30), unique=True)
permissions: [Permission] = db.relationship("Permission", secondary=role_permission_association_table)
class User(db.Model, ModelSerializeMixin):
"""Database Object for User
Table for all saved User
Attributes:
id: Id in Database as Primary Key.
uid: User ID used by authentication provider
display_name: Name to show
firstname: Firstname of the User
lastname: Lastname of the User
mail: mail address of the User
birthday: Birthday of the user
"""
__tablename__ = "user"
userid: str = db.Column(db.String(30), nullable=False)
display_name: str = db.Column(db.String(30))
firstname: str = db.Column(db.String(50), nullable=False)
lastname: str = db.Column(db.String(50), nullable=False)
mail: str = db.Column(db.String(60), nullable=False)
birthday: Optional[date] = db.Column(db.Date)
roles: [str] = []
avatar_url: Optional[str] = ""
roles_: [Role] = db.relationship("Role", secondary=association_table, cascade="save-update, merge")
_id = db.Column("id", db.Integer, primary_key=True)
_sessions = db.relationship("Session", back_populates="_user")
_attributes = db.relationship(
"_UserAttribute", collection_class=attribute_mapped_collection("name"), cascade="all, delete"
)
@property
def avatar_url(self):
return url_for("users.get_avatar", userid=self.userid)
@property
def roles(self):
return [role.name for role in self.roles_]
def set_attribute(self, name, value):
if name in self._attributes:
self._attributes[name].value = value
else:
self._attributes[name] = _UserAttribute(name=name, value=value)
def has_attribute(self, name):
return name in self._attributes
def get_attribute(self, name, default=None):
if name in self._attributes:
return self._attributes[name].value
return default
def get_permissions(self):
return ["user"] + [permission.name for role in self.roles_ for permission in role.permissions]
def has_permission(self, permission):
return permission in self.get_permissions()
class _UserAttribute(db.Model, ModelSerializeMixin):
__tablename__ = "user_attribute"
id = db.Column("id", db.Integer, primary_key=True)
user: User = db.Column("user", db.Integer, db.ForeignKey("user.id"), nullable=False)
name: str = db.Column(db.String(30))
value: any = db.Column(db.PickleType(protocol=4))
class _PasswordReset(db.Model):
"""Table containing password reset requests"""
__tablename__ = "password_reset"
_user_id: User = db.Column("user", db.Integer, db.ForeignKey("user.id"), primary_key=True)
user: User = db.relationship("User", foreign_keys=[_user_id])
token: str = db.Column(db.String(30))
expires: datetime = db.Column(UtcDateTime)
class _Avatar:
"""Wrapper class for avatar binaries"""
mimetype = ""
binary = bytearray()