def test_unit__get_receiver_ids_user_event__nominal_case( self, session, workspace_and_users, admin_user, user_api_factory): (my_workspace, same_workspace_user, _, other_user, event_initiator) = workspace_and_users user_api = user_api_factory.get() fields = { Event.AUTHOR_FIELD: UserSchema().dump( user_api.get_user_with_context(event_initiator)).data, Event.CLIENT_TOKEN_FIELD: "test", Event.USER_FIELD: UserSchema().dump( user_api.get_user_with_context(event_initiator)).data, } event = Event(entity_type=EntityType.USER, operation=OperationType.MODIFIED, fields=fields) receivers_ids = FakeLiveMessageBuilder()._get_receiver_ids( event, session) assert event_initiator.user_id in receivers_ids assert same_workspace_user.user_id in receivers_ids assert other_user.user_id not in receivers_ids assert admin_user.user_id in receivers_ids
def test_unit__get_receiver_ids_workspace_members_event__nominal_case( self, session, workspace_and_users, admin_user, user_api_factory, workspace_api_factory, role_api_factory, ): (my_workspace, same_workspace_user, role, other_user, event_initiator) = workspace_and_users workspace_api = workspace_api_factory.get() workspace_in_context = workspace_api.get_workspace_with_context(my_workspace) rapi = role_api_factory.get() user_api = user_api_factory.get() role_in_context = rapi.get_user_role_workspace_with_context(role) fields = { Event.AUTHOR_FIELD: UserSchema() .dump(user_api.get_user_with_context(event_initiator)) .data, Event.USER_FIELD: UserSchema() .dump(user_api.get_user_with_context(event_initiator)) .data, Event.CLIENT_TOKEN_FIELD: "test", Event.WORKSPACE_FIELD: WorkspaceSchema().dump(workspace_in_context).data, Event.MEMBER_FIELD: WorkspaceMemberDigestSchema().dump(role_in_context).data, } event = Event( entity_type=EntityType.WORKSPACE_MEMBER, operation=OperationType.MODIFIED, fields=fields ) receivers_ids = FakeLiveMessageBuilder()._get_receiver_ids(event, session) assert event_initiator.user_id in receivers_ids assert same_workspace_user.user_id in receivers_ids assert other_user.user_id not in receivers_ids assert admin_user.user_id in receivers_ids
def test_unit__get_receiver_ids_workspace_event__accessible_workspace( self, session, accessible_workspace_and_users, admin_user, user_api_factory, workspace_api_factory, ): ( my_workspace, same_workspace_user, _, other_user, event_initiator, ) = accessible_workspace_and_users workspace_api = workspace_api_factory.get() workspace_in_context = workspace_api.get_workspace_with_context(my_workspace) user_api = user_api_factory.get() fields = { Event.AUTHOR_FIELD: UserSchema() .dump(user_api.get_user_with_context(event_initiator)) .data, Event.CLIENT_TOKEN_FIELD: "test", Event.WORKSPACE_FIELD: WorkspaceSchema().dump(workspace_in_context).data, } event = Event( entity_type=EntityType.WORKSPACE, operation=OperationType.MODIFIED, fields=fields ) receivers_ids = FakeLiveMessageBuilder()._get_receiver_ids(event, session) assert event_initiator.user_id in receivers_ids assert same_workspace_user.user_id in receivers_ids assert other_user.user_id in receivers_ids assert admin_user.user_id in receivers_ids
def test_unit__get_receiver_ids_content_event__nominal_case( self, session, user_api_factory, content_type_list, content_api_factory, admin_user, workspace_api_factory, role_api_factory, workspace_and_users, ): (my_workspace, same_workspace_user, role, other_user, event_initiator) = workspace_and_users workspace_api = workspace_api_factory.get() user_api = user_api_factory.get() workspace_in_context = workspace_api.get_workspace_with_context( my_workspace) content_api = content_api_factory.get(current_user=event_initiator) folder = content_api.create( label="test_folder", content_type_slug=content_type_list.Folder.slug, workspace=my_workspace, do_save=True, do_notify=False, ) transaction.commit() content_in_context = content_api.get_content_in_context(folder) fields = { Event.AUTHOR_FIELD: UserSchema().dump( user_api.get_user_with_context(event_initiator)).data, Event.CONTENT_FIELD: ContentSchema().dump(content_in_context).data, Event.CLIENT_TOKEN_FIELD: "test", Event.WORKSPACE_FIELD: WorkspaceSchema().dump(workspace_in_context).data, } event = Event(entity_type=EntityType.CONTENT, operation=OperationType.MODIFIED, fields=fields) receivers_ids = FakeLiveMessageBuilder()._get_receiver_ids( event, session) assert event_initiator.user_id in receivers_ids assert same_workspace_user.user_id in receivers_ids assert other_user.user_id not in receivers_ids assert admin_user.user_id not in receivers_ids
class EventApi: """Api to query event & messages""" user_schema = UserSchema() workspace_schema = WorkspaceSchema() content_schemas = { COMMENT_TYPE: CommentSchema(), HTML_DOCUMENTS_TYPE: TextBasedContentSchema(), FILE_TYPE: FileContentSchema(), FOLDER_TYPE: TextBasedContentSchema(), THREAD_TYPE: TextBasedContentSchema(), } event_schema = EventSchema() workspace_user_role_schema = WorkspaceMemberDigestSchema() workspace_subscription_schema = WorkspaceSubscriptionSchema() def __init__(self, current_user: Optional[User], session: TracimSession, config: CFG) -> None: self._current_user = current_user self._session = session self._config = config def _filter_event_types(self, query: Query, event_types: Optional[ List[EventTypeDatabaseParameters]], exclude: bool) -> Query: if event_types: event_type_filters = [] for event_type in event_types: if event_type.subtype: event_type_filter = and_( Event.entity_type == event_type.entity, Event.operation == event_type.operation, Event.entity_subtype == event_type.subtype, ) else: event_type_filter = and_( Event.entity_type == event_type.entity, Event.operation == event_type.operation, ) event_type_filters.append(event_type_filter) if len(event_type_filters) > 1: f = or_(*event_type_filters) else: f = event_type_filters[0] if exclude: f = not_(f) return query.filter(f) return query def _base_query( self, read_status: ReadStatus = ReadStatus.ALL, event_id: Optional[int] = None, user_id: Optional[int] = None, include_event_types: List[EventTypeDatabaseParameters] = None, exclude_event_types: List[EventTypeDatabaseParameters] = None, exclude_author_ids: Optional[List[int]] = None, after_event_id: int = 0, ) -> Query: query = self._session.query(Message).join(Event) if event_id: query = query.filter(Message.event_id == event_id) if user_id: query = query.filter(Message.receiver_id == user_id) if read_status == ReadStatus.READ: query = query.filter(Message.read != null()) elif read_status == ReadStatus.UNREAD: query = query.filter(Message.read == null()) else: # ALL doesn't need any filtering and is the only other handled case assert read_status == ReadStatus.ALL query = self._filter_event_types(query, include_event_types, False) query = self._filter_event_types(query, exclude_event_types, True) if exclude_event_types: event_type_filters = [] for event_type in exclude_event_types: if event_type.subtype: event_type_filter = or_( Event.entity_type != event_type.entity, Event.operation != event_type.operation, Event.entity_subtype != event_type.subtype, ) else: event_type_filter = or_( Event.entity_type != event_type.entity, Event.operation != event_type.operation, ) event_type_filters.append(event_type_filter) if len(event_type_filters) > 1: query = query.filter(and_(*event_type_filters)) else: query = query.filter(event_type_filters[0]) if exclude_author_ids: for author_id in exclude_author_ids: # RJ & SG - 2020-09-11 - HACK # We wanted to use Event.fields["author"] == JSON.NULL instead of this # soup involving a cast and a get out of my way text("'null'") to # know whether a JSON field is null. However, this does not work on # PostgreSQL. See https://github.com/sqlalchemy/sqlalchemy/issues/5575 query = query.filter( or_( cast(Event.fields["author"], String) == text("'null'"), Event.fields["author"]["user_id"].as_integer() != author_id, )) if after_event_id: query = query.filter(Message.event_id > after_event_id) return query def get_one_message(self, event_id: int, user_id: int) -> Message: try: return self._base_query(event_id=event_id, user_id=user_id).one() except NoResultFound as exc: raise MessageDoesNotExist( 'Message for user {} with event id "{}" not found in database'. format(user_id, event_id)) from exc def mark_user_message_as_read(self, event_id: int, user_id: int) -> Message: message = self.get_one_message(event_id, user_id) message.read = datetime.utcnow() self._session.add(message) self._session.flush() return message def mark_user_message_as_unread(self, event_id: int, user_id: int) -> Message: message = self.get_one_message(event_id, user_id) message.read = None self._session.add(message) self._session.flush() return message def mark_user_messages_as_read(self, user_id: int) -> List[Message]: unread_messages = self._base_query(read_status=ReadStatus.UNREAD, user_id=user_id).all() for message in unread_messages: message.read = datetime.utcnow() self._session.add(message) self._session.flush() return unread_messages def get_messages_for_user(self, user_id: int, after_event_id: int = 0) -> List[Message]: query = self._base_query( user_id=user_id, after_event_id=after_event_id, ) return query.all() def get_paginated_messages_for_user( self, user_id: int, read_status: ReadStatus, exclude_author_ids: List[int] = None, include_event_types: List[EventTypeDatabaseParameters] = None, exclude_event_types: List[EventTypeDatabaseParameters] = None, count: Optional[int] = DEFAULT_NB_ITEM_PAGINATION, page_token: Optional[int] = None, ) -> Page: query = self._base_query( user_id=user_id, read_status=read_status, include_event_types=include_event_types, exclude_event_types=exclude_event_types, exclude_author_ids=exclude_author_ids, ).order_by(Message.event_id.desc()) return get_page(query, per_page=count, page=page_token or False) def get_messages_count( self, user_id: int, read_status: ReadStatus, include_event_types: List[EventTypeDatabaseParameters] = None, exclude_event_types: List[EventTypeDatabaseParameters] = None, exclude_author_ids: List[int] = None, ) -> int: return self._base_query( user_id=user_id, include_event_types=include_event_types, exclude_event_types=exclude_event_types, read_status=read_status, exclude_author_ids=exclude_author_ids, ).count() def create_event( self, entity_type: EntityType, operation: OperationType, additional_fields: Dict[str, JsonDict], context: TracimContext, entity_subtype: Optional[str] = None, ) -> Event: current_user = context.safe_current_user() user_api = UserApi( current_user=current_user, session=context.dbsession, config=self._config, show_deleted=True, ) if current_user: author = self.user_schema.dump( user_api.get_user_with_context(current_user)).data else: author = None fields = { Event.AUTHOR_FIELD: author, Event.CLIENT_TOKEN_FIELD: context.client_token, } fields.update(additional_fields) event = Event( entity_type=entity_type, operation=operation, entity_subtype=entity_subtype, fields=fields, ) context.dbsession.add(event) context.pending_events.append(event) return event @classmethod def get_content_schema_for_type(cls, content_type: str) -> ContentSchema: try: return cls.content_schemas[content_type] except KeyError: logger.error( cls, ("Cannot dump proper content for content-type '{}' in generated event " "as it is unknown, falling back to generic content schema" ).format(content_type), ) return ContentSchema()
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
class SessionController(Controller): @hapic.with_api_doc(tags=[SWAGGER_TAG__AUTHENTICATION_ENDPOINTS]) @hapic.input_headers(LoginOutputHeaders()) @hapic.input_body(BasicAuthSchema()) @hapic.output_body(UserSchema()) def login(self, context, request: TracimRequest, hapic_data=None): """ Logs the user into the system. In case of success, the JSON returned is the user profile. In that case, a cookie is created with a session_key and an expiration date. Eg. : `session_key=932d2ad68f3a094c2d4da563ccb921e6479729f5b5f707eba91d4194979df20831be48a0; expires=Mon, 22-Oct-2018 19:37:02 GMT; Path=/; SameSite=Lax` """ login = hapic_data.body app_config = request.registry.settings["CFG"] # type: CFG uapi = UserApi(None, session=request.dbsession, config=app_config) ldap_connector = None if AuthType.LDAP in app_config.AUTH_TYPES: ldap_connector = get_ldap_connector(request) user = uapi.authenticate(login.email, login.password, ldap_connector) remember(request, user.user_id) return uapi.get_user_with_context(user) @hapic.with_api_doc(tags=[SWAGGER_TAG__AUTHENTICATION_ENDPOINTS]) @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) def logout(self, context, request: TracimRequest, hapic_data=None): """ Logs out current logged in user. This also trashes the associated session """ request.session.delete() return @hapic.with_api_doc(tags=[SWAGGER_TAG__AUTHENTICATION_ENDPOINTS]) @hapic.output_body(UserSchema()) def whoami(self, context, request: TracimRequest, hapic_data=None): """ Return current logged-in user. If user is not authenticated or the session has expired, a 401 is returned. This is the recommanded way to check if the user is already authenticated """ app_config = request.registry.settings["CFG"] # type: CFG uapi = UserApi(request.current_user, session=request.dbsession, config=app_config) user = uapi.get_current_user() # User return uapi.get_user_with_context(user) def bind(self, configurator: Configurator): # Login configurator.add_route("login", "/auth/login", request_method="POST") configurator.add_view(self.login, route_name="login") # Logout configurator.add_route("logout", "/auth/logout", request_method="POST") configurator.add_view(self.logout, route_name="logout") configurator.add_route("logout_get", "/auth/logout", request_method="GET") configurator.add_view(self.logout, route_name="logout_get") # Whoami configurator.add_route("whoami", "/auth/whoami", request_method="GET") configurator.add_view(self.whoami, route_name="whoami")
def test_unit__get_receiver_ids_workspace_subscription_event__reject_subscription( self, session: TracimSession, user_api_factory: UserApiFactory, subscription_lib_factory: SubscriptionLibFactory, admin_user: User, workspace_api_factory: WorkspaceApiFactory, role_api_factory: RoleApiFactory, ): user_api = user_api_factory.get() profile = Profile.USER subscriber = user_api.create_user( "*****@*****.**", password="******", do_save=True, do_notify=False, profile=profile, ) workspace_content_manager = user_api.create_user( "*****@*****.**", password="******", do_save=True, do_notify=False, profile=profile, ) workspace_manager = user_api.create_user( "*****@*****.**", password="******", do_save=True, do_notify=False, profile=profile, ) other_user = user_api.create_user( "*****@*****.**", password="******", do_save=True, do_notify=False, profile=profile, ) workspace_api = workspace_api_factory.get(current_user=admin_user) my_workspace = workspace_api.create_workspace( "test workspace", save_now=True, access_type=WorkspaceAccessType.ON_REQUEST ) workspace_in_context = workspace_api.get_workspace_with_context(my_workspace) subscription_lib = subscription_lib_factory.get(current_user=subscriber) rapi = role_api_factory.get(current_user=subscriber) rapi.create_one( workspace_content_manager, my_workspace, UserRoleInWorkspace.CONTENT_MANAGER, False ) rapi.create_one( workspace_manager, my_workspace, UserRoleInWorkspace.WORKSPACE_MANAGER, False ) subscription = subscription_lib.submit_subscription(my_workspace) subscription_lib.reject_subscription(subscription) transaction.commit() fields = { Event.AUTHOR_FIELD: UserSchema().dump(user_api.get_user_with_context(admin_user)).data, Event.WORKSPACE_FIELD: WorkspaceSchema().dump(workspace_in_context).data, Event.SUBSCRIPTION_FIELD: WorkspaceSubscriptionSchema().dump(subscription).data, } event = Event( entity_type=EntityType.WORKSPACE_SUBSCRIPTION, operation=OperationType.MODIFIED, fields=fields, ) receivers_ids = FakeLiveMessageBuilder()._get_receiver_ids(event, session) assert subscriber.user_id in receivers_ids assert workspace_manager.user_id in receivers_ids assert admin_user.user_id in receivers_ids assert workspace_content_manager.user_id not in receivers_ids assert other_user.user_id not in receivers_ids
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")
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")
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