Exemplo n.º 1
0
class UserController(Controller):
    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(
        WorkspaceDigestSchema(many=True), )
    def user_workspace(self, context, request: TracimRequest, hapic_data=None):
        """
        Get list of user workspaces
        """
        app_config = request.registry.settings['CFG']
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )

        workspaces = wapi.get_all_for_user(request.candidate_user)
        return [
            wapi.get_workspace_with_context(workspace)
            for workspace in workspaces
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def user(self, context, request: TracimRequest, hapic_data=None):
        """
        Get user infos.
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        return uapi.get_user_with_context(request.candidate_user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @require_profile(Group.TIM_ADMIN)
    @hapic.output_body(UserDigestSchema(many=True))
    def users(self, context, request: TracimRequest, hapic_data=None):
        """
        Get all users
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        users = uapi.get_all()
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_MANAGER)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(KnownMemberQuerySchema(),
                       as_list=['exclude_user_ids',
                                'exclude_workspace_ids'])  # nopep8
    @hapic.output_body(UserDigestSchema(many=True))
    def known_members(self, context, request: TracimRequest, hapic_data=None):
        """
        Get known users list
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deactivated=False,
        )
        users = uapi.get_known_user(
            acp=hapic_data.query.acp,
            exclude_user_ids=hapic_data.query.exclude_user_ids,
            exclude_workspace_ids=hapic_data.query.exclude_workspace_ids,
        )
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(EmailAlreadyExistInDb, HTTPStatus.BAD_REQUEST)
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_body(SetEmailSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_email(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user Email
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        user = uapi.set_email(request.candidate_user,
                              hapic_data.body.loggedin_user_password,
                              hapic_data.body.email,
                              do_save=True)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(PasswordDoNotMatch, HTTPStatus.BAD_REQUEST)
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_body(SetPasswordSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_user_password(self,
                          context,
                          request: TracimRequest,
                          hapic_data=None):  # nopep8
        """
        Set user password
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        uapi.set_password(request.candidate_user,
                          hapic_data.body.loggedin_user_password,
                          hapic_data.body.new_password,
                          hapic_data.body.new_password2,
                          do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_body(SetUserInfoSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_infos(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user info data
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        user = uapi.update(request.candidate_user,
                           name=hapic_data.body.public_name,
                           timezone=hapic_data.body.timezone,
                           lang=hapic_data.body.lang,
                           do_save=True)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(EmailAlreadyExistInDb, HTTPStatus.BAD_REQUEST)
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_body(UserCreationSchema())
    @hapic.output_body(UserSchema())
    def create_user(self, context, request: TracimRequest, hapic_data=None):
        """
        Create new user
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        gapi = GroupApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        groups = [gapi.get_one_with_name(hapic_data.body.profile)]
        user = uapi.create_user(email=hapic_data.body.email,
                                password=hapic_data.body.password,
                                timezone=hapic_data.body.timezone,
                                lang=hapic_data.body.lang,
                                name=hapic_data.body.public_name,
                                do_notify=hapic_data.body.email_notification,
                                groups=groups,
                                do_save=True)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def enable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        enable user
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        uapi.enable(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @hapic.handle_exception(UserCantDeleteHimself, HTTPStatus.BAD_REQUEST)
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def delete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        delete user
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        uapi.delete(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def undelete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        undelete user
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deleted=True,
        )
        uapi.undelete(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @hapic.handle_exception(UserCantDisableHimself, HTTPStatus.BAD_REQUEST)
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def disable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        disable user
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        uapi.disable(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(UserCantChangeIsOwnProfile, HTTPStatus.BAD_REQUEST)
    @require_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(SetUserProfileSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_profile(self, context, request: TracimRequest, hapic_data=None):
        """
        set user profile
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        gapi = GroupApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        groups = [gapi.get_one_with_name(hapic_data.body.profile)]
        uapi.update(
            user=request.candidate_user,
            groups=groups,
            do_save=True,
        )
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ActiveContentFilterQuerySchema())
    @hapic.output_body(ContentDigestSchema(many=True))
    def last_active_content(self,
                            context,
                            request: TracimRequest,
                            hapic_data=None):  # nopep8
        """
        Get last_active_content for user
        """
        app_config = request.registry.settings['CFG']
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        before_content = None
        if content_filter.before_content_id:
            before_content = api.get_one(
                content_id=content_filter.before_content_id,
                workspace=workspace,
                content_type=content_type_list.Any_SLUG)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=content_filter.limit or None,
            before_content=before_content,
        )
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ContentIdsQuerySchema(), as_list=['contents_ids'])
    @hapic.output_body(ReadStatusSchema(many=True))  # nopep8
    def contents_read_status(self,
                             context,
                             request: TracimRequest,
                             hapic_data=None):  # nopep8
        """
        get user_read status of contents
        """
        app_config = request.registry.settings['CFG']
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=None,
            before_content=None,
            content_ids=hapic_data.query.contents_ids or None)
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_content_as_read(self,
                            context,
                            request: TracimRequest,
                            hapic_data=None):  # nopep8
        """
        set user_read status of content to read
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_content_as_unread(self,
                              context,
                              request: TracimRequest,
                              hapic_data=None):  # nopep8
        """
        set user_read status of content to unread
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_unread(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_workspace_as_read(self,
                              context,
                              request: TracimRequest,
                              hapic_data=None):  # nopep8
        """
        set user_read status of all content of workspace to read
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read__workspace(request.current_workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def enable_workspace_notification(self,
                                      context,
                                      request: TracimRequest,
                                      hapic_data=None):  # nopep8
        """
        enable workspace notification
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.enable_notifications(request.candidate_user, workspace)
        rapi = RoleApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        role = rapi.get_one(request.candidate_user.user_id,
                            workspace.workspace_id)
        wapi.save(workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @require_same_user_or_profile(Group.TIM_ADMIN)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def disable_workspace_notification(self,
                                       context,
                                       request: TracimRequest,
                                       hapic_data=None):  # nopep8
        """
        disable workspace notification
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.disable_notifications(request.candidate_user, workspace)
        wapi.save(workspace)
        return

    def bind(self, configurator: Configurator) -> None:
        """
        Create all routes and views using pyramid configurator
        for this controller
        """

        # user workspace
        configurator.add_route('user_workspace',
                               '/users/{user_id:\d+}/workspaces',
                               request_method='GET')  # nopep8
        configurator.add_view(self.user_workspace, route_name='user_workspace')

        # user info
        configurator.add_route('user',
                               '/users/{user_id:\d+}',
                               request_method='GET')  # nopep8
        configurator.add_view(self.user, route_name='user')

        # users lists
        configurator.add_route('users', '/users',
                               request_method='GET')  # nopep8
        configurator.add_view(self.users, route_name='users')

        # known members lists
        configurator.add_route('known_members',
                               '/users/{user_id:\d+}/known_members',
                               request_method='GET')  # nopep8
        configurator.add_view(self.known_members, route_name='known_members')

        # set user email
        configurator.add_route('set_user_email',
                               '/users/{user_id:\d+}/email',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_user_email, route_name='set_user_email')

        # set user password
        configurator.add_route('set_user_password',
                               '/users/{user_id:\d+}/password',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_user_password,
                              route_name='set_user_password')  # nopep8

        # set user_info
        configurator.add_route('set_user_info',
                               '/users/{user_id:\d+}',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_user_infos, route_name='set_user_info')

        # create user
        configurator.add_route('create_user', '/users', request_method='POST')
        configurator.add_view(self.create_user, route_name='create_user')

        # enable user
        configurator.add_route('enable_user',
                               '/users/{user_id:\d+}/enabled',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.enable_user, route_name='enable_user')

        # disable user
        configurator.add_route('disable_user',
                               '/users/{user_id:\d+}/disabled',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.disable_user, route_name='disable_user')

        # delete user
        configurator.add_route('delete_user',
                               '/users/{user_id:\d+}/trashed',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.delete_user, route_name='delete_user')

        # undelete user
        configurator.add_route('undelete_user',
                               '/users/{user_id:\d+}/trashed/restore',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.undelete_user, route_name='undelete_user')

        # set user profile
        configurator.add_route('set_user_profile',
                               '/users/{user_id:\d+}/profile',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_profile, route_name='set_user_profile')

        # user content
        configurator.add_route(
            'contents_read_status',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/contents/read_status',
            request_method='GET')  # nopep8
        configurator.add_view(self.contents_read_status,
                              route_name='contents_read_status')  # nopep8
        # last active content for user
        configurator.add_route(
            'last_active_content',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/contents/recently_active',
            request_method='GET')  # nopep8
        configurator.add_view(self.last_active_content,
                              route_name='last_active_content')  # nopep8

        # set content as read/unread
        configurator.add_route(
            'read_content',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/read',
            request_method='PUT')  # nopep8
        configurator.add_view(self.set_content_as_read,
                              route_name='read_content')  # nopep8
        configurator.add_route(
            'unread_content',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/unread',
            request_method='PUT')  # nopep8
        configurator.add_view(self.set_content_as_unread,
                              route_name='unread_content')  # nopep8

        # set workspace as read
        configurator.add_route(
            'read_workspace',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/read',
            request_method='PUT')  # nopep8
        configurator.add_view(self.set_workspace_as_read,
                              route_name='read_workspace')  # nopep8

        # enable workspace notification
        configurator.add_route(
            'enable_workspace_notification',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/activate',
            request_method='PUT')  # nopep8
        configurator.add_view(
            self.enable_workspace_notification,
            route_name='enable_workspace_notification')  # nopep8

        # enable workspace notification
        configurator.add_route(
            'disable_workspace_notification',
            '/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/deactivate',
            request_method='PUT')  # nopep8
        configurator.add_view(
            self.disable_workspace_notification,
            route_name='disable_workspace_notification')  # nopep8
Exemplo n.º 2
0
class UserController(Controller):
    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(UserWorkspaceFilterQuerySchema())
    @hapic.output_body(WorkspaceSchema(many=True))
    def user_workspace(self, context, request: TracimRequest, hapic_data=None):
        """
        Get list of user workspaces
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )

        workspaces = wapi.get_all_for_user(
            request.candidate_user,
            include_owned=hapic_data.query.show_owned_workspace,
            include_with_role=hapic_data.query.show_workspace_with_role,
            parents_ids=hapic_data.query.parent_ids,
        )
        return [wapi.get_workspace_with_context(workspace) for workspace in workspaces]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(RoleAlreadyExistError, HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(WorkspaceIdSchema())
    @hapic.output_body(WorkspaceSchema())
    def join_workspace(self, context, request: TracimRequest, hapic_data=None):
        """
        Join a workspace.
        Only possible for OPEN workspaces.
        Subscribing to a ON_REQUEST workspace is done through /api/users/<user_id>/workspace_subscriptions.
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.add_current_user_as_member(workspace_id=hapic_data.body["workspace_id"])
        return wapi.get_workspace_with_context(workspace)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def user(self, context, request: TracimRequest, hapic_data=None):
        """
        Get user infos.
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        return uapi.get_user_with_context(request.candidate_user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserDiskSpaceSchema())
    def user_disk_space(self, context, request: TracimRequest, hapic_data=None):
        """
        Get user space infos.
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        return uapi.get_user_with_context(request.candidate_user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.output_body(UserDigestSchema(many=True))
    def users(self, context, request: TracimRequest, hapic_data=None):
        """
        Get all users
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        users = uapi.get_all()
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(KnownMembersQuerySchema())
    @hapic.output_body(UserDigestSchema(many=True))
    @hapic.handle_exception(CannotUseBothIncludeAndExcludeWorkspaceUsers, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(TooShortAutocompleteString, HTTPStatus.BAD_REQUEST)
    def known_members(self, context, request: TracimRequest, hapic_data=None):
        """
        Get known users list
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deactivated=False,
        )
        users = uapi.get_known_users(
            acp=hapic_data.query.acp,
            exclude_user_ids=hapic_data.query.exclude_user_ids,
            exclude_workspace_ids=hapic_data.query.exclude_workspace_ids,
            include_workspace_ids=hapic_data.query.include_workspace_ids,
            limit=hapic_data.query.limit,
            filter_results=app_config.KNOWN_MEMBERS__FILTER,
        )
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(EmailAlreadyExists, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserEmailModificationDisallowed, HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_body(SetEmailSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_email(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user Email
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        user = uapi.set_email(
            request.candidate_user,
            hapic_data.body.loggedin_user_password,
            hapic_data.body.email,
            do_save=True,
        )
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(UsernameAlreadyExists, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ReservedUsernameError, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(TracimValidationFailed, HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_body(SetUsernameSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_username(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user username
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        user = uapi.set_username(
            request.candidate_user,
            hapic_data.body.loggedin_user_password,
            hapic_data.body.username,
            do_save=True,
        )
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(PasswordDoNotMatch, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserPasswordModificationDisallowed, HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_body(SetPasswordSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_user_password(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user password
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        uapi.set_password(
            request.candidate_user,
            hapic_data.body.loggedin_user_password,
            hapic_data.body.new_password,
            hapic_data.body.new_password2,
            do_save=True,
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_body(SetUserInfoSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_infos(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user info data
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        user = uapi.update(
            request.candidate_user,
            auth_type=request.candidate_user.auth_type,
            name=hapic_data.body.public_name,
            timezone=hapic_data.body.timezone,
            lang=hapic_data.body.lang,
            do_save=True,
        )
        uapi.execute_updated_user_actions(user)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(EmailAlreadyExists, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(UsernameAlreadyExists, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ReservedUsernameError, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(TracimValidationFailed, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_body(UserCreationSchema())
    @hapic.output_body(UserSchema())
    def create_user(self, context, request: TracimRequest, hapic_data=None):
        """
        Create new user. Note: One of username or email required.
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        if hapic_data.body.profile:
            profile = Profile.get_profile_from_slug(hapic_data.body.profile)
        else:
            profile = None
        password = hapic_data.body.password
        if not password and hapic_data.body.email_notification:
            password = password_generator()

        user = uapi.create_user(
            auth_type=AuthType.UNKNOWN,
            email=hapic_data.body.email,
            password=password,
            timezone=hapic_data.body.timezone,
            lang=hapic_data.body.lang,
            name=hapic_data.body.public_name,
            username=hapic_data.body.username,
            do_notify=hapic_data.body.email_notification,
            allowed_space=hapic_data.body.allowed_space,
            profile=profile,
            do_save=True,
        )
        uapi.execute_created_user_actions(user)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def enable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        enable user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        uapi.enable(user=request.candidate_user, do_save=True)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @hapic.handle_exception(UserCantDeleteHimself, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def delete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        delete user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        uapi.delete(user=request.candidate_user, do_save=True)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def undelete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        undelete user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deleted=True,
        )
        uapi.undelete(user=request.candidate_user, do_save=True)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @hapic.handle_exception(UserCantDisableHimself, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def disable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        disable user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        uapi.disable(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(UserCantChangeIsOwnProfile, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(SetUserProfileSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_profile(self, context, request: TracimRequest, hapic_data=None):
        """
        set user profile
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        profile = Profile.get_profile_from_slug(hapic_data.body.profile)
        uapi.update(
            user=request.candidate_user,
            auth_type=request.candidate_user.auth_type,
            profile=profile,
            do_save=True,
        )
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(SetUserAllowedSpaceSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_allowed_space(self, context, request: TracimRequest, hapic_data=None):
        """
        set user allowed_space
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user, session=request.dbsession, config=app_config  # User
        )
        uapi.update(
            user=request.candidate_user,
            auth_type=request.candidate_user.auth_type,
            allowed_space=hapic_data.body.allowed_space,
            do_save=True,
        )
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ActiveContentFilterQuerySchema())
    @hapic.output_body(ContentDigestSchema(many=True))
    def last_active_content(self, context, request: TracimRequest, hapic_data=None):
        """
        Get last_active_content for user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        before_content = None
        if content_filter.before_content_id:
            before_content = api.get_one(
                content_id=content_filter.before_content_id,
                workspace=workspace,
                content_type=content_type_list.Any_SLUG,
            )
        last_actives = api.get_last_active(
            workspace=workspace, limit=content_filter.limit or None, before_content=before_content
        )
        return [api.get_content_in_context(content) for content in last_actives]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ContentIdsQuerySchema())
    @hapic.output_body(ReadStatusSchema(many=True))
    def contents_read_status(self, context, request: TracimRequest, hapic_data=None):
        """
        get user_read status of contents
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=None,
            before_content=None,
            content_ids=hapic_data.query.content_ids or None,
        )
        return [api.get_content_in_context(content) for content in last_actives]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_content_as_read(self, context, request: TracimRequest, hapic_data=None):
        """
        set user_read status of content to read
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read(request.current_content, do_flush=True)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_content_as_unread(self, context, request: TracimRequest, hapic_data=None):
        """
        set user_read status of content to unread
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_unread(request.current_content, do_flush=True)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_workspace_as_read(self, context, request: TracimRequest, hapic_data=None):
        """
        set user_read status of all content of workspace to read
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read__workspace(request.current_workspace)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def enable_workspace_notification(self, context, request: TracimRequest, hapic_data=None):
        """
        enable workspace notification
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.enable_notifications(request.candidate_user, workspace)
        wapi.save(workspace)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def disable_workspace_notification(self, context, request: TracimRequest, hapic_data=None):
        """
        disable workspace notification
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.disable_notifications(request.candidate_user, workspace)
        wapi.save(workspace)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(GetLiveMessageQuerySchema())
    @hapic.output_body(LiveMessageSchemaPage())
    def get_user_messages(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> PaginatedObject:
        """
        Returns user messages matching the given query
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        event_api = EventApi(request.current_user, request.dbsession, app_config)
        return PaginatedObject(
            event_api.get_paginated_messages_for_user(
                user_id=request.candidate_user.user_id,
                read_status=hapic_data.query.read_status,
                page_token=hapic_data.query.page_token,
                count=hapic_data.query.count,
                exclude_author_ids=hapic_data.query.exclude_author_ids,
                include_event_types=hapic_data.query.include_event_types,
                exclude_event_types=hapic_data.query.exclude_event_types,
                workspace_ids=hapic_data.query.workspace_ids,
                include_not_sent=hapic_data.query.include_not_sent,
                related_to_content_ids=hapic_data.query.related_to_content_ids,
            )
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(UserMessagesSummaryQuerySchema())
    @hapic.output_body(UserMessagesSummarySchema())
    def get_user_messages_summary(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> UserMessagesSummary:
        """
        Returns a summary about messages filtered
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        event_api = EventApi(request.current_user, request.dbsession, app_config)
        candidate_user = UserApi(
            request.current_user, request.dbsession, app_config
        ).get_user_with_context(request.candidate_user)
        unread_messages_count = event_api.get_messages_count(
            user_id=candidate_user.user_id,
            read_status=ReadStatus.UNREAD,
            include_event_types=hapic_data.query.include_event_types,
            exclude_event_types=hapic_data.query.exclude_event_types,
            exclude_author_ids=hapic_data.query.exclude_author_ids,
            include_not_sent=hapic_data.query.include_not_sent,
            workspace_ids=hapic_data.query.workspace_ids,
            related_to_content_ids=hapic_data.query.related_to_content_ids,
        )
        read_messages_count = event_api.get_messages_count(
            user_id=candidate_user.user_id,
            read_status=ReadStatus.READ,
            include_event_types=hapic_data.query.include_event_types,
            exclude_event_types=hapic_data.query.exclude_event_types,
            exclude_author_ids=hapic_data.query.exclude_author_ids,
            include_not_sent=hapic_data.query.include_not_sent,
            workspace_ids=hapic_data.query.workspace_ids,
            related_to_content_ids=hapic_data.query.related_to_content_ids,
        )
        return UserMessagesSummary(
            user=candidate_user,
            unread_messages_count=unread_messages_count,
            read_messages_count=read_messages_count,
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_all_user_messages_as_read(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> None:
        """
        Read all unread message for user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        event_api = EventApi(request.current_user, request.dbsession, app_config)
        event_api.mark_user_messages_as_read(request.candidate_user.user_id)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @hapic.handle_exception(MessageDoesNotExist, http_code=HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_path(MessageIdsPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_message_as_read(self, context, request: TracimRequest, hapic_data: HapicData) -> None:
        """
        Read one message
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        event_api = EventApi(request.current_user, request.dbsession, app_config)
        event_api.mark_user_message_as_read(
            event_id=hapic_data.path.event_id, user_id=request.candidate_user.user_id
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @hapic.handle_exception(MessageDoesNotExist, http_code=HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_path(MessageIdsPathSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_message_as_unread(self, context, request: TracimRequest, hapic_data: HapicData) -> None:
        """
        unread one message
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        event_api = EventApi(request.current_user, request.dbsession, app_config)
        event_api.mark_user_message_as_unread(
            event_id=hapic_data.path.event_id, user_id=request.candidate_user.user_id
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_EVENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_headers(TracimLiveEventHeaderSchema())
    @hapic.input_query(TracimLiveEventQuerySchema())
    def open_message_stream(self, context, request: TracimRequest, hapic_data) -> Response:
        """
        Open the message stream for the given user.
        Tracim Live Message Events as ServerSide Event Stream
        """
        stream_opened_event = ":Tracim Live Messages for user {}\n\nevent: stream-open\ndata:\n\n".format(
            str(request.candidate_user.user_id)
        )

        after_event_id = hapic_data.query["after_event_id"]  # type: int
        if after_event_id:
            app_config = request.registry.settings["CFG"]  # type: CFG
            event_api = EventApi(request.current_user, request.dbsession, app_config)
            messages = event_api.get_messages_for_user(
                request.candidate_user.user_id, after_event_id=after_event_id
            )  # type: typing.List[Message]

            stream_opened_event += "".join(
                [
                    "data:" + json.dumps(LiveMessagesLib.message_as_dict(message)) + "\n\n"
                    for message in messages
                ]
            )

        escaped_keepalive_event = "event: keep-alive\\ndata:\\n\\n"
        user_channel_name = LiveMessagesLib.user_grip_channel(request.candidate_user.user_id)
        headers = [
            # Here we ask push pin to keep the connection open
            ("Grip-Hold", "stream"),
            # and register this connection on the given channel
            # multiple channels subscription is possible
            ("Grip-Channel", user_channel_name),
            ("Grip-Keep-Alive", "{}; format=cstring; timeout=30".format(escaped_keepalive_event)),
            # content type for SSE
            ("Content-Type", "text/event-stream"),
            # do not cache the events
            ("Cache-Control", "no-cache"),
        ]
        return Response(
            headerlist=headers, charset="utf-8", status_code=200, body=stream_opened_event
        )

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONFIG_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserConfigSchema())
    def get_user_config(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> typing.Dict:
        """
        get all the configuration parameters for the given user
        """
        config_api = UserConfigApi(current_user=request.candidate_user, session=request.dbsession)
        return {"parameters": config_api.get_all_params()}

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONFIG_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(SetConfigSchema())
    @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)
    def set_user_config(self, context, request: TracimRequest, hapic_data: HapicData) -> None:
        """
        Set or update the given configuration parameters for the given user
        The behavior of this endpoint is adding/updating key (patch-like) but not replacing the
        whole configuration, so it's not possible to remove keys through this endpoint.
        """
        config_api = UserConfigApi(current_user=request.candidate_user, session=request.dbsession)
        config_api.set_params(params=hapic_data.body["parameters"])

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONFIG_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(WorkspaceSchema(many=True))
    def get_accessible_workspaces(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> typing.List[WorkspaceInContext]:
        """
        Return the list of accessible workspaces by the given user id.
        An accessible workspace is:
          - a workspace the user is not member of (`workspaces` API returns them)
          - has an OPEN or ON_REQUEST access type
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user, session=request.dbsession, config=app_config,
        )

        workspaces = wapi.get_all_accessible_by_user(request.candidate_user)
        return [wapi.get_workspace_with_context(workspace) for workspace in workspaces]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_SUBSCRIPTIONS_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(WorkspaceSubscriptionSchema(many=True))
    def user_subscriptions(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> typing.List[WorkspaceSubscription]:
        subscription_lib = SubscriptionLib(
            current_user=request.current_user, session=request.dbsession, config=request.app_config,
        )
        return subscription_lib.get_user_subscription(request.candidate_user.user_id)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_SUBSCRIPTIONS_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.handle_exception(InvalidWorkspaceAccessType, HTTPStatus.BAD_REQUEST)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(WorkspaceIdSchema())
    @hapic.output_body(WorkspaceSubscriptionSchema())
    def submit_subscription(
        self, context, request: TracimRequest, hapic_data: HapicData
    ) -> typing.List[WorkspaceSubscription]:
        workspace = WorkspaceApi(
            current_user=None, session=request.dbsession, config=request.app_config
        ).get_one(hapic_data.body["workspace_id"])
        subscription_lib = SubscriptionLib(
            current_user=request.current_user, session=request.dbsession, config=request.app_config,
        )
        return subscription_lib.submit_subscription(workspace=workspace)

    def bind(self, configurator: Configurator) -> None:
        """
        Create all routes and views using pyramid configurator
        for this controller
        """

        # user workspace
        configurator.add_route(
            "get_user_workspace",
            "/users/{user_id:\d+}/workspaces",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.user_workspace, route_name="get_user_workspace")
        configurator.add_route(
            "post_user_workspace",
            "/users/{user_id:\d+}/workspaces",
            request_method="POST",  # noqa: W605
        )
        configurator.add_view(self.join_workspace, route_name="post_user_workspace")

        # user info
        configurator.add_route("user", "/users/{user_id:\d+}", request_method="GET")  # noqa: W605
        configurator.add_view(self.user, route_name="user")

        # user space info
        configurator.add_route(
            "user_disk_space", "/users/{user_id:\d+}/disk_space", request_method="GET"
        )  # noqa: W605
        configurator.add_view(self.user_disk_space, route_name="user_disk_space")

        # users lists
        configurator.add_route("users", "/users", request_method="GET")
        configurator.add_view(self.users, route_name="users")

        # known members lists
        configurator.add_route(
            "known_members",
            "/users/{user_id:\d+}/known_members",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.known_members, route_name="known_members")

        # set user email
        configurator.add_route(
            "set_user_email", "/users/{user_id:\d+}/email", request_method="PUT"
        )  # noqa: W605
        configurator.add_view(self.set_user_email, route_name="set_user_email")

        # set user username
        configurator.add_route(
            "set_user_username", "/users/{user_id:\d+}/username", request_method="PUT"
        )  # noqa: W605
        configurator.add_view(self.set_user_username, route_name="set_user_username")

        # set user password
        configurator.add_route(
            "set_user_password", "/users/{user_id:\d+}/password", request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.set_user_password, route_name="set_user_password")

        # set user_info
        configurator.add_route(
            "set_user_info", "/users/{user_id:\d+}", request_method="PUT"
        )  # noqa: W605
        configurator.add_view(self.set_user_infos, route_name="set_user_info")

        # create user
        configurator.add_route("create_user", "/users", request_method="POST")
        configurator.add_view(self.create_user, route_name="create_user")

        # enable user
        configurator.add_route(
            "enable_user", "/users/{user_id:\d+}/enabled", request_method="PUT"
        )  # noqa: W605
        configurator.add_view(self.enable_user, route_name="enable_user")

        # disable user
        configurator.add_route(
            "disable_user", "/users/{user_id:\d+}/disabled", request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.disable_user, route_name="disable_user")

        # delete user
        configurator.add_route(
            "delete_user", "/users/{user_id:\d+}/trashed", request_method="PUT"
        )  # noqa: W605
        configurator.add_view(self.delete_user, route_name="delete_user")

        # undelete user
        configurator.add_route(
            "undelete_user",
            "/users/{user_id:\d+}/trashed/restore",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.undelete_user, route_name="undelete_user")

        # set user profile
        configurator.add_route(
            "set_user_profile", "/users/{user_id:\d+}/profile", request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.set_profile, route_name="set_user_profile")

        # set user allowed_space
        configurator.add_route(
            "set_user_allowed_space",
            "/users/{user_id:\d+}/allowed_space",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.set_allowed_space, route_name="set_user_allowed_space")

        # user content
        configurator.add_route(
            "contents_read_status",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/read_status",  # noqa: W605
            request_method="GET",
        )
        configurator.add_view(self.contents_read_status, route_name="contents_read_status")
        # last active content for user
        configurator.add_route(
            "last_active_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/recently_active",  # noqa: W605
            request_method="GET",
        )
        configurator.add_view(self.last_active_content, route_name="last_active_content")

        # set content as read/unread
        configurator.add_route(
            "read_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/read",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_content_as_read, route_name="read_content")
        configurator.add_route(
            "unread_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/unread",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_content_as_unread, route_name="unread_content")

        # set workspace as read
        configurator.add_route(
            "read_workspace",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/read",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_workspace_as_read, route_name="read_workspace")

        # enable workspace notification
        configurator.add_route(
            "enable_workspace_notification",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/activate",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(
            self.enable_workspace_notification, route_name="enable_workspace_notification"
        )

        # enable workspace notification
        configurator.add_route(
            "disable_workspace_notification",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/deactivate",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(
            self.disable_workspace_notification, route_name="disable_workspace_notification"
        )
        # TracimLiveMessages notification
        configurator.add_route(
            "live_messages",
            "/users/{user_id:\d+}/live_messages",  # noqa: W605
            request_method="GET",
        )
        configurator.add_view(self.open_message_stream, route_name="live_messages")

        # Tracim user messages
        configurator.add_route(
            "messages", "/users/{user_id:\d+}/messages", request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.get_user_messages, route_name="messages")

        configurator.add_route(
            "messages_summary",
            "/users/{user_id:\d+}/messages/summary",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.get_user_messages_summary, route_name="messages_summary")

        # read all unread messages for user
        configurator.add_route(
            "read_messages",
            "/users/{user_id:\d+}/messages/read",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.set_all_user_messages_as_read, route_name="read_messages")

        # read all unread messages for user
        configurator.add_route(
            "read_message",
            "/users/{user_id:\d+}/messages/{event_id:\d+}/read",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.set_message_as_read, route_name="read_message")

        # read all unread messages for user
        configurator.add_route(
            "unread_message",
            "/users/{user_id:\d+}/messages/{event_id:\d+}/unread",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.set_message_as_unread, route_name="unread_message")

        # User configuration
        configurator.add_route(
            "config_get", "/users/{user_id:\d+}/config", request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.get_user_config, route_name="config_get")

        configurator.add_route(
            "config_post", "/users/{user_id:\d+}/config", request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.set_user_config, route_name="config_post")

        # User accessible workspaces (not member of, but can see information about them to subscribe)
        configurator.add_route(
            "get_accessible_workspaces",
            "/users/{user_id:\d+}/accessible_workspaces",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(
            self.get_accessible_workspaces, route_name="get_accessible_workspaces"
        )

        # User subscriptions
        configurator.add_route(
            "subscriptions_get",
            "/users/{user_id:\d+}/workspace_subscriptions",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.user_subscriptions, route_name="subscriptions_get")

        configurator.add_route(
            "subscriptions_put",
            "/users/{user_id:\d+}/workspace_subscriptions",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.submit_subscription, route_name="subscriptions_put")
Exemplo n.º 3
0
class UserController(Controller):
    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(WorkspaceDigestSchema(many=True))
    def user_workspace(self, context, request: TracimRequest, hapic_data=None):
        """
        Get list of user workspaces
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )

        workspaces = wapi.get_all_for_user(request.candidate_user)
        return [
            wapi.get_workspace_with_context(workspace)
            for workspace in workspaces
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def user(self, context, request: TracimRequest, hapic_data=None):
        """
        Get user infos.
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        return uapi.get_user_with_context(request.candidate_user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.output_body(UserDigestSchema(many=True))
    def users(self, context, request: TracimRequest, hapic_data=None):
        """
        Get all users
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        users = uapi.get_all()
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_query(KnownMemberQuerySchema())
    @hapic.output_body(UserDigestSchema(many=True))
    def known_members(self, context, request: TracimRequest, hapic_data=None):
        """
        Get known users list
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deactivated=False,
        )
        users = uapi.get_known_user(
            acp=hapic_data.query.acp,
            exclude_user_ids=hapic_data.query.exclude_user_ids,
            exclude_workspace_ids=hapic_data.query.exclude_workspace_ids,
        )
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(EmailAlreadyExistInDb, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserEmailModificationDisallowed,
                            HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_body(SetEmailSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_email(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user Email
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        user = uapi.set_email(
            request.candidate_user,
            hapic_data.body.loggedin_user_password,
            hapic_data.body.email,
            do_save=True,
        )
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(PasswordDoNotMatch, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserPasswordModificationDisallowed,
                            HTTPStatus.BAD_REQUEST)
    @check_right(has_personal_access)
    @hapic.input_body(SetPasswordSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def set_user_password(self,
                          context,
                          request: TracimRequest,
                          hapic_data=None):
        """
        Set user password
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        uapi.set_password(
            request.candidate_user,
            hapic_data.body.loggedin_user_password,
            hapic_data.body.new_password,
            hapic_data.body.new_password2,
            do_save=True,
        )
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_body(SetUserInfoSchema())
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(UserSchema())
    def set_user_infos(self, context, request: TracimRequest, hapic_data=None):
        """
        Set user info data
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        user = uapi.update(
            request.candidate_user,
            auth_type=request.candidate_user.auth_type,
            name=hapic_data.body.public_name,
            timezone=hapic_data.body.timezone,
            lang=hapic_data.body.lang,
            do_save=True,
        )
        uapi.execute_updated_user_actions(user)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(EmailAlreadyExistInDb, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_body(UserCreationSchema())
    @hapic.output_body(UserSchema())
    def create_user(self, context, request: TracimRequest, hapic_data=None):
        """
        Create new user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        gapi = GroupApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        groups = [gapi.get_one_with_name(hapic_data.body.profile)]
        password = hapic_data.body.password
        if not password and hapic_data.body.email_notification:
            password = password_generator()

        user = uapi.create_user(
            auth_type=AuthType.UNKNOWN,
            email=hapic_data.body.email,
            password=password,
            timezone=hapic_data.body.timezone,
            lang=hapic_data.body.lang,
            name=hapic_data.body.public_name,
            do_notify=hapic_data.body.email_notification,
            groups=groups,
            do_save=True,
        )
        uapi.execute_created_user_actions(user)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def enable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        enable user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        uapi.enable(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @hapic.handle_exception(UserCantDeleteHimself, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def delete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        delete user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        uapi.delete(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_TRASH_AND_RESTORE_ENDPOINTS])
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def undelete_user(self, context, request: TracimRequest, hapic_data=None):
        """
        undelete user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deleted=True,
        )
        uapi.undelete(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENABLE_AND_DISABLE_ENDPOINTS])
    @hapic.handle_exception(UserCantDisableHimself, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def disable_user(self, context, request: TracimRequest, hapic_data=None):
        """
        disable user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        uapi.disable(user=request.candidate_user, do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
    @hapic.handle_exception(UserCantChangeIsOwnProfile, HTTPStatus.BAD_REQUEST)
    @check_right(is_administrator)
    @hapic.input_path(UserIdPathSchema())
    @hapic.input_body(SetUserProfileSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def set_profile(self, context, request: TracimRequest, hapic_data=None):
        """
        set user profile
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        uapi = UserApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        gapi = GroupApi(
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config  # User
        )
        groups = [gapi.get_one_with_name(hapic_data.body.profile)]
        uapi.update(
            user=request.candidate_user,
            auth_type=request.candidate_user.auth_type,
            groups=groups,
            do_save=True,
        )
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ActiveContentFilterQuerySchema())
    @hapic.output_body(ContentDigestSchema(many=True))
    def last_active_content(self,
                            context,
                            request: TracimRequest,
                            hapic_data=None):
        """
        Get last_active_content for user
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        before_content = None
        if content_filter.before_content_id:
            before_content = api.get_one(
                content_id=content_filter.before_content_id,
                workspace=workspace,
                content_type=content_type_list.Any_SLUG,
            )
        last_actives = api.get_last_active(workspace=workspace,
                                           limit=content_filter.limit or None,
                                           before_content=before_content)
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.input_query(ContentIdsQuerySchema())
    @hapic.output_body(ReadStatusSchema(many=True))
    def contents_read_status(self,
                             context,
                             request: TracimRequest,
                             hapic_data=None):
        """
        get user_read status of contents
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=None,
            before_content=None,
            content_ids=hapic_data.query.content_ids or None,
        )
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def set_content_as_read(self,
                            context,
                            request: TracimRequest,
                            hapic_data=None):
        """
        set user_read status of content to read
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def set_content_as_unread(self,
                              context,
                              request: TracimRequest,
                              hapic_data=None):
        """
        set user_read status of content to unread
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_unread(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_CONTENT_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def set_workspace_as_read(self,
                              context,
                              request: TracimRequest,
                              hapic_data=None):
        """
        set user_read status of all content of workspace to read
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.candidate_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read__workspace(request.current_workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def enable_workspace_notification(self,
                                      context,
                                      request: TracimRequest,
                                      hapic_data=None):
        """
        enable workspace notification
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.enable_notifications(request.candidate_user, workspace)
        wapi.save(workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_NOTIFICATION_ENDPOINTS])
    @check_right(has_personal_access)
    @hapic.input_path(UserWorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)
    def disable_workspace_notification(self,
                                       context,
                                       request: TracimRequest,
                                       hapic_data=None):
        """
        disable workspace notification
        """
        app_config = request.registry.settings["CFG"]  # type: CFG
        wapi = WorkspaceApi(
            current_user=request.candidate_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.disable_notifications(request.candidate_user, workspace)
        wapi.save(workspace)
        return

    def bind(self, configurator: Configurator) -> None:
        """
        Create all routes and views using pyramid configurator
        for this controller
        """

        # user workspace
        configurator.add_route(
            "user_workspace",
            "/users/{user_id:\d+}/workspaces",
            request_method="GET"  # noqa: W605
        )
        configurator.add_view(self.user_workspace, route_name="user_workspace")

        # user info
        configurator.add_route("user",
                               "/users/{user_id:\d+}",
                               request_method="GET")  # noqa: W605
        configurator.add_view(self.user, route_name="user")

        # users lists
        configurator.add_route("users", "/users", request_method="GET")
        configurator.add_view(self.users, route_name="users")

        # known members lists
        configurator.add_route(
            "known_members",
            "/users/{user_id:\d+}/known_members",
            request_method="GET",  # noqa: W605
        )
        configurator.add_view(self.known_members, route_name="known_members")

        # set user email
        configurator.add_route("set_user_email",
                               "/users/{user_id:\d+}/email",
                               request_method="PUT")  # noqa: W605
        configurator.add_view(self.set_user_email, route_name="set_user_email")

        # set user password
        configurator.add_route(
            "set_user_password",
            "/users/{user_id:\d+}/password",
            request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.set_user_password,
                              route_name="set_user_password")

        # set user_info
        configurator.add_route("set_user_info",
                               "/users/{user_id:\d+}",
                               request_method="PUT")  # noqa: W605
        configurator.add_view(self.set_user_infos, route_name="set_user_info")

        # create user
        configurator.add_route("create_user", "/users", request_method="POST")
        configurator.add_view(self.create_user, route_name="create_user")

        # enable user
        configurator.add_route("enable_user",
                               "/users/{user_id:\d+}/enabled",
                               request_method="PUT")  # noqa: W605
        configurator.add_view(self.enable_user, route_name="enable_user")

        # disable user
        configurator.add_route(
            "disable_user",
            "/users/{user_id:\d+}/disabled",
            request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.disable_user, route_name="disable_user")

        # delete user
        configurator.add_route("delete_user",
                               "/users/{user_id:\d+}/trashed",
                               request_method="PUT")  # noqa: W605
        configurator.add_view(self.delete_user, route_name="delete_user")

        # undelete user
        configurator.add_route(
            "undelete_user",
            "/users/{user_id:\d+}/trashed/restore",
            request_method="PUT",  # noqa: W605
        )
        configurator.add_view(self.undelete_user, route_name="undelete_user")

        # set user profile
        configurator.add_route(
            "set_user_profile",
            "/users/{user_id:\d+}/profile",
            request_method="PUT"  # noqa: W605
        )
        configurator.add_view(self.set_profile, route_name="set_user_profile")

        # user content
        configurator.add_route(
            "contents_read_status",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/read_status",  # noqa: W605
            request_method="GET",
        )
        configurator.add_view(self.contents_read_status,
                              route_name="contents_read_status")
        # last active content for user
        configurator.add_route(
            "last_active_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/recently_active",  # noqa: W605
            request_method="GET",
        )
        configurator.add_view(self.last_active_content,
                              route_name="last_active_content")

        # set content as read/unread
        configurator.add_route(
            "read_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/read",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_content_as_read,
                              route_name="read_content")
        configurator.add_route(
            "unread_content",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/contents/{content_id}/unread",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_content_as_unread,
                              route_name="unread_content")

        # set workspace as read
        configurator.add_route(
            "read_workspace",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/read",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.set_workspace_as_read,
                              route_name="read_workspace")

        # enable workspace notification
        configurator.add_route(
            "enable_workspace_notification",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/activate",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.enable_workspace_notification,
                              route_name="enable_workspace_notification")

        # enable workspace notification
        configurator.add_route(
            "disable_workspace_notification",
            "/users/{user_id:\d+}/workspaces/{workspace_id}/notifications/deactivate",  # noqa: W605
            request_method="PUT",
        )
        configurator.add_view(self.disable_workspace_notification,
                              route_name="disable_workspace_notification")
Exemplo n.º 4
0
class AccountController(Controller):
    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_ENDPOINTS])
    @check_right(is_user)
    @hapic.output_body(UserSchema())
    def account(self, context, request: TracimRequest, hapic_data=None):
        """
        Get user infos.
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        return uapi.get_user_with_context(request.current_user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_body(SetUserInfoSchema())
    @hapic.output_body(UserSchema())
    def set_account_infos(self,
                          context,
                          request: TracimRequest,
                          hapic_data=None):
        """
        Set user info data
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        user = uapi.update(request.current_user,
                           name=hapic_data.body.public_name,
                           timezone=hapic_data.body.timezone,
                           lang=hapic_data.body.lang,
                           do_save=True)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_query(KnownMemberQuerySchema())
    @hapic.output_body(UserDigestSchema(many=True))
    def account_known_members(self,
                              context,
                              request: TracimRequest,
                              hapic_data=None):
        """
        Get known users list
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
            show_deactivated=False,
        )
        users = uapi.get_known_user(
            acp=hapic_data.query.acp,
            exclude_user_ids=hapic_data.query.exclude_user_ids,
            exclude_workspace_ids=hapic_data.query.exclude_workspace_ids,
        )
        context_users = [uapi.get_user_with_context(user) for user in users]
        return context_users

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(EmailAlreadyExistInDb, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserEmailModificationDisallowed,
                            HTTPStatus.BAD_REQUEST)  # nopep8
    @check_right(is_user)
    @hapic.input_body(SetEmailSchema())
    @hapic.output_body(UserSchema())
    def set_account_email(self,
                          context,
                          request: TracimRequest,
                          hapic_data=None):
        """
        Set user Email
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        user = uapi.set_email(request.current_user,
                              hapic_data.body.loggedin_user_password,
                              hapic_data.body.email,
                              do_save=True)
        return uapi.get_user_with_context(user)

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_ENDPOINTS])
    @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
    @hapic.handle_exception(PasswordDoNotMatch, HTTPStatus.BAD_REQUEST)
    @hapic.handle_exception(ExternalAuthUserPasswordModificationDisallowed,
                            HTTPStatus.BAD_REQUEST)  # nopep8
    @check_right(is_user)
    @hapic.input_body(SetPasswordSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_account_password(self,
                             context,
                             request: TracimRequest,
                             hapic_data=None):  # nopep8
        """
        Set user password
        """
        app_config = request.registry.settings['CFG']
        uapi = UserApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        uapi.set_password(request.current_user,
                          hapic_data.body.loggedin_user_password,
                          hapic_data.body.new_password,
                          hapic_data.body.new_password2,
                          do_save=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.output_body(
        WorkspaceDigestSchema(many=True), )
    def account_workspace(self,
                          context,
                          request: TracimRequest,
                          hapic_data=None):
        """
        Get list of auth user workspaces
        """
        app_config = request.registry.settings['CFG']
        wapi = WorkspaceApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )

        workspaces = wapi.get_all_for_user(request.current_user)
        return [
            wapi.get_workspace_with_context(workspace)
            for workspace in workspaces
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceIdPathSchema())
    @hapic.input_query(ActiveContentFilterQuerySchema())
    @hapic.output_body(ContentDigestSchema(many=True))
    def account_last_active_content(self,
                                    context,
                                    request: TracimRequest,
                                    hapic_data=None):  # nopep8
        """
        Get last_active_content for user
        """
        app_config = request.registry.settings['CFG']
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        before_content = None
        if content_filter.before_content_id:
            before_content = api.get_one(
                content_id=content_filter.before_content_id,
                workspace=workspace,
                content_type=content_type_list.Any_SLUG)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=content_filter.limit or None,
            before_content=before_content,
        )
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceIdPathSchema())
    @hapic.input_query(ContentIdsQuerySchema())
    @hapic.output_body(ReadStatusSchema(many=True))  # nopep8
    def account_contents_read_status(self,
                                     context,
                                     request: TracimRequest,
                                     hapic_data=None):  # nopep8
        """
        get user_read status of contents
        """
        app_config = request.registry.settings['CFG']
        content_filter = hapic_data.query
        api = ContentApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = None
        if hapic_data.path.workspace_id:
            workspace = wapi.get_one(hapic_data.path.workspace_id)
        last_actives = api.get_last_active(
            workspace=workspace,
            limit=None,
            before_content=None,
            content_ids=hapic_data.query.content_ids or None)
        return [
            api.get_content_in_context(content) for content in last_actives
        ]

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_account_content_as_read(self,
                                    context,
                                    request: TracimRequest,
                                    hapic_data=None):  # nopep8
        """
        set user_read status of content to read
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceAndContentIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_account_content_as_unread(self,
                                      context,
                                      request: TracimRequest,
                                      hapic_data=None):  # nopep8
        """
        set user_read status of content to unread
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_unread(request.current_content, do_flush=True)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_CONTENT_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def set_account_workspace_as_read(self,
                                      context,
                                      request: TracimRequest,
                                      hapic_data=None):  # nopep8
        """
        set user_read status of all content of workspace to read
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            show_archived=True,
            show_deleted=True,
            current_user=request.current_user,
            session=request.dbsession,
            config=app_config,
        )
        api.mark_read__workspace(request.current_workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_NOTIFICATION_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def enable_account_workspace_notification(self,
                                              context,
                                              request: TracimRequest,
                                              hapic_data=None):  # nopep8
        """
        enable workspace notification
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.enable_notifications(request.current_user, workspace)
        rapi = RoleApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        role = rapi.get_one(request.current_user.user_id,
                            workspace.workspace_id)  # nopep8
        wapi.save(workspace)
        return

    @hapic.with_api_doc(tags=[SWAGGER_TAG__ACCOUNT_NOTIFICATION_ENDPOINTS])
    @check_right(is_user)
    @hapic.input_path(WorkspaceIdPathSchema())
    @hapic.output_body(NoContentSchema(),
                       default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
    def disable_account_workspace_notification(self,
                                               context,
                                               request: TracimRequest,
                                               hapic_data=None):  # nopep8
        """
        disable workspace notification
        """
        app_config = request.registry.settings['CFG']
        api = ContentApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        wapi = WorkspaceApi(
            current_user=request.current_user,  # User
            session=request.dbsession,
            config=app_config,
        )
        workspace = wapi.get_one(hapic_data.path.workspace_id)
        wapi.disable_notifications(request.current_user, workspace)
        wapi.save(workspace)
        return

    def bind(self, configurator: Configurator) -> None:
        """
        Create all routes and views using pyramid configurator
        for this controller
        """

        # account workspace
        configurator.add_route('account_workspace',
                               '/users/me/workspaces',
                               request_method='GET')  # nopep8
        configurator.add_view(self.account_workspace,
                              route_name='account_workspace')

        # account info
        configurator.add_route('account', '/users/me',
                               request_method='GET')  # nopep8
        configurator.add_view(self.account, route_name='account')
        #
        #
        # known members lists
        configurator.add_route('account_known_members',
                               '/users/me/known_members',
                               request_method='GET')  # nopep8
        configurator.add_view(self.account_known_members,
                              route_name='account_known_members')
        #
        # set account email
        configurator.add_route('set_account_email',
                               '/users/me/email',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_email,
                              route_name='set_account_email')

        # set account password
        configurator.add_route('set_account_password',
                               '/users/me/password',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_password,
                              route_name='set_account_password')  # nopep8

        # set account_infos
        configurator.add_route('set_account_info',
                               '/users/me',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_infos,
                              route_name='set_account_info')

        # account content
        configurator.add_route(
            'account_contents_read_status',
            '/users/me/workspaces/{workspace_id}/contents/read_status',
            request_method='GET')  # nopep8
        configurator.add_view(
            self.account_contents_read_status,
            route_name='account_contents_read_status')  # nopep8
        # last active content for user
        configurator.add_route(
            'account_last_active_content',
            '/users/me/workspaces/{workspace_id}/contents/recently_active',
            request_method='GET')  # nopep8
        configurator.add_view(
            self.account_last_active_content,
            route_name='account_last_active_content')  # nopep8

        # set content as read/unread
        configurator.add_route(
            'account_read_content',
            '/users/me/workspaces/{workspace_id}/contents/{content_id}/read',
            request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_content_as_read,
                              route_name='account_read_content')  # nopep8

        configurator.add_route(
            'account_unread_content',
            '/users/me/workspaces/{workspace_id}/contents/{content_id}/unread',
            request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_content_as_unread,
                              route_name='account_unread_content')  # nopep8

        # set workspace as read
        configurator.add_route('account_read_workspace',
                               '/users/me/workspaces/{workspace_id}/read',
                               request_method='PUT')  # nopep8
        configurator.add_view(self.set_account_workspace_as_read,
                              route_name='account_read_workspace')  # nopep8

        # enable workspace notification
        configurator.add_route(
            'enable_account_workspace_notification',
            '/users/me/workspaces/{workspace_id}/notifications/activate',
            request_method='PUT')  # nopep8
        configurator.add_view(
            self.enable_account_workspace_notification,
            route_name='enable_account_workspace_notification')  # nopep8

        # disable workspace notification
        configurator.add_route(
            'disable_account_workspace_notification',
            '/users/me/workspaces/{workspace_id}/notifications/deactivate',
            request_method='PUT')  # nopep8
        configurator.add_view(
            self.disable_account_workspace_notification,
            route_name='disable_account_workspace_notification')  # nopep8