Compare commits
2 Commits
593b8546a2
...
d0674e8876
Author | SHA1 | Date |
---|---|---|
|
d0674e8876 | |
|
50fa39be4f |
|
@ -1,5 +1,6 @@
|
||||||
import secrets
|
import secrets
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from sqlalchemy import exc
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from flask.helpers import send_file
|
from flask.helpers import send_file
|
||||||
|
@ -168,11 +169,34 @@ def find_user(uid_mail):
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def delete(user):
|
@Hook
|
||||||
|
def delete_user(user: User):
|
||||||
"""Delete given user"""
|
"""Delete given user"""
|
||||||
|
# First let the backend delete the user, as this might fail
|
||||||
current_app.config["FG_AUTH_BACKEND"].delete_user(user)
|
current_app.config["FG_AUTH_BACKEND"].delete_user(user)
|
||||||
|
# Clear all easy relationships
|
||||||
|
user.avatar_ = None
|
||||||
|
user._attributes.clear()
|
||||||
|
user.roles_.clear()
|
||||||
|
user.sessions_.clear()
|
||||||
|
user.reset_requests_.clear()
|
||||||
|
db.session.commit()
|
||||||
|
try:
|
||||||
|
# Delete the user
|
||||||
db.session.delete(user)
|
db.session.delete(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
except exc.IntegrityError:
|
||||||
|
logger.error("Delete of user failed, there might be ForeignKey contraits from disabled plugins", exec_info=True)
|
||||||
|
# Remove at least all personal data
|
||||||
|
user.userid = f"__deleted_user__{user.id_}"
|
||||||
|
user.display_name = "DELETED USER"
|
||||||
|
user.firstname = ""
|
||||||
|
user.lastname = ""
|
||||||
|
user.birthday = None
|
||||||
|
user.mail = None
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def register(data):
|
def register(data):
|
||||||
|
|
|
@ -5,10 +5,9 @@ from typing import Optional
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||||
|
|
||||||
from flaschengeist.models.image import Image
|
|
||||||
|
|
||||||
from ..database import db
|
from ..database import db
|
||||||
from . import ModelSerializeMixin, UtcDateTime, Serial
|
from . import ModelSerializeMixin, UtcDateTime, Serial
|
||||||
|
from .image import Image
|
||||||
|
|
||||||
|
|
||||||
association_table = db.Table(
|
association_table = db.Table(
|
||||||
|
@ -63,16 +62,21 @@ class User(db.Model, ModelSerializeMixin):
|
||||||
roles: list[str] = []
|
roles: list[str] = []
|
||||||
permissions: Optional[list[str]] = None
|
permissions: Optional[list[str]] = None
|
||||||
|
|
||||||
|
# Protected stuff for backend use only
|
||||||
id_ = db.Column("id", Serial, primary_key=True)
|
id_ = db.Column("id", Serial, primary_key=True)
|
||||||
roles_: list[Role] = db.relationship("Role", secondary=association_table, cascade="save-update, merge")
|
roles_: list[Role] = db.relationship("Role", secondary=association_table, cascade="save-update, merge")
|
||||||
sessions_ = db.relationship("Session", back_populates="user_")
|
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)
|
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"))
|
_avatar_id = db.Column("avatar", Serial, db.ForeignKey("image.id"))
|
||||||
_attributes = db.relationship(
|
_attributes = db.relationship(
|
||||||
"_UserAttribute",
|
"_UserAttribute",
|
||||||
collection_class=attribute_mapped_collection("name"),
|
collection_class=attribute_mapped_collection("name"),
|
||||||
cascade="all, delete",
|
cascade="all, delete, delete-orphan",
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -117,7 +121,7 @@ class _PasswordReset(db.Model):
|
||||||
|
|
||||||
__tablename__ = "password_reset"
|
__tablename__ = "password_reset"
|
||||||
_user_id: User = db.Column("user", Serial, db.ForeignKey("user.id"), primary_key=True)
|
_user_id: User = db.Column("user", Serial, db.ForeignKey("user.id"), primary_key=True)
|
||||||
user: User = db.relationship("User", foreign_keys=[_user_id])
|
user: User = db.relationship("User", back_populates="reset_requests_", foreign_keys=[_user_id])
|
||||||
token: str = db.Column(db.String(32))
|
token: str = db.Column(db.String(32))
|
||||||
expires: datetime = db.Column(UtcDateTime)
|
expires: datetime = db.Column(UtcDateTime)
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,11 @@ before_update_user = HookBefore("update_user")
|
||||||
Args:
|
Args:
|
||||||
user: User object
|
user: User object
|
||||||
"""
|
"""
|
||||||
|
before_delete_user = HookBefore("delete_user")
|
||||||
|
"""Hook decorator,this is called before an user gets deleted.
|
||||||
|
Args:
|
||||||
|
user: User object
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
|
|
|
@ -6,8 +6,7 @@ Flaschengeist database (as User attribute)
|
||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
import binascii
|
import binascii
|
||||||
from werkzeug.exceptions import BadRequest, NotFound
|
from werkzeug.exceptions import BadRequest
|
||||||
|
|
||||||
from flaschengeist.plugins import AuthPlugin
|
from flaschengeist.plugins import AuthPlugin
|
||||||
from flaschengeist.models.user import User, Role, Permission
|
from flaschengeist.models.user import User, Role, Permission
|
||||||
from flaschengeist.database import db
|
from flaschengeist.database import db
|
||||||
|
@ -18,6 +17,8 @@ class AuthPlain(AuthPlugin):
|
||||||
def post_install(self):
|
def post_install(self):
|
||||||
if User.query.first() is None:
|
if User.query.first() is None:
|
||||||
logger.info("Installing admin user")
|
logger.info("Installing admin user")
|
||||||
|
role = Role.query.filter(Role.name == "Superuser").first()
|
||||||
|
if role is None:
|
||||||
role = Role(name="Superuser", permissions=Permission.query.all())
|
role = Role(name="Superuser", permissions=Permission.query.all())
|
||||||
admin = User(
|
admin = User(
|
||||||
userid="admin",
|
userid="admin",
|
||||||
|
|
|
@ -2,18 +2,17 @@
|
||||||
|
|
||||||
Provides routes used to manage users
|
Provides routes used to manage users
|
||||||
"""
|
"""
|
||||||
from io import BytesIO
|
|
||||||
from http.client import NO_CONTENT, CREATED
|
from http.client import NO_CONTENT, CREATED
|
||||||
from flask import Blueprint, request, jsonify, make_response, Response, send_file
|
from flask import Blueprint, request, jsonify, make_response
|
||||||
from werkzeug.exceptions import BadRequest, Forbidden, MethodNotAllowed, NotFound
|
from werkzeug.exceptions import BadRequest, Forbidden, MethodNotAllowed, NotFound
|
||||||
|
|
||||||
from . import permissions
|
from . import permissions
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
from flaschengeist.config import config
|
from flaschengeist.config import config
|
||||||
from flaschengeist.plugins import Plugin
|
from flaschengeist.plugins import Plugin
|
||||||
from flaschengeist.models.user import User, _Avatar
|
from flaschengeist.models.user import User
|
||||||
from flaschengeist.utils.decorators import login_required, extract_session, headers
|
from flaschengeist.utils.decorators import login_required, extract_session, headers
|
||||||
from flaschengeist.controller import userController, imageController as image_controller
|
from flaschengeist.controller import userController
|
||||||
from flaschengeist.utils.HTTP import created, no_content
|
from flaschengeist.utils.HTTP import created, no_content
|
||||||
from flaschengeist.utils.datetime import from_iso_format
|
from flaschengeist.utils.datetime import from_iso_format
|
||||||
|
|
||||||
|
@ -23,6 +22,10 @@ class UsersPlugin(Plugin):
|
||||||
blueprint = Blueprint(name, __name__)
|
blueprint = Blueprint(name, __name__)
|
||||||
permissions = permissions.permissions
|
permissions = permissions.permissions
|
||||||
|
|
||||||
|
def install(self):
|
||||||
|
userController.install()
|
||||||
|
return super().install()
|
||||||
|
|
||||||
|
|
||||||
@UsersPlugin.blueprint.route("/users", methods=["POST"])
|
@UsersPlugin.blueprint.route("/users", methods=["POST"])
|
||||||
def register():
|
def register():
|
||||||
|
@ -144,7 +147,7 @@ def delete_avatar(userid, current_session):
|
||||||
if userid != current_session.user_.userid and not current_session.user_.has_permission(permissions.EDIT):
|
if userid != current_session.user_.userid and not current_session.user_.has_permission(permissions.EDIT):
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
userController.delete_avatar(user)
|
userController.delete_avatar(user)
|
||||||
return "", NO_CONTENT
|
return no_content()
|
||||||
|
|
||||||
|
|
||||||
@UsersPlugin.blueprint.route("/users/<userid>", methods=["DELETE"])
|
@UsersPlugin.blueprint.route("/users/<userid>", methods=["DELETE"])
|
||||||
|
@ -163,8 +166,8 @@ def delete_user(userid, current_session):
|
||||||
"""
|
"""
|
||||||
logger.debug("Delete user {{ {} }}".format(userid))
|
logger.debug("Delete user {{ {} }}".format(userid))
|
||||||
user = userController.get_user(userid)
|
user = userController.get_user(userid)
|
||||||
userController.delete(user)
|
userController.delete_user(user)
|
||||||
return "", NO_CONTENT
|
return no_content()
|
||||||
|
|
||||||
|
|
||||||
@UsersPlugin.blueprint.route("/users/<userid>", methods=["PUT"])
|
@UsersPlugin.blueprint.route("/users/<userid>", methods=["PUT"])
|
||||||
|
@ -217,7 +220,7 @@ def edit_user(userid, current_session):
|
||||||
|
|
||||||
userController.modify_user(user, password, new_password)
|
userController.modify_user(user, password, new_password)
|
||||||
userController.update_user(user)
|
userController.update_user(user)
|
||||||
return "", NO_CONTENT
|
return no_content()
|
||||||
|
|
||||||
|
|
||||||
@UsersPlugin.blueprint.route("/notifications", methods=["GET"])
|
@UsersPlugin.blueprint.route("/notifications", methods=["GET"])
|
||||||
|
|
Loading…
Reference in New Issue