Added achievement data model #268_achievements

This commit is contained in:
2023-06-14 19:30:30 +02:00
parent 2c9569b75f
commit 7f197a0ea7
14 changed files with 459 additions and 8 deletions

View File

@@ -0,0 +1,35 @@
from abc import ABC, abstractmethod
from cpl_query.extension import List
from bot_data.model.achievement import Achievement
class AchievementRepositoryABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod
def get_achievements(self) -> List[Achievement]:
pass
@abstractmethod
def get_achievement_by_id(self, id: int) -> Achievement:
pass
@abstractmethod
def get_achievements_by_server_id(self, server_id: int) -> List[Achievement]:
pass
@abstractmethod
def add_achievement(self, achievement: Achievement):
pass
@abstractmethod
def update_achievement(self, achievement: Achievement):
pass
@abstractmethod
def delete_achievement(self, achievement: Achievement):
pass

View File

@@ -5,6 +5,7 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
@@ -24,6 +25,7 @@ from bot_data.abc.user_message_count_per_hour_repository_abc import (
)
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
from bot_data.service.achievements_repository_service import AchievementRepositoryService
from bot_data.service.api_key_repository_service import ApiKeyRepositoryService
from bot_data.service.auth_user_repository_service import AuthUserRepositoryService
from bot_data.service.auto_role_repository_service import AutoRoleRepositoryService
@@ -77,5 +79,6 @@ class DataModule(ModuleABC):
)
services.add_transient(GameServerRepositoryABC, GameServerRepositoryService)
services.add_transient(UserGameIdentRepositoryABC, UserGameIdentRepositoryService)
services.add_transient(AchievementRepositoryABC, AchievementRepositoryService)
services.add_transient(SeederService)

View File

@@ -0,0 +1,95 @@
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.migration_abc import MigrationABC
from bot_data.db_context import DBContext
class AchievementsMigration(MigrationABC):
name = "1.1.0_AchievementsMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)
self._logger = logger
self._db = db
self._cursor = db.cursor
def upgrade(self):
self._logger.debug(__name__, "Running upgrade")
self._cursor.execute(
str(
f"""
CREATE TABLE IF NOT EXISTS `Achievements` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`ServerId` BIGINT,
`Name` VARCHAR(255) NOT NULL,
`Attribute` VARCHAR(255) NOT NULL,
`Operator` VARCHAR(2) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
`CreatedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6),
`LastModifiedAt` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`ServerId`) REFERENCES `Servers`(`ServerId`)
);
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE Users ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;
ALTER TABLE Users ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;
"""
)
)
self._cursor.execute(
str(
f"""
ALTER TABLE UsersHistory ADD MessageCount BIGINT NOT NULL DEFAULT 0 AFTER XP;
ALTER TABLE UsersHistory ADD ReactionCount BIGINT NOT NULL DEFAULT 0 AFTER XP;
"""
)
)
self._cursor.execute(
str(
f"""
DROP TRIGGER IF EXISTS `TR_AchievementsUpdate`;
CREATE TRIGGER `TR_AchievementsUpdate`
AFTER UPDATE
ON `Achievements`
FOR EACH ROW
BEGIN
INSERT INTO `AchievementsHistory` (
`Id`, `Name`, `Attribute`, `Operator`, `Value`, `ServerId`, `DateFrom`, `DateTo`
)
VALUES (
OLD.Id, OLD.Name, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
);
END;
DROP TRIGGER IF EXISTS `TR_AchievementsDelete`;
CREATE TRIGGER `TR_AchievementsDelete`
AFTER DELETE
ON `Achievements`
FOR EACH ROW
BEGIN
INSERT INTO `AchievementsHistory` (
`Id`, `Name`, `Attribute`, `Operator`, `Value`, `ServerId`, `Deleted`, `DateFrom`, `DateTo`
)
VALUES (
OLD.Id, OLD.Name, OLD.Attribute, OLD.Operator, OLD.Value, OLD.ServerId, TRUE, OLD.LastModifiedAt, CURRENT_TIMESTAMP(6)
);
END;
"""
)
)
def downgrade(self):
self._cursor.execute("DROP TABLE `Achievements`;")
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN MessageCount;"""))
self._cursor.execute(str(f"""ALTER TABLE Users DROP COLUMN ReactionCount;"""))

View File

@@ -0,0 +1,117 @@
from datetime import datetime
from typing import Optional
from cpl_core.database import TableABC
from bot_data.model.server import Server
class Achievement(TableABC):
def __init__(
self,
name: str,
attribute: str,
operator: str,
value: str,
server: Optional[Server],
created_at: datetime = None,
modified_at: datetime = None,
id=0,
):
self._id = id
self._name = name
self._attribute = attribute
self._operator = operator
self._value = value
self._server = server
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 id(self) -> int:
return self._id
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, value: str):
self._name = value
@property
def operator(self) -> str:
return self._operator
@operator.setter
def operator(self, value: str):
self._operator = value
@property
def value(self) -> str:
return self._value
@value.setter
def value(self, value: str):
self._value = value
@property
def server(self) -> Server:
return self._server
@staticmethod
def get_select_all_string() -> str:
return str(
f"""
SELECT * FROM `Achievements`;
"""
)
@staticmethod
def get_select_by_id_string(id: int) -> str:
return str(
f"""
SELECT * FROM `Achievements`
WHERE `Id` = {id};
"""
)
@property
def insert_string(self) -> str:
return str(
f"""
INSERT INTO `Achievements` (
`Name`, `Attribute`, `Operator`, `Value`, `ServerId`
) VALUES (
'{self._name}',
'{self._attribute}',
'{self._operator}',
'{self._value}',
{self._server.id}
);
"""
)
@property
def udpate_string(self) -> str:
return str(
f"""
UPDATE `Levels`
SET `Name` = '{self._name}',
`Attribute` = '{self._attribute}',
`Operator` = '{self._operator}',
`Value` = '{self._value}'
WHERE `Id` = {self._id};
"""
)
@property
def delete_string(self) -> str:
return str(
f"""
DELETE FROM `Achievements`
WHERE `Id` = {self._id};
"""
)

View File

@@ -0,0 +1,66 @@
from datetime import datetime
from typing import Optional
from cpl_core.database import TableABC
from bot_data.abc.history_table_abc import HistoryTableABC
from bot_data.model.server import Server
class Achievement(HistoryTableABC):
def __init__(
self,
name: str,
attribute: str,
operator: str,
value: str,
server: Optional[Server],
deleted: bool,
date_from: str,
date_to: str,
id=0,
):
HistoryTableABC.__init__(self)
self._id = id
self._name = name
self._attribute = attribute
self._operator = operator
self._value = value
self._server = server
self._deleted = deleted
self._date_from = date_from
self._date_to = date_to
@property
def id(self) -> int:
return self._id
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, value: str):
self._name = value
@property
def operator(self) -> str:
return self._operator
@operator.setter
def operator(self, value: str):
self._operator = value
@property
def value(self) -> str:
return self._value
@value.setter
def value(self, value: str):
self._value = value
@property
def server(self) -> Server:
return self._server

View File

@@ -0,0 +1,72 @@
from cpl_core.database.context import DatabaseContextABC
from cpl_query.extension import List
from bot_core.logging.database_logger import DatabaseLogger
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.model.achievement import Achievement
class AchievementRepositoryService(AchievementRepositoryABC):
def __init__(
self,
logger: DatabaseLogger,
db_context: DatabaseContextABC,
servers: ServerRepositoryABC,
):
self._logger = logger
self._context = db_context
self._servers = servers
AchievementRepositoryABC.__init__(self)
def _from_result(self, result: tuple):
return Achievement(
result[3],
result[4],
result[5],
result[6],
self._servers.get_server_by_id(result[2]),
result[6],
result[7],
id=result[0],
)
def get_achievements(self) -> List[Achievement]:
achievements = List(Achievement)
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_all_string()}")
results = self._context.select(Achievement.get_select_all_string())
for result in results:
self._logger.trace(__name__, f"Get user with id {result[0]}")
achievements.append(self._from_result(result))
return achievements
def get_achievement_by_id(self, id: int) -> Achievement:
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_by_id_string(id)}")
result = self._context.select(Achievement.get_select_by_id_string(id))[0]
return self._from_result(result)
def get_achievements_by_server_id(self, server_id: int) -> List[Achievement]:
achievements = List(Achievement)
self._logger.trace(__name__, f"Send SQL command: {Achievement.get_select_by_id_string(server_id)}")
results = self._context.select(Achievement.get_select_all_string())
for result in results:
self._logger.trace(__name__, f"Get user with id {result[0]}")
achievements.append(self._from_result(result))
return achievements
def add_achievement(self, achievement: Achievement):
self._logger.trace(__name__, f"Send SQL command: {achievement.insert_string}")
self._context.cursor.execute(achievement.insert_string)
def update_achievement(self, achievement: Achievement):
self._logger.trace(__name__, f"Send SQL command: {achievement.udpate_string}")
self._context.cursor.execute(achievement.udpate_string)
def delete_achievement(self, achievement: Achievement):
self._logger.trace(__name__, f"Send SQL command: {achievement.delete_string}")
self._context.cursor.execute(achievement.delete_string)