def join_channel(cls, registration_data): user = Authenticator.authenticate_team(registration_data.authentication) channel = ChannelDatabaseClient.get_channel_by_id(registration_data.channel_id) if channel is None: cls.logger().info(f"User {user.user_id} attempting to join channel #{registration_data.channel_id}, " f"which does not exist.") return BadRequestChannelMessageResponse("Channel not found.", ChannelResponseStatus.CHANNEL_NOT_FOUND.value) if channel.team_id != user.team_id: cls.logger().info(f"User {user.user_id} from team {user.team_id} attempting to join channel " f"#{channel.channel_id}, but it's in team {channel.team_id}.") return BadRequestChannelMessageResponse("Other team's channel.", ChannelResponseStatus.OTHER_TEAM.value) if channel.visibility == ChannelVisibilities.PRIVATE.value: cls.logger().info( f"User {user.user_id} attempting to join channel #{channel.channel_id}, which is private.") return BadRequestChannelMessageResponse("Private channel!", ChannelResponseStatus.PRIVATE_VISIBILITY.value) try: new_channel_user = ChannelUser(user_id=user.id, channel_id=channel.channel_id) ChannelDatabaseClient.add_channel_user(new_channel_user) new_chat = Chat(user_id=user.id, chat_id=channel.channel_id, team_id=user.team_id) MessageDatabaseClient.add_chat(new_chat) DatabaseClient.commit() cls.logger().info(f"User {user.id} joined channel #{channel.channel_id}.") return SuccessfulChannelResponse(channel, ChannelResponseStatus.JOINED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error(f"User #{user.id} failed at joining channel #{channel.channel_id}.") return UnsuccessfulChannelMessageResponse("Couldn't join channel.")
def add_forbidden_word(cls, word_data): user = Authenticator.authenticate_team(word_data.authentication, TeamRoles.is_team_moderator) if TeamDatabaseClient.get_forbidden_word_by_word( user.team_id, word_data.word) is not None: cls.logger().debug( f"User #{user.id} attempted to add a forbidden word that already exists ({word_data.word})." ) return BadRequestTeamMessageResponse( "Word already forbidden!", TeamResponseStatus.ALREADY_REGISTERED.value) forbidden_word = ForbiddenWord(word=word_data.word, team_id=user.team_id) try: TeamDatabaseClient.add_forbidden_word(forbidden_word) DatabaseClient.commit() cls.logger().info( f"Word \"{word_data.word}\" forbidden in team #{user.team_id} by user #{user.id}." ) return SuccessfulTeamMessageResponse( "Forbidden word added!", TeamResponseStatus.ADDED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"User #{user.id} couldn't add forbidden word \"{word_data.word}\"." ) return UnsuccessfulTeamMessageResponse( "Couldn't add forbidden word.")
def delete_forbidden_word(cls, word_data): user = Authenticator.authenticate_team(word_data.authentication, TeamRoles.is_team_moderator) forbidden_word = TeamDatabaseClient.get_forbidden_word_by_id( user.team_id, word_data.word_id) if forbidden_word is None: cls.logger().error( f"User #{user.id} tried to delete forbidden word {word_data.word_id} from team " f"#{user.team_id}, which doesn't exist.") return BadRequestTeamMessageResponse( "Forbidden word not found!", TeamResponseStatus.NOT_FOUND.value) try: TeamDatabaseClient.delete_forbidden_word(forbidden_word) DatabaseClient.commit() cls.logger().info( f"User #{user.id} deleted forbidden word \"{forbidden_word.word}\" from team " f"#{user.team_id}.") return SuccessfulTeamMessageResponse( "Forbidden word removed!", TeamResponseStatus.REMOVED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"User #{user.id} couldn't remove forbidden word \"{forbidden_word.word}\" from team " f"#{user.team_id}.") return UnsuccessfulTeamMessageResponse("Couldn't remove team.")
def test_app_user_authenticating_to_team_with_role_verifying_authenticates( self): user_id = 0 team_id = 0 token = Authenticator.generate(user_id) authentication = MagicMock() authentication.token = token authentication.team_id = team_id def verifying_function(_): return True '''Mocked outputs''' user = User(user_id=user_id, token=token) team_user = PublicUser(user_id=user_id) team_user.team_role = TeamRoles.CREATOR.value team_user.team_id = team_id sys.modules[ "daos.users"].UserDatabaseClient.get_user_by_id.return_value = user sys.modules[ "daos.users"].UserDatabaseClient.get_team_user_by_ids.return_value = team_user authenticated_user = Authenticator.authenticate_team( authentication, verifying_function) self.assertEqual(user_id, authenticated_user.id)
def create_bot(cls, bot_data): admin = Authenticator.authenticate_team(bot_data.authentication, UserRoles.is_admin) try: new_client = UserDatabaseClient.add_client() new_bot = Bot( bot_id=new_client.id, name=bot_data.name, callback=bot_data.callback, token=Authenticator.generate(new_client.id) ) BotDatabaseClient.add_bot(new_bot) team_bot = TeamUser( user_id=new_client.id, team_id=admin.team_id, role=TeamRoles.BOT.value ) TeamDatabaseClient.add_team_user(team_bot) DatabaseClient.commit() cls.logger().info(f"Bot #{new_bot.id} created in team {admin.team_id} with callback url {new_bot.callback} " f"by admin {admin.id}.") return SuccessfulUserMessageResponse("Bot created.", UserResponseStatus.OK.value) except IntegrityError as exc: DatabaseClient.rollback() if BotDatabaseClient.get_bot_by_name(bot_data.name) is not None: cls.logger().info(f"Failing to create bot {bot_data.name}. Name already in use.", exc) return BadRequestUserMessageResponse("Name already in use for other bot.", UserResponseStatus.ALREADY_REGISTERED.value) else: cls.logger().info(f"Failing to create bot {bot_data.name}.") return UnsuccessfulClientResponse("Couldn't create bot.")
def create_channel(cls, creation_data): user = Authenticator.authenticate_team(creation_data.authentication) try: new_client = UserDatabaseClient.add_client() new_channel = Channel( channel_id=new_client.id, team_id=user.team_id, creator=user.id, name=creation_data.name, visibility=creation_data.visibility, description=creation_data.description, welcome_message=creation_data.welcome_message ) ChannelDatabaseClient.add_channel(new_channel) new_channel_user = ChannelUser(user_id=user.id, channel_id=new_channel.channel_id) ChannelDatabaseClient.add_channel_user(new_channel_user) new_chat = Chat(user_id=user.id, chat_id=new_channel.channel_id, team_id=new_channel.team_id) MessageDatabaseClient.add_chat(new_chat) DatabaseClient.commit() channel = ChannelDatabaseClient.get_channel_by_id(new_channel.channel_id) cls.logger().info(f"Channel #{new_channel.channel_id} created in team {new_channel.team_id}.") cls.logger().info(f"User #{user.id} assigned as channel #{new_channel.channel_id} creator.") except IntegrityError: DatabaseClient.rollback() if ChannelDatabaseClient.get_channel_by_name(creation_data.name) is not None: cls.logger().info(f"Failing to create channel {creation_data.name}. Name already in use.") return BadRequestChannelMessageResponse(f"Channel name {creation_data.name} already in use.", TeamResponseStatus.ALREADY_REGISTERED.value) else: cls.logger().error(f"Failing to create channel {creation_data.name}.") return UnsuccessfulChannelMessageResponse("Couldn't create channel.") else: return SuccessfulChannelResponse(channel, TeamResponseStatus.CREATED.value)
def channels_for_user(cls, user_data): user = Authenticator.authenticate_team(user_data) channels = ChannelDatabaseClient.get_user_channels_by_user_id( user.id, user.team_id, user.role == UserRoles.ADMIN.value) return SuccessfulChannelsListResponse( cls._generate_channels_list(channels))
def team_user_profile(cls, user_data): user = Authenticator.authenticate_team(user_data.authentication) response = UserService.team_user_profile( user_data.user_id, user.team_id, user.team_role == UserRoles.ADMIN.value) return response or BadRequestTeamMessageResponse( "You cannot access to this user's profile", TeamResponseStatus.USER_NOT_MEMBER.value)
def team_users(cls, user_data): user = Authenticator.authenticate_team(user_data) team_users = TeamDatabaseClient.get_all_team_users_by_team_id( user.team_id) cls.logger().info( f"User #{user.id} got {len(team_users)} users from team #{user.team_id}." ) return SuccessfulUsersListResponse(cls._team_users_list(team_users))
def search_users(cls, user_data): user = Authenticator.authenticate_team(user_data.authentication) found_users = TeamDatabaseClient.get_all_team_users_by_likely_name( user.team_id, user_data.searched_username) cls.logger().info( f"Found {len(found_users)} users for user #{user.id} with keyword {user.username} ." ) return SuccessfulUsersListResponse(cls._team_users_list(found_users))
def forbidden_words(cls, user_data): user = Authenticator.authenticate_team(user_data, TeamRoles.is_team_moderator) forbidden_words = TeamDatabaseClient.get_forbidden_words_from_team( user.team_id) cls.logger().info( f"User #{user.id} got {len(forbidden_words)} forbidden words in team #{user.team_id}." ) return SuccessfulForbiddenWordsList( cls._generate_forbidden_words_list(forbidden_words))
def get_preview_messages(cls, user_data): user = Authenticator.authenticate_team(user_data) db_direct_messages = MessageDatabaseClient.get_direct_messages_previews(user.id, user.team_id) db_channel_messages = MessageDatabaseClient.get_channel_messages_previews(user.id, user.team_id) direct_messages = cls._generate_direct_chats_list(db_direct_messages, user.id, user.team_id) channel_messages = cls._generate_channel_chats_list(db_channel_messages, user.team_id) total_messages = direct_messages + channel_messages total_messages.sort(key=lambda msg: msg.get("timestamp"), reverse=True) cls.logger().info(f"Retrieved {len(total_messages)} chats from user #{user.id} ({user.username}).") return ChatsListResponse(total_messages)
def send_message(cls, inbox_data): user = Authenticator.authenticate_team(inbox_data.authentication) if user.id == inbox_data.chat_id: raise WrongActionError("You cannot send a message to yourself!", MessageResponseStatus.ERROR.value) receiver = cls._determinate_message_receiver(inbox_data.chat_id, user.team_id) if receiver is None or receiver.team_id != user.team_id: cls.logger().info(f"Trying to send a message to client #{inbox_data.chat_id} who's not part of team " f"{user.team_id}.") return BadRequestMessageSentResponse("The receiver it's not part of this team!", TeamResponseStatus.USER_NOT_MEMBER.value) new_message = Message( sender_id=user.id, receiver_id=inbox_data.chat_id, team_id=user.team_id, content=inbox_data.content, send_type=SendMessageType.DIRECT.value if receiver.is_user else SendMessageType.CHANNEL.value, message_type=inbox_data.message_type ) chat_sender, chat_receivers = cls._increase_chats_offset(user.id, inbox_data.chat_id, user.team_id, receiver.is_user) try: new_message = MessageDatabaseClient.add_message(new_message) if inbox_data.mentions is not None: MentionService.save_mentions(new_message, inbox_data.mentions) MessageDatabaseClient.add_or_update_chat(chat_sender) for chat_receiver in chat_receivers: MessageDatabaseClient.add_or_update_chat(chat_receiver) DatabaseClient.commit() NotificationService.notify_message(new_message, receiver.is_user) cls.logger().info(f"Message sent from user #{new_message.sender_id} to client #{new_message.receiver_id}.") except IntegrityError: DatabaseClient.rollback() if UserDatabaseClient.get_client_by_id(inbox_data.chat_id) is None: cls.logger().error(f"User #{new_message.sender_id} trying to sent a message to an nonexistent user.") raise UserNotFoundError("User not found.", UserResponseStatus.USER_NOT_FOUND.value) else: cls.logger().error(f"Failing to send message from user #{new_message.sender_id} to client" f" #{inbox_data.chat_id}.") return UnsuccessfulMessageSentResponse("Couldn't sent message.") except FlushError: cls.logger().error( f"Failing to send message from user #{new_message.sender_id} to client #{inbox_data.chat_id} " f"due to DB problems.") return UnsuccessfulMessageSentResponse("Couldn't sent message.") else: return SuccessfulMessageSentResponse("Message sent")
def delete_team(cls, user_data): user = Authenticator.authenticate_team(user_data, TeamRoles.is_team_moderator) team = TeamDatabaseClient.get_team_by_id(user.team_id) try: TeamDatabaseClient.delete_team(team) DatabaseClient.commit() cls.logger().info(f"Team #{user.team_id} deleted.") return SuccessfulTeamMessageResponse( "Team removed!", TeamResponseStatus.REMOVED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"User #{user.id} couldn't remove team #{user.team_id}.") return UnsuccessfulTeamMessageResponse("Couldn't remove team.")
def leave_team(cls, user_data): user = Authenticator.authenticate_team(user_data) delete_user = TeamDatabaseClient.get_user_in_team_by_ids( user.id, user.team_id) try: TeamDatabaseClient.delete_team_user(delete_user) DatabaseClient.commit() cls.logger().info(f"User #{user.id} leaved team #{user.team_id}.") return SuccessfulTeamMessageResponse( "Team leaved!", TeamResponseStatus.REMOVED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"User #{user.id} failing to leave team #{user.team_id}.") return UnsuccessfulTeamMessageResponse("Couldn't leave team.")
def test_admin_user_authenticates_to_every_team(self): user_id = 0 team_id = 0 token = Authenticator.generate(user_id) authentication = MagicMock() authentication.token = token authentication.team_id = team_id '''Mocked outputs''' user = User(user_id=user_id, token=token, role=UserRoles.ADMIN.value) sys.modules[ "daos.users"].UserDatabaseClient.get_user_by_id.return_value = user authenticated_user = Authenticator.authenticate_team(authentication) self.assertEqual(user_id, authenticated_user.id) self.assertEqual(team_id, authenticated_user.team_id) self.assertEqual(UserRoles.ADMIN.value, authenticated_user.role)
def change_role(cls, change_role_data): team_admin = Authenticator.authenticate_team( change_role_data.authentication, TeamRoles.is_team_creator) if change_role_data.new_role == TeamRoles.CREATOR.value: cls.logger().warning( f"Trying to set user as team #{team_admin.team_id} {TeamRoles.CREATOR.value}" ) return BadRequestTeamMessageResponse( "You cannot set someone as team CREATOR.", TeamResponseStatus.ROLE_UNAVAILABLE.value) user_team = TeamDatabaseClient.get_user_in_team_by_ids( change_role_data.user_id, team_admin.team_id) if user_team is None: cls.logger().info( f"Trying to modify role from user #{change_role_data.user_id}, who's not part of team #{team_admin.team_id}" ) return BadRequestTeamMessageResponse( "The given user is not part this team.", TeamResponseStatus.USER_NOT_MEMBER.value) old_role = user_team.role user_team.role = change_role_data.new_role try: TeamDatabaseClient.update_team_user(user_team) DatabaseClient.commit() NotificationService.notify_change_role(user_team, old_role, team_admin.id) cls.logger().info( f"User #{user_team.user_id} set as team #{team_admin.team_id} {user_team.role} by user " f"#{team_admin.id}.") except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"Failing to modifying role of #{user_team.user_id} in team #{user_team.team_id}." ) return UnsuccessfulTeamMessageResponse( "Couldn't modify user role.") else: return SuccessfulTeamMessageResponse( "Role modified", TeamResponseStatus.ROLE_MODIFIED.value)
def update_information(cls, update_data): user = Authenticator.authenticate_team(update_data.authentication, TeamRoles.is_team_moderator) team = TeamDatabaseClient.get_team_by_id( update_data.authentication.team_id) team.name = \ update_data.updated_team["team_name"] if "team_name" in update_data.updated_team else team.name team.picture = \ update_data.updated_team["picture"] if "picture" in update_data.updated_team else team.picture team.location = \ update_data.updated_team["location"] if "location" in update_data.updated_team else team.location team.description = \ update_data.updated_team["description"] if "description" in update_data.updated_team else team.description team.welcome_message = \ update_data.updated_team[ "welcome_message"] if "welcome_message" in update_data.updated_team else team.welcome_message try: team = TeamDatabaseClient.update_team(team) DatabaseClient.commit() cls.logger().info( f"Team {team.id} information updated by user #{user.id}, who's team {user.team_role}." ) return SuccessfulTeamResponse(team, TeamResponseStatus.UPDATED.value) except IntegrityError: DatabaseClient.rollback() team_name = update_data.updated_team.get("team_name") if TeamDatabaseClient.get_team_by_name(team_name) is not None: cls.logger().info( f"Trying to update team {user.team_id}'s name with {team_name}, that currently exists." ) return BadRequestTeamMessageResponse( f"Name {team_name} is already in use!", TeamResponseStatus.ALREADY_REGISTERED.value) else: cls.logger().error( f"Couldn't update team {user.team_id} information.") return UnsuccessfulTeamMessageResponse( "Couldn't update team information!")
def delete_user(cls, delete_data): user = Authenticator.authenticate_team(delete_data.authentication, TeamRoles.is_team_moderator) delete_user = TeamDatabaseClient.get_user_in_team_by_ids( delete_data.delete_id, user.team_id) if delete_user is not None: if TeamRoles.is_higher_role(user.team_role, delete_user.role): try: TeamDatabaseClient.delete_team_user(delete_user) DatabaseClient.commit() cls.logger().info( f"User #{delete_user.user_id} deleted from team #{user.team_id} by user #{user.id}." ) return SuccessfulTeamMessageResponse( "User removed!", TeamResponseStatus.REMOVED.value) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"User #{user.id} failed to delete user {delete_user.user_id} from team #{user.team_id}." ) return UnsuccessfulTeamMessageResponse( "Couldn't delete user.") else: cls.logger().info( f"Cannot delete user #{delete_user.user_id} because he's role ({delete_user.role}) " f"is higher than yours.") return ForbiddenTeamMessageResponse( "You don't have enough permissions to delete this user.", TeamResponseStatus.NOT_ENOUGH_PERMISSIONS.value) else: cls.logger().info( f"Trying to delete user #{delete_data.delete_id}, who's not part of the team {user.team_id}." ) return NotFoundTeamMessageResponse( "Couldn't find user to delete", UserResponseStatus.USER_NOT_FOUND.value)
def get_messages_from_chat(cls, chat_data): user = Authenticator.authenticate_team(chat_data.authentication) chat = MessageDatabaseClient.get_chat_by_ids(user.id, chat_data.chat_id, user.team_id) if chat is None: cls.logger().error(f"User #{user.id} trying to retrieve messages from chat {chat_data.chat_id}, " f"that doesn't exist.") raise ChatNotFoundError("Chat not found.", MessageResponseStatus.CHAT_NOT_FOUND.value) else: is_channel, messages = cls._determinate_messages(user.id, chat_data.chat_id, user.team_id, chat_data.offset) unseen_messages = chat.offset try: chat.offset = 0 MessageDatabaseClient.add_or_update_chat(chat) DatabaseClient.commit() cls.logger().error(f"{unseen_messages} messages set as seen for user {user.id} in chat {chat.chat_id}.") except IntegrityError: DatabaseClient.rollback() cls.logger().error(f"Couldn't set seen messages for user {user.id} in chat {chat.chat_id}.") cls.logger().info(f"Retrieved {len(messages)} messages from chat {chat_data.chat_id} from user #{user.id}.") return MessageListResponse(cls._generate_messages_list(messages, unseen_messages, user.id, user.team_id), is_channel)
def team_bots(cls, user_data): user = Authenticator.authenticate_team(user_data) bots = BotDatabaseClient.get_team_bots(user.team_id) return SuccessfulBotListResponse(bots)
def invite_user(cls, invite_data): team_mod = Authenticator.authenticate_team(invite_data.authentication, TeamRoles.is_team_moderator) invited_user = UserDatabaseClient.get_user_by_email(invite_data.email) if invited_user is not None and invited_user.role == UserRoles.ADMIN.value: cls.logger().info( f"Mod #{team_mod.id} tried to invite admin #{invited_user.id} to team #{team_mod.team_id}." ) return BadRequestTeamMessageResponse( "You cannot invite an admin to a team!", TeamResponseStatus.ROLE_UNAVAILABLE.value) already_member = TeamDatabaseClient.get_user_in_team_by_email( invite_data.email, team_mod.team_id) if already_member is not None: cls.logger().info( f"Mod #{team_mod.id} tried to invite user #{already_member.user_id} to team " f"#{team_mod.team_id}, but it already belongs to that team.") return BadRequestTeamMessageResponse( "This user already belongs to the team.", TeamResponseStatus.ALREADY_REGISTERED.value) if TeamDatabaseClient.get_team_invite(team_mod.team_id, invite_data.email) is not None: cls.logger().info( f"Mod #{team_mod.id} tried to invite an user already invited to team #{team_mod.team_id}" ) return BadRequestTeamMessageResponse( "This user was already invited to join the team.", TeamResponseStatus.ALREADY_INVITED.value) invite_token = Authenticator.generate_team_invitation() new_invite = TeamInvite(team_id=team_mod.team_id, email=invite_data.email, token=invite_token) try: TeamDatabaseClient.add_invite(new_invite) team = TeamDatabaseClient.get_team_by_id(team_mod.team_id) DatabaseClient.commit() cls.logger().info( f"New invitation for {new_invite.email} to join team #{team_mod.team_id}, by user #" f"{team_mod.id}.") email_data = TeamInvitationEmailDTO( email=invite_data.email, team_name=team.name, inviter_name=team_mod.username, token=invite_token, message_template=EmailService.team_invitation_message) EmailService.send_email(email_data) NotificationService.notify_team_invitation(new_invite, team_mod.id) cls.logger().info( f"Team #{team_mod.team_id} invitation email sent to {new_invite.email}." ) except IntegrityError: DatabaseClient.rollback() cls.logger().error( f"Couldn't invite user {new_invite.email} to team #{team_mod.team_id}." ) return UnsuccessfulTeamMessageResponse( "Couldn't invite user to team.") else: return SuccessfulTeamMessageResponse( "User invited.", TeamResponseStatus.INVITED.value)