diff --git a/kdb-bot/src/bot_api/model/auth_user_dto.py b/kdb-bot/src/bot_api/model/auth_user_dto.py index e5831f5fe5..15efc55923 100644 --- a/kdb-bot/src/bot_api/model/auth_user_dto.py +++ b/kdb-bot/src/bot_api/model/auth_user_dto.py @@ -15,7 +15,6 @@ class AuthUserDTO(DtoABC): password: str = None, confirmation_id: Optional[str] = None, auth_role: AuthRoleEnum = None, - user_id: Optional[int] = None, ): DtoABC.__init__(self) @@ -26,7 +25,6 @@ class AuthUserDTO(DtoABC): self._password = password self._is_confirmed = confirmation_id is None self._auth_role = auth_role - self._user_id = user_id @property def id(self) -> int: @@ -80,14 +78,6 @@ class AuthUserDTO(DtoABC): def auth_role(self, value: AuthRoleEnum): self._auth_role = value - @property - def user_id(self) -> Optional[int]: - return self._user_id - - @user_id.setter - def user_id(self, value: Optional[int]): - self._user_id = value - def from_dict(self, values: dict): self._id = values['id'] self._first_name = values['firstName'] @@ -96,7 +86,6 @@ class AuthUserDTO(DtoABC): self._password = values['password'] self._is_confirmed = values['isConfirmed'] self._auth_role = values['authRole'] - self._user_id = values['userId'] def to_dict(self) -> dict: return { @@ -107,5 +96,4 @@ class AuthUserDTO(DtoABC): 'password': self._password, 'isConfirmed': self._is_confirmed, 'authRole': self._auth_role.value, - 'userId': self._user_id, } diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index 304e340a95..507a971366 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -12,6 +12,7 @@ from bot_api.model.discord.server_dto import ServerDTO from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO from bot_api.model.error_dto import ErrorDTO from bot_api.transformer.server_transformer import ServerTransformer +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.user_repository_abc import UserRepositoryABC from bot_data.model.auth_role_enum import AuthRoleEnum @@ -25,11 +26,13 @@ class DiscordService: bot: DiscordBotServiceABC, servers: ServerRepositoryABC, auth: AuthServiceABC, + auth_users: AuthUserRepositoryABC, users: UserRepositoryABC, ): self._bot = bot self._servers = servers self._auth = auth + self._auth_users = auth_users self._users = users def _to_dto(self, x: Server) -> Optional[ServerDTO]: @@ -43,11 +46,11 @@ class DiscordService: ) return ServerTransformer.to_dto( - x, - guild.name, - guild.member_count, - guild.icon - ) + x, + guild.name, + guild.member_count, + guild.icon + ) async def get_all_servers(self) -> List[ServerDTO]: servers = List(ServerDTO, self._servers.get_servers()) @@ -59,12 +62,12 @@ class DiscordService: raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') role = AuthRoleEnum(token['role']) - if role == AuthRoleEnum.admin: - servers = self._servers.get_servers() - else: - user = await self._auth.find_auth_user_by_email_async(token['email']) - user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) - servers = self._servers.get_servers().where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) + servers = self._servers.get_servers() + if role != AuthRoleEnum.admin: + auth_user = self._auth_users.find_auth_user_by_email(token['email']) + if auth_user is not None: + user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id) + servers = servers.where(lambda x: x.server_id in user_ids) servers = List(ServerDTO, servers) return servers.select(self._to_dto).where(lambda x: x.name != '') @@ -78,9 +81,10 @@ class DiscordService: filtered_result = self._servers.get_filtered_servers(criteria) # filter out servers, where the user not exists if role != AuthRoleEnum.admin: - user = await self._auth.find_auth_user_by_email_async(token['email']) - user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) - filtered_result.result = filtered_result.result.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) + auth_user = self._auth_users.find_auth_user_by_email(token['email']) + if auth_user is not None: + user_ids = auth_user.users.select(lambda x: x.server is not None and x.server.server_id) + filtered_result.result = filtered_result.result.where(lambda x: x.server_id in user_ids) servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != '') result = List(ServerDTO, servers) diff --git a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py index 529344515e..dfb34ff943 100644 --- a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py +++ b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py @@ -23,7 +23,7 @@ class AuthUserTransformer(TransformerABC): datetime.now(tz=timezone.utc), AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), dto.user_id, - id=0 if dto.id is None else dto.id + auth_user_id=0 if dto.id is None else dto.id ) @staticmethod @@ -35,6 +35,5 @@ class AuthUserTransformer(TransformerABC): db.email, '' if password is None else password, db.confirmation_id, - db.auth_role, - db.user_id + db.auth_role ) diff --git a/kdb-bot/src/bot_data/migration/api_migration.py b/kdb-bot/src/bot_data/migration/api_migration.py index d3241e6ab5..3bd83ee144 100644 --- a/kdb-bot/src/bot_data/migration/api_migration.py +++ b/kdb-bot/src/bot_data/migration/api_migration.py @@ -18,26 +18,41 @@ class ApiMigration(MigrationABC): self._cursor.execute( str(f""" CREATE TABLE IF NOT EXISTS `AuthUsers` ( - `Id` BIGINT NOT NULL AUTO_INCREMENT, - `FirstName` VARCHAR(255), - `LastName` VARCHAR(255), - `EMail` VARCHAR(255), - `Password` VARCHAR(255), - `PasswordSalt` VARCHAR(255), - `RefreshToken` VARCHAR(255), - `ConfirmationId` VARCHAR(255) DEFAULT NULL, - `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, - `OAuthId` VARCHAR(255) DEFAULT NULL, - `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, - `AuthRole` INT NOT NULL DEFAULT '0', - `UserId` BIGINT DEFAULT NULL, - `CreatedOn` DATETIME(6) NOT NULL, - `LastModifiedOn` DATETIME(6) NOT NULL, - PRIMARY KEY(`Id`), - FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`) - ) + `Id` BIGINT NOT NULL AUTO_INCREMENT, + `FirstName` VARCHAR(255), + `LastName` VARCHAR(255), + `EMail` VARCHAR(255), + `Password` VARCHAR(255), + `PasswordSalt` VARCHAR(255), + `RefreshToken` VARCHAR(255), + `ConfirmationId` VARCHAR(255) DEFAULT NULL, + `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, + `OAuthId` VARCHAR(255) DEFAULT NULL, + `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, + `AuthRole` INT NOT NULL DEFAULT '0', + `CreatedOn` DATETIME(6) NOT NULL, + `LastModifiedOn` DATETIME(6) NOT NULL, + PRIMARY KEY(`Id`) + ); + """) + ) + + self._cursor.execute( + str(f""" + CREATE TABLE IF NOT EXISTS `AuthUserUsersRelations`( + `Id` BIGINT NOT NULL AUTO_INCREMENT, + `AuthUserId` BIGINT DEFAULT NULL, + `UserId` BIGINT DEFAULT NULL, + `CreatedOn` DATETIME(6) NOT NULL, + `LastModifiedOn` DATETIME(6) NOT NULL, + PRIMARY KEY(`Id`), + FOREIGN KEY (`AuthUserId`) REFERENCES `AuthUsers`(`Id`), + FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`) + ); """) ) def downgrade(self): self._cursor.execute('DROP TABLE `AuthUsers`;') + self._cursor.execute('DROP TABLE `AuthUserUsersRelations`;') + diff --git a/kdb-bot/src/bot_data/model/auth_user.py b/kdb-bot/src/bot_data/model/auth_user.py index c97c02d89f..38c46ceaaa 100644 --- a/kdb-bot/src/bot_data/model/auth_user.py +++ b/kdb-bot/src/bot_data/model/auth_user.py @@ -2,9 +2,11 @@ import uuid from datetime import datetime from typing import Optional from cpl_core.database import TableABC +from cpl_query.extension import List from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.server import Server +from bot_data.model.user import User class AuthUser(TableABC): @@ -22,12 +24,12 @@ class AuthUser(TableABC): oauth_id: Optional[str], refresh_token_expire_time: datetime, auth_role: AuthRoleEnum, - user_id: Optional[int], created_at: datetime = None, modified_at: datetime = None, - id=0 + auth_user_id=0, + users: List[User] = None ): - self._auth_user_id = id + self._auth_user_id = auth_user_id self._first_name = first_name self._last_name = last_name self._email = email @@ -39,8 +41,10 @@ class AuthUser(TableABC): self._forgot_password_id = forgot_password_id self._refresh_token_expire_time = refresh_token_expire_time + if users is None: + self._users = List(User) + self._auth_role_id = auth_role - self._user_id = user_id TableABC.__init__(self) self._created_at = created_at if created_at is not None else self._created_at @@ -139,12 +143,12 @@ class AuthUser(TableABC): self._auth_role_id = value @property - def user_id(self) -> Optional[int]: - return self._user_id + def users(self) -> List[User]: + return self._users - @user_id.setter - def user_id(self, value: Optional[int]): - self._user_id = value + @users.setter + def users(self, value: List[User]): + self._users = value @staticmethod def get_select_all_string() -> str: @@ -180,6 +184,13 @@ class AuthUser(TableABC): WHERE `ForgotPasswordId` = '{id}'; """) + def get_select_user_id_from_relations(self) -> str: + return str(f""" + SELECT `UserId` + FROM `AuthUserUsersRelations` + WHERE `AuthUserId` = {self._auth_user_id}; + """) + @property def insert_string(self) -> str: return str(f""" @@ -196,7 +207,6 @@ class AuthUser(TableABC): `OAuthId`, `RefreshTokenExpiryTime`, `AuthRole`, - `UserId`, `CreatedOn`, `LastModifiedOn` ) VALUES ( @@ -212,7 +222,6 @@ class AuthUser(TableABC): '{"NULL" if self._oauth_id is None else self._oauth_id}', '{self._refresh_token_expire_time}', {self._auth_role_id.value}, - {"NULL" if self._user_id is None else self._user_id}, '{self._created_at}', '{self._modified_at}' ) @@ -233,7 +242,6 @@ class AuthUser(TableABC): `OAuthId` = '{"NULL" if self._oauth_id is None else self._oauth_id}', `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', `AuthRole` = {self._auth_role_id.value}, - `UserId` = {"NULL" if self._user_id is None else self._user_id}, `LastModifiedOn` = '{self._modified_at}' WHERE `AuthUsers`.`Id` = {self._auth_user_id}; """) diff --git a/kdb-bot/src/bot_data/model/auth_user_users_relation.py b/kdb-bot/src/bot_data/model/auth_user_users_relation.py new file mode 100644 index 0000000000..dfa33f4c47 --- /dev/null +++ b/kdb-bot/src/bot_data/model/auth_user_users_relation.py @@ -0,0 +1,87 @@ +from datetime import datetime +from typing import Optional + +from cpl_core.database import TableABC + +from bot_data.model.auth_user import AuthUser +from bot_data.model.user import User +from bot_data.model.server import Server + + +class AuthUserUsersRelation(TableABC): + + def __init__(self, auth_user: AuthUser, user: User, created_at: datetime = None, modified_at: datetime = None): + self._auth_user = auth_user + self._user = user + + TableABC.__init__(self) + self._created_at = created_at if created_at is not None else self._created_at + self._modified_at = modified_at if modified_at is not None else self._modified_at + + @property + def auth_user(self) -> AuthUser: + return self._auth_user + + @auth_user.setter + def auth_user(self, value: AuthUser): + self._auth_user = value + + @property + def user(self) -> User: + return self._user + + @user.setter + def user(self, value: User): + self._user = value + + @staticmethod + def get_select_all_string() -> str: + return str(f""" + SELECT * FROM `AuthUserUsersRelations`; + """) + + @staticmethod + def get_select_by_auth_user_id_string(id: int) -> str: + return str(f""" + SELECT * FROM `AuthUserUsersRelations` + WHERE `AuthUserId` = {id}; + """) + + @staticmethod + def get_select_by_user_id_string(id: int) -> str: + return str(f""" + SELECT * FROM `AuthUserUsersRelations` + WHERE `UserId` = {id}; + """) + + @property + def insert_string(self) -> str: + return str(f""" + INSERT INTO `AuthUserUsersRelations` ( + `AuthUserId`, `UserId`, `CreatedAt`, `LastModifiedAt` + ) VALUES ( + {self._auth_user.id}, + {self._user.user_id}, + '{self._created_at}', + '{self._modified_at}' + ); + """) + + @property + def udpate_string(self) -> str: + return str(f""" + UPDATE `AuthUserUsersRelations` + SET `AuthUserId` = '{self._auth_user.id}',, + `UserId` = '{self._user.user_id}' + `LastModifiedAt` = '{self._modified_at}' + WHERE `AuthUserId` = {self._auth_user.id} + AND `UserId` = {self._user.user_id}; + """) + + @property + def delete_string(self) -> str: + return str(f""" + DELETE FROM `AuthUserUsersRelations` + WHERE `AuthUserId` = {self._auth_user.id} + AND `UserId` = {self._user.user_id}; + """) diff --git a/kdb-bot/src/bot_data/service/auth_user_repository_service.py b/kdb-bot/src/bot_data/service/auth_user_repository_service.py index 94d86bcfe8..ebc383c01b 100644 --- a/kdb-bot/src/bot_data/service/auth_user_repository_service.py +++ b/kdb-bot/src/bot_data/service/auth_user_repository_service.py @@ -6,16 +6,19 @@ from cpl_query.extension import List from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_core.logging.database_logger import DatabaseLogger from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC +from bot_data.abc.user_repository_abc import UserRepositoryABC from bot_data.filtered_result import FilteredResult from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_user import AuthUser +from bot_data.model.user import User class AuthUserRepositoryService(AuthUserRepositoryABC): - def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC): + def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC, users: UserRepositoryABC): self._logger = logger self._context = db_context + self._users = users AuthUserRepositoryABC.__init__(self) @@ -26,23 +29,34 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return value - def _user_from_result(self, result: tuple) -> AuthUser: - return AuthUser( - self._get_value_from_result(result[1]), - self._get_value_from_result(result[2]), - self._get_value_from_result(result[3]), - self._get_value_from_result(result[4]), - self._get_value_from_result(result[5]), - self._get_value_from_result(result[6]), - self._get_value_from_result(result[7]), - self._get_value_from_result(result[8]), - self._get_value_from_result(result[9]), - self._get_value_from_result(result[10]), - AuthRoleEnum(self._get_value_from_result(result[11])), - self._get_value_from_result(result[12]), - id=self._get_value_from_result(result[0]) + def _user_from_result(self, au_result: tuple) -> AuthUser: + auth_user = AuthUser( + self._get_value_from_result(au_result[1]), + self._get_value_from_result(au_result[2]), + self._get_value_from_result(au_result[3]), + self._get_value_from_result(au_result[4]), + self._get_value_from_result(au_result[5]), + self._get_value_from_result(au_result[6]), + self._get_value_from_result(au_result[7]), + self._get_value_from_result(au_result[8]), + self._get_value_from_result(au_result[9]), + self._get_value_from_result(au_result[10]), + AuthRoleEnum(self._get_value_from_result(au_result[11])), + auth_user_id=self._get_value_from_result(au_result[0]) ) + self._logger.trace(__name__, f'Send SQL command: {auth_user.get_select_user_id_from_relations()}') + results = self._context.select(auth_user.get_select_user_id_from_relations()) + for result in results: + user_id = self._get_value_from_result(result[0]) + if user_id is None: + continue + + user = self._users.get_user_by_id(user_id) + auth_user.users.append(user) + + return auth_user + def get_all_auth_users(self) -> List[AuthUser]: users = List(AuthUser) self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}')