131 lines
4.5 KiB
Python
131 lines
4.5 KiB
Python
from typing import Optional
|
|
from datetime import date, datetime
|
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
|
|
|
from ..database import db
|
|
from ..database.types import ModelSerializeMixin, UtcDateTime, Serial
|
|
|
|
association_table = db.Table(
|
|
"user_x_role",
|
|
db.Column("user_id", Serial, db.ForeignKey("user.id")),
|
|
db.Column("role_id", Serial, db.ForeignKey("role.id")),
|
|
)
|
|
|
|
role_permission_association_table = db.Table(
|
|
"role_x_permission",
|
|
db.Column("role_id", Serial, db.ForeignKey("role.id")),
|
|
db.Column("permission_id", Serial, db.ForeignKey("permission.id")),
|
|
)
|
|
|
|
|
|
class Permission(db.Model, ModelSerializeMixin):
|
|
__tablename__ = "permission"
|
|
name: str = db.Column(db.String(30), unique=True)
|
|
|
|
_id = db.Column("id", Serial, primary_key=True)
|
|
_plugin_id: int = db.Column("plugin", Serial, db.ForeignKey("plugin.id"))
|
|
|
|
|
|
class Role(db.Model, ModelSerializeMixin):
|
|
__tablename__ = "role"
|
|
id: int = db.Column(Serial, primary_key=True)
|
|
name: str = db.Column(db.String(30), unique=True)
|
|
permissions: list[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), unique=True, 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)
|
|
deleted: bool = db.Column(db.Boolean(), default=False)
|
|
birthday: Optional[date] = db.Column(db.Date)
|
|
mail: str = db.Column(db.String(60))
|
|
roles: list[str] = []
|
|
permissions: Optional[list[str]] = None
|
|
|
|
# Protected stuff for backend use only
|
|
id_ = db.Column("id", Serial, primary_key=True)
|
|
roles_: list[Role] = db.relationship("Role", secondary=association_table, cascade="save-update, merge")
|
|
sessions_: list["Session"] = db.relationship(
|
|
"Session", back_populates="user_", cascade="all, delete, delete-orphan"
|
|
)
|
|
avatar_: Optional["Image"] = db.relationship("Image", cascade="all, delete, delete-orphan", single_parent=True)
|
|
reset_requests_: list["_PasswordReset"] = db.relationship("_PasswordReset", cascade="all, delete, delete-orphan")
|
|
|
|
# Private stuff for internal use
|
|
_avatar_id = db.Column("avatar", Serial, db.ForeignKey("image.id"))
|
|
_attributes = db.relationship(
|
|
"_UserAttribute",
|
|
collection_class=attribute_mapped_collection("name"),
|
|
cascade="all, delete, delete-orphan",
|
|
)
|
|
|
|
@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 delete_attribute(self, name):
|
|
if name in self._attributes:
|
|
self._attributes.pop(name)
|
|
|
|
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", Serial, primary_key=True)
|
|
user: User = db.Column("user", Serial, 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", Serial, db.ForeignKey("user.id"), primary_key=True)
|
|
user: User = db.relationship("User", back_populates="reset_requests_", foreign_keys=[_user_id])
|
|
token: str = db.Column(db.String(32))
|
|
expires: datetime = db.Column(UtcDateTime)
|
|
|
|
|
|
class _Avatar:
|
|
"""Wrapper class for avatar binaries"""
|
|
|
|
mimetype = ""
|
|
binary = bytearray()
|