Skip to content
Snippets Groups Projects
Select Git revision
  • b80a5bf7c004c68410786bdd97acaf9441f7c0d9
  • develop default
  • master protected
  • feature/frontend-tests
  • 0.107
  • 0.106
  • 0.105
  • 0.104
  • 0.103
  • 0.102
  • 0.101
  • 0.100
  • 0.99
  • 0.98
  • 0.97
  • 0.96
  • 0.95
  • 0.94
  • 0.93
  • 0.92
  • 0.91
  • 0.90
  • 0.89
  • 0.88
24 results

user.py

Blame
  • Bjarke Madsen's avatar
    Bjarke Madsen authored
    3edc352f
    History
    user.py 4.94 KiB
    import logging
    from typing import Any, Union
    
    from flask import Blueprint, jsonify, request
    from flask_login import current_user, AnonymousUserMixin, login_required  # type: ignore
    from sqlalchemy import select
    
    from compendium_v2.auth.session_management import admin_required
    from compendium_v2.db import db
    from compendium_v2.db.auth_model import User, ROLES
    from compendium_v2.db.model import NREN
    from compendium_v2.routes import common
    
    routes = Blueprint('user', __name__)
    logger = logging.getLogger(__name__)
    
    USER_RESPONSE_SCHEMA = {
        '$schema': 'http://json-schema.org/draft-07/schema#',
    
        'definitions': {
            'permissions': {
                'type': 'object',
                'properties': {
                    'admin': {'type': 'boolean'},
                    'active': {'type': 'boolean'},
                },
                'required': ['admin', 'active'],
                'additionalProperties': False
            },
            'user': {
                'type': 'object',
                'properties': {
                    'name': {'type': ['string', 'null']},
                    'email': {'type': ['string', 'null']},
                    'permissions': {'$ref': '#/definitions/permissions'},
                    'id': {'type': 'uuid'},
                    'role': {'type': 'string'},
                    'oidc_sub': {'type': 'string'},
                    'nrens': {
                        'type': 'array',
                        'items': {'type': 'string'}
                    }
                },
                'required': ['permissions'],
                'additionalProperties': False
            }
        },
    
        'type': 'array',
        'items': {'$ref': '#/definitions/charging'}
    }
    
    
    def _extract_user(user: Union[User, AnonymousUserMixin]):
        if isinstance(user, AnonymousUserMixin):
            return {
                'permissions': {
                    'admin': False,
                    'active': False,
                }
            }
        return {
            'name': user.fullname,
            'email': user.email,
            'permissions': {
                'admin': user.roles == ROLES.admin,
                'active': user.active,
            },
            'id': user.id,
            'role': user.roles.value,
            'oidc_sub': user.oidc_sub,
            'nrens': [nren.name for nren in user.nrens]
        }
    
    
    @routes.route('/', methods=['GET'])
    @common.require_accepts_json
    def current_user_view() -> Any:
        """
        handler for /api/user/ requests
    
        response will be formatted as:
    
        .. asjson::
            compendium_v2.routes.user.USER_RESPONSE_SCHEMA
    
        :return:
        """
    
        return jsonify(_extract_user(current_user))
    
    
    @routes.route('/list', methods=['GET'])
    @common.require_accepts_json
    @login_required
    @admin_required
    def all_users_view() -> Any:
        # TODO schema and docstring
    
        entries = [_extract_user(user) for user in db.session.scalars(
            select(User).order_by(User.email)).unique()]
        return jsonify(entries)
    
    
    @routes.route('/', methods=['PUT'])
    @common.require_accepts_json
    @login_required
    @admin_required
    def update_user_view() -> Any:
        """
        Handler for updating user information via PUT request.
    
        Request data should be in JSON format with the fields you want to update.
        The response will be formatted the same way as in the current_user_view.
    
        Example JSON request data:
        {
            "name": "Updated Name",
            "email": "updated@example.com",
            "roles": ["role1", "role2"],
            "active": False
        }
    
        :return:
        """
    
        def _update_user_data(user: User, update_data: dict):
    
            new_roles = update_data.get('roles', user.roles.value)
    
            if new_roles != user.roles.value:
                if user == current_user:
                    return jsonify({'success': False, 'message': 'Cannot change your own role.'}), 400
    
                user.roles = new_roles
    
            if 'active' in update_data:
                _active = bool(update_data['active'])
                if _active != user.active:
                    if user == current_user:
                        return jsonify({'success': False, 'message': 'Cannot deactivate yourself.'}), 400
    
                    user.active = _active
    
            nrens = update_data.get('nrens', None)
            if nrens is not None:
                new_nrens = None
                try:
                    new_nrens = db.session.scalars(select(NREN).filter(NREN.id.in_(update_data['nrens']))).all()
                    user.nrens = [nren for nren in new_nrens]
                    db.session.commit()
                except Exception:
                    return jsonify({'success': False, 'message': 'No valid NREN IDs provided.'}), 400
    
            return jsonify({'success': True, 'message': 'User updated successfully'})
    
        body = request.get_json()
        if not body:
            return jsonify({"success": False, 'message': 'Invalid request'}), 400
    
        user_id = body.get("id")
        if not user_id:
            return jsonify({"success": False, 'message': 'No user ID provided in the request data.'}), 400
    
        user = db.session.execute(select(User).filter_by(id=user_id)).scalar()
    
        if not user:
            return jsonify({"success": False, 'message': 'User not found.'}), 404
    
        return _update_user_data(user, body)