Compare commits
38 Commits
898e005978
...
dev
Author | SHA1 | Date | |
---|---|---|---|
266dacb301 | |||
280cd9827d | |||
36998470e8 | |||
53c6bf4208 | |||
4e80e3ccb7 | |||
ba173a6743 | |||
84ff2a8a9b | |||
13bc38fea8 | |||
dfdf0555d7 | |||
39299eb11b | |||
dfb6751bf9 | |||
4a75635a55 | |||
f6b2739394 | |||
36d2605655 | |||
af891fa588 | |||
af348b85a4 | |||
7ed621a25b | |||
013f953a7f | |||
4163532696 | |||
b6a1172cc1 | |||
20bdb6bd98 | |||
3f13f65932 | |||
711e184895 | |||
7e3975f4be | |||
d4f4f39522 | |||
af9c55e4b1 | |||
e3172d6f24 | |||
0706579f62 | |||
ad3fc94923 | |||
69882af0bd | |||
b0fb12f841 | |||
4d980331e2 | |||
e6667c78c8 | |||
9976c59302 | |||
293c8cd81c | |||
8f4ea56184 | |||
919eef79f6 | |||
5de6710261 |
@@ -6,9 +6,17 @@ on:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
on-push-deploy_sh-edraft:
|
||||
pre-build:
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: sh-edraft.de/act-runner:latest
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_dev
|
||||
|
||||
build-bot:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
@@ -22,10 +30,44 @@ jobs:
|
||||
|
||||
- name: Prepare bot build
|
||||
run: |
|
||||
cd bot
|
||||
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
cd bot
|
||||
cpl i
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-dev .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd bot
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-dev
|
||||
|
||||
build-web:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
- run: docker -v
|
||||
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Setup node
|
||||
uses: https://github.com/actions/setup-node@v3
|
||||
|
||||
@@ -35,29 +77,45 @@ jobs:
|
||||
npm install -g ts-node
|
||||
npm ci
|
||||
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_dev
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-dev .
|
||||
|
||||
- name: Build docker web
|
||||
run: |
|
||||
cd web
|
||||
docker image prune -f
|
||||
cp src/favicon.dev.ico src/favicon.ico
|
||||
npm run build
|
||||
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-dev .
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-dev .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd web
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-dev
|
||||
|
||||
deploy:
|
||||
needs: [ build-bot, build-web ]
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Install cpl
|
||||
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
cd bot/docker
|
||||
chmod +x ./set-docker-compose-image-version.sh
|
||||
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-dev sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-dev
|
||||
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-dev git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-dev
|
||||
|
||||
- name: Deploy Stack to sh-edraft.de
|
||||
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
||||
|
@@ -6,9 +6,17 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
on-push-deploy_sh-edraft:
|
||||
pre-build:
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: sh-edraft.de/act-runner:latest
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_prod
|
||||
|
||||
build-bot:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
@@ -22,10 +30,44 @@ jobs:
|
||||
|
||||
- name: Prepare bot build
|
||||
run: |
|
||||
cd bot
|
||||
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
cd bot
|
||||
cpl i
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv) .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd bot
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)
|
||||
|
||||
build-web:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
- run: docker -v
|
||||
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Setup node
|
||||
uses: https://github.com/actions/setup-node@v3
|
||||
|
||||
@@ -35,28 +77,45 @@ jobs:
|
||||
npm install -g ts-node
|
||||
npm ci
|
||||
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_prod
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t sh-edraft.de/sdb-bot:$(cpl gv) .
|
||||
|
||||
- name: Build docker web
|
||||
run: |
|
||||
cd web
|
||||
docker image prune -f
|
||||
cp src/favicon.ico src/favicon.ico
|
||||
npm run build
|
||||
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv) .
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv) .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd web
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)
|
||||
|
||||
deploy:
|
||||
needs: [ build-bot, build-web ]
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Install cpl
|
||||
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
cd bot/docker
|
||||
chmod +x ./set-docker-compose-image-version.sh
|
||||
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv) sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)
|
||||
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv) git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)
|
||||
|
||||
- name: Deploy Stack to sh-edraft.de
|
||||
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
||||
|
@@ -6,9 +6,17 @@ on:
|
||||
- staging
|
||||
|
||||
jobs:
|
||||
on-push-deploy_sh-edraft:
|
||||
pre-build:
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: sh-edraft.de/act-runner:latest
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_staging
|
||||
|
||||
build-bot:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
@@ -22,10 +30,44 @@ jobs:
|
||||
|
||||
- name: Prepare bot build
|
||||
run: |
|
||||
cd bot
|
||||
python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
cd bot
|
||||
cpl i
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-staging .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd bot
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cpl gv)-staging
|
||||
|
||||
build-web:
|
||||
needs: pre-build
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Setup docker
|
||||
uses: https://github.com/papodaca/install-docker-action@main
|
||||
- run: docker -v
|
||||
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Setup node
|
||||
uses: https://github.com/actions/setup-node@v3
|
||||
|
||||
@@ -35,29 +77,45 @@ jobs:
|
||||
npm install -g ts-node
|
||||
npm ci
|
||||
|
||||
- name: Shutdown stack
|
||||
run: docker stack rm sdb_staging
|
||||
|
||||
- name: Build docker bot
|
||||
run: |
|
||||
cd bot
|
||||
docker image prune -f
|
||||
cpl build
|
||||
docker build -t sh-edraft.de/sdb-bot:$(cpl gv)-staging .
|
||||
|
||||
- name: Build docker web
|
||||
run: |
|
||||
cd web
|
||||
docker image prune -f
|
||||
cp src/favicon.staging.ico src/favicon.ico
|
||||
npm run build
|
||||
docker build -t sh-edraft.de/sdb-web:$(npm run -s gv)-staging .
|
||||
docker build -t git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-staging .
|
||||
|
||||
- name: Login to registry git.sh-edraft.de
|
||||
uses: https://github.com/docker/login-action@v1
|
||||
with:
|
||||
registry: git.sh-edraft.de
|
||||
username: ${{ secrets.CI_USERNAME }}
|
||||
password: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
cd web
|
||||
docker push git.sh-edraft.de/sh-edraft.de/sdb-web:$(npm run -s gv)-staging
|
||||
|
||||
deploy:
|
||||
needs: [ build-bot, build-web ]
|
||||
runs-on: [ dobby.sh-edraft.de, ubuntu-latest ]
|
||||
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: https://github.com/actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
|
||||
- name: Install cpl
|
||||
run: python3.10 -m pip install --extra-index-url https://pip.sh-edraft.de cpl-cli
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
cd bot/docker
|
||||
chmod +x ./set-docker-compose-image-version.sh
|
||||
./set-docker-compose-image-version.sh sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-staging sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-staging
|
||||
./set-docker-compose-image-version.sh git.sh-edraft.de/sh-edraft.de/sdb-bot:$(cd ../; cpl gv)-staging git.sh-edraft.de/sh-edraft.de/sdb-web:$(cd ../../web; npm run -s gv;)-staging
|
||||
|
||||
- name: Deploy Stack to sh-edraft.de
|
||||
uses: https://github.com/kgierke/portainer-stack-deployment@v1
|
||||
|
Submodule bot/docker updated: b0bacce9f6...36ed43055d
@@ -16,7 +16,7 @@
|
||||
"LicenseName": "MIT",
|
||||
"LicenseDescription": "MIT, see LICENSE for more details.",
|
||||
"Dependencies": [
|
||||
"cpl-core==2023.10.0",
|
||||
"cpl-core==2023.10.1",
|
||||
"cpl-translation==2023.4.0.post1",
|
||||
"cpl-query==2023.10.0",
|
||||
"cpl-discord==2023.10.0.post1",
|
||||
@@ -33,7 +33,8 @@
|
||||
"cryptography==41.0.4",
|
||||
"discord==2.3.2",
|
||||
"bs4==0.0.1",
|
||||
"lxml==4.9.3"
|
||||
"lxml==4.9.3",
|
||||
"python-valve==0.2.1"
|
||||
],
|
||||
"DevDependencies": [
|
||||
"cpl-cli==2023.4.0.post3",
|
||||
|
Submodule bot/src/bot/config updated: c11ca6f2e8...be5b15f227
@@ -15,6 +15,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_core.logging.database_logger import DatabaseLogger
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_core.logging.message_logger import MessageLogger
|
||||
from bot_core.logging.task_logger import TaskLogger
|
||||
from bot_data.db_context import DBContext
|
||||
@@ -45,6 +46,7 @@ class Startup(StartupABC):
|
||||
services.add_singleton(CustomFileLoggerABC, DatabaseLogger)
|
||||
services.add_singleton(CustomFileLoggerABC, MessageLogger)
|
||||
services.add_singleton(CustomFileLoggerABC, TaskLogger)
|
||||
services.add_singleton(CustomFileLoggerABC, EventLogger)
|
||||
|
||||
if self._feature_flags.get_flag(FeatureFlagsEnum.api_module):
|
||||
services.add_singleton(CustomFileLoggerABC, ApiLogger)
|
||||
|
@@ -1,20 +1,18 @@
|
||||
import asyncio
|
||||
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnReadyABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.environment_variables import MAINTENANCE
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
|
||||
|
||||
class CoreExtensionOnReadyEvent(OnReadyABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
t: TranslatePipe,
|
||||
|
@@ -1,15 +1,15 @@
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnReadyABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
|
||||
|
||||
class CoreOnReadyEvent(OnReadyABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
client_utils: ClientUtilsABC,
|
||||
t: TranslatePipe,
|
||||
|
15
bot/src/bot_core/logging/event_logger.py
Normal file
15
bot/src/bot_core/logging/event_logger.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.environment import ApplicationEnvironmentABC
|
||||
from cpl_core.time import TimeFormatSettings
|
||||
|
||||
from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC
|
||||
|
||||
|
||||
class EventLogger(CustomFileLoggerABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
time_format: TimeFormatSettings,
|
||||
env: ApplicationEnvironmentABC,
|
||||
):
|
||||
CustomFileLoggerABC.__init__(self, "Event", config, time_format, env)
|
@@ -74,7 +74,7 @@ class PermissionService(PermissionServiceABC):
|
||||
self._logger.debug(__name__, f"Checking is member {member.name} {team_member_type.value}")
|
||||
|
||||
has_permission = True in [
|
||||
member.guild.get_role(x.role_id) not in member.roles
|
||||
member.guild.get_role(x.role_id) in member.roles
|
||||
for x in self._server_configs.get_server_config_by_server(
|
||||
self._servers.get_server_by_discord_id(member.guild.id).id
|
||||
).team_role_ids
|
||||
|
@@ -31,6 +31,10 @@ class UserRepositoryABC(ABC):
|
||||
def get_users_by_server_id(self, server_id: int) -> List[User]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_users_with_activity_by_server_id(self, server_id: int) -> List[User]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User:
|
||||
pass
|
||||
|
@@ -32,6 +32,8 @@ class User(TableABC):
|
||||
self._birthday = birthday
|
||||
self._server = server
|
||||
|
||||
self._activity = 0
|
||||
|
||||
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
|
||||
@@ -120,6 +122,14 @@ class User(TableABC):
|
||||
return 0
|
||||
return float(result)
|
||||
|
||||
@property
|
||||
def activity(self) -> int:
|
||||
return self._activity
|
||||
|
||||
@activity.setter
|
||||
def activity(self, value: int):
|
||||
self._activity = value
|
||||
|
||||
@property
|
||||
@ServiceProviderABC.inject
|
||||
def level(self, services: ServiceProviderABC) -> Level:
|
||||
@@ -158,6 +168,13 @@ class User(TableABC):
|
||||
game_idents_repo: UserGameIdentRepositoryABC = services.get_service(UserGameIdentRepositoryABC)
|
||||
return game_idents_repo.get_user_game_idents_by_user_id(self.id)
|
||||
|
||||
@property
|
||||
@ServiceProviderABC.inject
|
||||
def profile_picture_url(self, bot: DiscordBotServiceABC) -> str:
|
||||
guild = bot.get_guild(self.server.discord_id)
|
||||
user = guild.get_member(self._discord_id)
|
||||
return None if user is None else user.avatar.url
|
||||
|
||||
@staticmethod
|
||||
def get_select_all_string() -> str:
|
||||
return str(
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import datetime
|
||||
from typing import Optional
|
||||
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_core.type import T, R
|
||||
from cpl_query.extension import List
|
||||
|
||||
from bot_core.logging.database_logger import DatabaseLogger
|
||||
@@ -38,7 +40,9 @@ class UserRepositoryService(UserRepositoryABC):
|
||||
|
||||
def get_users(self) -> List[User]:
|
||||
self._logger.trace(__name__, f"Send SQL command: {User.get_select_all_string()}")
|
||||
return List(User, [self._from_result(user) for user in self._context.select(User.get_select_all_string())])
|
||||
return List(
|
||||
User, [self._from_result(user) for user in self._context.select(User.get_select_all_string())]
|
||||
).for_each(lambda x: self._set_user_activity(x))
|
||||
|
||||
def get_user_by_id(self, id: int) -> User:
|
||||
self._logger.trace(__name__, f"Send SQL command: {User.get_select_by_id_string(id)}")
|
||||
@@ -77,6 +81,16 @@ class UserRepositoryService(UserRepositoryABC):
|
||||
[self._from_result(user) for user in self._context.select(User.get_select_by_server_id_string(server_id))],
|
||||
)
|
||||
|
||||
def get_users_with_activity_by_server_id(self, server_id: int) -> List[User]:
|
||||
self._logger.trace(
|
||||
__name__,
|
||||
f"Send SQL command: {User.get_select_by_server_id_string(server_id)}",
|
||||
)
|
||||
return List(
|
||||
User,
|
||||
[self._from_result(user) for user in self._context.select(User.get_select_by_server_id_string(server_id))],
|
||||
).for_each(lambda x: self._set_user_activity(x))
|
||||
|
||||
def get_user_by_discord_id_and_server_id(self, discord_id: int, server_id: int) -> User:
|
||||
self._logger.trace(
|
||||
__name__,
|
||||
@@ -109,3 +123,91 @@ class UserRepositoryService(UserRepositoryABC):
|
||||
def delete_user(self, user: User):
|
||||
self._logger.trace(__name__, f"Send SQL command: {user.delete_string}")
|
||||
self._context.cursor.execute(user.delete_string)
|
||||
|
||||
def _set_user_activity(self, user):
|
||||
days = (datetime.date.today() - (datetime.date.today() - datetime.timedelta(days=7))).days
|
||||
query = f"""
|
||||
SELECT (
|
||||
(
|
||||
SELECT Count(UserGotAchievements.CreatedAt)
|
||||
FROM UserGotAchievements
|
||||
INNER JOIN Achievements ON UserGotAchievements.AchievementId = Achievements.Id
|
||||
INNER JOIN Users ON UserGotAchievements.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserGotAchievements.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) +
|
||||
(
|
||||
SELECT SUM(
|
||||
UserMessageCountPerHour.XPCount / (
|
||||
SELECT XpPerMessage
|
||||
FROM CFG_Server
|
||||
WHERE ServerId = {user.server.id}
|
||||
)
|
||||
)
|
||||
FROM UserMessageCountPerHour
|
||||
INNER JOIN Users ON UserMessageCountPerHour.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserMessageCountPerHour.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) +
|
||||
(
|
||||
SELECT Count(UserJoinedVoiceChannel.CreatedAt)
|
||||
FROM UserJoinedVoiceChannel
|
||||
INNER JOIN Users ON UserJoinedVoiceChannel.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserJoinedVoiceChannel.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) +
|
||||
(
|
||||
SELECT IFNULL(ROUND(SUM(TIME_TO_SEC(
|
||||
TIMEDIFF(UserJoinedVoiceChannel.LeavedOn, UserJoinedVoiceChannel.JoinedOn)
|
||||
) / 3600), 2), 0)
|
||||
FROM UserJoinedVoiceChannel
|
||||
INNER JOIN Users ON UserJoinedVoiceChannel.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserJoinedVoiceChannel.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) +
|
||||
(
|
||||
SELECT Count(UserJoinedGameServer.CreatedAt)
|
||||
FROM UserJoinedGameServer
|
||||
INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserJoinedGameServer.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) +
|
||||
(
|
||||
SELECT IFNULL(ROUND(SUM(TIME_TO_SEC(
|
||||
TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)
|
||||
) / 3600), 2), 0)
|
||||
FROM UserJoinedGameServer
|
||||
INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserJoinedGameServer.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
) -
|
||||
(
|
||||
SELECT COUNT(UserWarnings.CreatedAt)
|
||||
FROM UserWarnings
|
||||
INNER JOIN Users ON UserWarnings.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {user.server.id}
|
||||
AND Users.UserId = {user.id}
|
||||
AND UserWarnings.CreatedAt >= "{datetime.date.today() - datetime.timedelta(days=7)}"
|
||||
)
|
||||
) / {days} * 1000 as count;
|
||||
"""
|
||||
user.activity = self._cast_query_result(query, int)
|
||||
|
||||
def _cast_query_result(self, query: str, r_type: T) -> Optional[R]:
|
||||
results = self._context.select(query)
|
||||
if len(results) == 0 or len(results[0]) == 0:
|
||||
return None
|
||||
result = results[0][0]
|
||||
default = None
|
||||
if r_type is int or r_type is float:
|
||||
default = 0
|
||||
elif r_type is str:
|
||||
default = ""
|
||||
|
||||
return r_type(result) if result is not None else default
|
||||
|
@@ -64,11 +64,9 @@ class QueryABC(ObjectType):
|
||||
if user == "system" or user.auth_role == AuthRoleEnum.admin:
|
||||
return self._resolve_collection(collection, *args, **kwargs)
|
||||
|
||||
for x in collection.to_list():
|
||||
if not self._can_user_see_element(user, x):
|
||||
collection.remove(x)
|
||||
|
||||
return self._resolve_collection(collection, *args, **kwargs)
|
||||
return self._resolve_collection(
|
||||
collection.where(lambda x: self._can_user_see_element(user, x)), *args, **kwargs
|
||||
)
|
||||
|
||||
self.set_field(f"{name}s", wrapper)
|
||||
self.set_field(f"{name}Count", lambda *args: wrapper(*args).count())
|
||||
|
@@ -9,6 +9,9 @@ type User implements TableWithHistoryQuery {
|
||||
ontime: Float
|
||||
gameOntime: Float
|
||||
level: Level
|
||||
activityScore: Int
|
||||
|
||||
profilePictureURL: String
|
||||
|
||||
joinedServers(filter: UserJoinedServerFilter, page: Page, sort: Sort): [UserJoinedServer]
|
||||
joinedServerCount: Int
|
||||
|
@@ -11,6 +11,7 @@ from flask import request
|
||||
from bot_api.configuration.authentication_settings import AuthenticationSettings
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.service.permission_service import PermissionService
|
||||
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
|
||||
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
@@ -24,7 +25,6 @@ from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.user_joined_game_server import UserJoinedGameServer
|
||||
from bot_data.model.user_role_enum import UserRoleEnum
|
||||
from bot_graphql.abc.query_abc import QueryABC
|
||||
from bot_core.service.permission_service import PermissionService
|
||||
|
||||
|
||||
class UserJoinedGameServerMutation(QueryABC):
|
||||
@@ -79,7 +79,10 @@ class UserJoinedGameServerMutation(QueryABC):
|
||||
)
|
||||
|
||||
def resolve_user_joined(self, *_, input: dict):
|
||||
game_ident = self._user_game_idents.get_user_game_ident_by_ident(input["ident"])
|
||||
game_ident = self._user_game_idents.find_user_game_ident_by_ident(input["ident"])
|
||||
if game_ident is None:
|
||||
return
|
||||
|
||||
user = game_ident.user
|
||||
|
||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{user.server.discord_id}")
|
||||
|
@@ -4,6 +4,7 @@ from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
|
||||
from bot_api.route.route import Route
|
||||
from bot_core.service.permission_service import PermissionService
|
||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
@@ -13,7 +14,6 @@ from bot_data.model.user_role_enum import UserRoleEnum
|
||||
from bot_graphql.abc.query_abc import QueryABC
|
||||
from modules.base.service.user_warnings_service import UserWarningsService
|
||||
from modules.level.service.level_service import LevelService
|
||||
from bot_core.service.permission_service import PermissionService
|
||||
|
||||
|
||||
class UserMutation(QueryABC):
|
||||
@@ -50,7 +50,7 @@ class UserMutation(QueryABC):
|
||||
member = self._bot.get_guild(user.server.discord_id).get_member(
|
||||
auth_user.users.where(lambda x: x.server.id == user.server.id).single().discord_id
|
||||
)
|
||||
if member.id != user.discord_id:
|
||||
if self._permissions.is_member_moderator(member) or member.id != user.discord_id:
|
||||
self._can_user_mutate_data(user.server, UserRoleEnum.moderator)
|
||||
|
||||
new_xp = None
|
||||
|
@@ -86,7 +86,7 @@ class ServerQuery(DataQueryWithHistoryABC):
|
||||
)
|
||||
self.add_collection(
|
||||
"user",
|
||||
lambda server, *_: self._users.get_users_by_server_id(server.id),
|
||||
lambda server, *_: self._users.get_users_with_activity_by_server_id(server.id),
|
||||
UserFilter,
|
||||
)
|
||||
self.add_collection(
|
||||
|
@@ -114,7 +114,9 @@ class ServerStatisticQuery(QueryABC):
|
||||
|
||||
def _resolve_voice_channel_ontime(self, server, *_):
|
||||
query = f"""
|
||||
SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedVoiceChannel.LeavedOn, UserJoinedVoiceChannel.JoinedOn)) / 3600),{server.server.id}) FROM UserJoinedVoiceChannel
|
||||
SELECT IFNULL(ROUND(SUM(
|
||||
TIME_TO_SEC(TIMEDIFF(UserJoinedVoiceChannel.LeavedOn, UserJoinedVoiceChannel.JoinedOn)) / 3600
|
||||
), 2), 0) FROM UserJoinedVoiceChannel
|
||||
INNER JOIN Users ON UserJoinedVoiceChannel.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {server.server.id}
|
||||
AND UserJoinedVoiceChannel.CreatedAt >= "{self._get_date(**server.kwargs)}";
|
||||
@@ -132,7 +134,10 @@ class ServerStatisticQuery(QueryABC):
|
||||
|
||||
def _resolve_game_server_ontime(self, server, *_):
|
||||
query = f"""
|
||||
SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600),2) FROM UserJoinedGameServer
|
||||
SELECT IFNULL(ROUND(SUM(
|
||||
TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600
|
||||
), 2), 0)
|
||||
FROM UserJoinedGameServer
|
||||
INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId
|
||||
WHERE Users.ServerId = {server.server.id}
|
||||
AND UserJoinedGameServer.CreatedAt >= "{self._get_date(**server.kwargs)}";
|
||||
|
@@ -59,6 +59,7 @@ class UserQuery(DataQueryWithHistoryABC):
|
||||
self.set_field("ontime", lambda user, *_: user.ontime)
|
||||
self.set_field("gameOntime", lambda user, *_: user.game_ontime)
|
||||
self.set_field("level", lambda user, *_: user.level)
|
||||
self.set_field("activityScore", lambda user, *_: user.activity)
|
||||
self.add_collection(
|
||||
"joinedServer",
|
||||
lambda user, *_: self._ujs.get_user_joined_servers_by_user_id(user.id),
|
||||
@@ -87,3 +88,4 @@ class UserQuery(DataQueryWithHistoryABC):
|
||||
|
||||
self.set_field("server", lambda user, *_: user.server)
|
||||
self.set_field("leftServer", lambda user, *_: user.left_server)
|
||||
self.set_field("profilePictureURL", lambda user, *_: user.profile_picture_url)
|
||||
|
@@ -62,8 +62,8 @@ class BaseModule(ModuleABC):
|
||||
services.add_transient(BaseReactionHandler)
|
||||
services.add_singleton(EventService)
|
||||
services.add_transient(UserWarningsService)
|
||||
services.add_singleton(TaskABC, BirthdayWatcher)
|
||||
services.add_singleton(TaskABC, ScheduledEventsWatcher)
|
||||
services.add_transient(TaskABC, BirthdayWatcher)
|
||||
services.add_transient(TaskABC, ScheduledEventsWatcher)
|
||||
|
||||
# forms
|
||||
services.add_transient(BugReportForm)
|
||||
|
@@ -9,6 +9,7 @@ from cpl_translation import TranslatePipe
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
from valve.steam.id import SteamID
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
@@ -50,6 +51,17 @@ class RegisterGroup(DiscordCommandABC):
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
async def _game_server_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> TList[app_commands.Choice[str]]:
|
||||
server = self._servers.get_server_by_discord_id(interaction.guild.id)
|
||||
game_servers = self._game_server.get_game_servers_by_server_id(server.id)
|
||||
|
||||
return [
|
||||
app_commands.Choice(name=gs.name, value=gs.id)
|
||||
for gs in self._client_utils.get_auto_complete_list(game_servers, current, lambda x: x.name)
|
||||
]
|
||||
|
||||
@commands.hybrid_group()
|
||||
@commands.guild_only()
|
||||
async def register(self, ctx: Context):
|
||||
@@ -101,10 +113,44 @@ class RegisterGroup(DiscordCommandABC):
|
||||
async def game_server_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> TList[app_commands.Choice[str]]:
|
||||
server = self._servers.get_server_by_discord_id(interaction.guild.id)
|
||||
game_servers = self._game_server.get_game_servers_by_server_id(server.id)
|
||||
return await self._game_server_autocomplete(interaction, current)
|
||||
|
||||
return [
|
||||
app_commands.Choice(name=gs.name, value=gs.id)
|
||||
for gs in self._client_utils.get_auto_complete_list(game_servers, current, lambda x: x.name)
|
||||
]
|
||||
@register.command()
|
||||
@commands.guild_only()
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_moderator()
|
||||
async def gmod(self, ctx: Context, member: discord.Member, game_server: int, steam_url: str):
|
||||
self._logger.debug(__name__, f"Received command register gmod {ctx}")
|
||||
|
||||
steam_id = None
|
||||
try:
|
||||
self._logger.debug(__name__, f"Try to get steam id for {id}")
|
||||
steam_id = SteamID.from_community_url(steam_url)
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Get steam id for {steam_id} failed", e)
|
||||
await self._message_service.send_interaction_msg(
|
||||
ctx.interaction, self._t.transform("modules.base.register.not_found")
|
||||
)
|
||||
|
||||
if steam_id is None:
|
||||
return
|
||||
|
||||
server = self._servers.get_server_by_discord_id(ctx.guild.id)
|
||||
user = self._users.get_user_by_discord_id_and_server_id(member.id, server.id)
|
||||
gs = self._game_server.get_game_server_by_id(game_server)
|
||||
|
||||
game_ident = UserGameIdent(user, gs, steam_id)
|
||||
self._user_game_ident.add_user_game_ident(game_ident)
|
||||
self._db.save_changes()
|
||||
|
||||
await self._message_service.send_interaction_msg(
|
||||
ctx.interaction, self._t.transform("modules.base.register.success")
|
||||
)
|
||||
|
||||
self._logger.trace(__name__, f"Finished register gmod command")
|
||||
|
||||
@gmod.autocomplete("game_server")
|
||||
async def game_server_autocomplete(
|
||||
self, interaction: discord.Interaction, current: str
|
||||
) -> TList[app_commands.Choice[str]]:
|
||||
return await self._game_server_autocomplete(interaction, current)
|
||||
|
@@ -1,22 +1,34 @@
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_discord.command import DiscordCommandABC
|
||||
from cpl_translation import TranslatePipe
|
||||
from discord.ext import commands
|
||||
from discord.ext.commands import Context
|
||||
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.command_checks import CommandChecks
|
||||
from bot_core.logging.command_logger import CommandLogger
|
||||
from bot_core.service.message_service import MessageService
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.base.service.event_service import EventService
|
||||
|
||||
|
||||
class ScheduledEventsCommand(DiscordCommandABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: CommandLogger,
|
||||
events: EventService,
|
||||
message_service: MessageService,
|
||||
t: TranslatePipe,
|
||||
):
|
||||
DiscordCommandABC.__init__(self)
|
||||
|
||||
self._config = config
|
||||
self._logger = logger
|
||||
self._events = events
|
||||
self._message_service = message_service
|
||||
self._t = t
|
||||
|
||||
self._logger.trace(__name__, f"Loaded command service: {type(self).__name__}")
|
||||
|
||||
@@ -30,6 +42,12 @@ class ScheduledEventsCommand(DiscordCommandABC):
|
||||
@CommandChecks.check_is_ready()
|
||||
@CommandChecks.check_is_member_moderator()
|
||||
async def reload(self, ctx: Context):
|
||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{ctx.guild.id}")
|
||||
if not FeatureFlagsSettings.get_flag_from_dict(settings.feature_flags, FeatureFlagsEnum.scheduled_events):
|
||||
self._logger.debug(__name__, f"Skipping scheduled event check for {ctx.guild.id}. Feature is disabled.")
|
||||
await self._message_service.send_ctx_msg(ctx, self._t.transform("common.feature_not_activated"))
|
||||
return
|
||||
|
||||
self._logger.debug(__name__, "Running scheduled-events reload")
|
||||
try:
|
||||
await self._events.check_and_create_scheduled_events(ctx.guild)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_core.time import TimeFormatSettings
|
||||
from cpl_discord.events.on_command_error_abc import OnCommandErrorABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
@@ -12,13 +11,14 @@ from discord.ext.commands import Context, CommandError
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.exception.check_error import CheckError
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
|
||||
|
||||
class BaseOnCommandErrorEvent(OnCommandErrorABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
messenger: MessageServiceABC,
|
||||
tech_settings: TechnicianConfig,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnGuildJoinABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from discord import Guild
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.model.server import Server
|
||||
@@ -14,7 +14,7 @@ from bot_data.service.seeder_service import SeederService
|
||||
class BaseOnGuildJoinEvent(OnGuildJoinABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
servers: ServerRepositoryABC,
|
||||
server_config: ServerConfigRepositoryABC,
|
||||
|
@@ -4,14 +4,15 @@ from typing import Union
|
||||
import discord
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnMemberJoinABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
from cpl_translation import TranslatePipe
|
||||
|
||||
from bot_core.abc.client_utils_abc import ClientUtilsABC
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.abc.permission_service_abc import PermissionServiceABC
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
||||
@@ -20,14 +21,13 @@ from bot_data.model.known_user import KnownUser
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.user import User
|
||||
from bot_data.model.user_joined_server import UserJoinedServer
|
||||
from bot_core.abc.permission_service_abc import PermissionServiceABC
|
||||
|
||||
|
||||
class BaseOnMemberJoinEvent(OnMemberJoinABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
messenger: MessageServiceABC,
|
||||
permissions: PermissionServiceABC,
|
||||
db: DatabaseContextABC,
|
||||
|
@@ -4,12 +4,12 @@ from typing import Union
|
||||
import discord
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnMemberRemoveABC
|
||||
from cpl_translation import TranslatePipe
|
||||
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
@@ -20,7 +20,7 @@ class BaseOnMemberRemoveEvent(OnMemberRemoveABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
db: DatabaseContextABC,
|
||||
message_service: MessageServiceABC,
|
||||
users: UserRepositoryABC,
|
||||
|
@@ -4,6 +4,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
||||
from discord import RawReactionActionEvent
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
||||
@@ -12,7 +13,7 @@ from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
||||
class BaseOnRawReactionAddEvent(OnRawReactionAddABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
servers: ServerRepositoryABC,
|
||||
auto_roles: AutoRoleRepositoryABC,
|
||||
|
@@ -4,6 +4,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
||||
from discord import RawReactionActionEvent
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
||||
@@ -12,7 +13,7 @@ from modules.base.helper.base_reaction_handler import BaseReactionHandler
|
||||
class BaseOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
servers: ServerRepositoryABC,
|
||||
auto_roles: AutoRoleRepositoryABC,
|
||||
|
@@ -5,6 +5,7 @@ from cpl_discord.service import DiscordBotServiceABC
|
||||
from discord import EventStatus
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from modules.base.model.active_event import ActiveEvent
|
||||
from modules.base.service.event_service import EventService
|
||||
|
||||
@@ -12,7 +13,7 @@ from modules.base.service.event_service import EventService
|
||||
class BaseOnScheduledEventUpdateEvent(OnScheduledEventUpdateABC):
|
||||
def __init__(
|
||||
self,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
events: EventService,
|
||||
):
|
||||
|
@@ -8,6 +8,7 @@ from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnVoiceStateUpdateABC
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
|
||||
@@ -25,7 +26,7 @@ class BaseOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
servers: ServerRepositoryABC,
|
||||
known_users: KnownUserRepositoryABC,
|
||||
users: UserRepositoryABC,
|
||||
|
@@ -6,6 +6,7 @@ from cpl_translation import TranslatePipe
|
||||
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_core.abc.permission_service_abc import PermissionServiceABC
|
||||
@@ -15,7 +16,7 @@ class BaseOnVoiceStateUpdateEventHelpChannel(OnVoiceStateUpdateABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
servers: ServerRepositoryABC,
|
||||
permissions: PermissionServiceABC,
|
||||
message_service: MessageServiceABC,
|
||||
|
@@ -5,6 +5,7 @@ from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnVoiceStateUpdateABC
|
||||
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.user_repository_abc import UserRepositoryABC
|
||||
from modules.base.service.event_service import EventService
|
||||
@@ -14,7 +15,7 @@ class BaseOnVoiceStateUpdateEventScheduledEventBonus(OnVoiceStateUpdateABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
servers: ServerRepositoryABC,
|
||||
users: UserRepositoryABC,
|
||||
events: EventService,
|
||||
|
@@ -9,7 +9,7 @@ from cpl_core.database.context import DatabaseContextABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.container import Guild
|
||||
from cpl_query.extension import List
|
||||
from discord import PrivacyLevel
|
||||
from discord import PrivacyLevel, EventStatus
|
||||
from discord.scheduled_event import ScheduledEvent as DiscordEvent
|
||||
|
||||
from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC
|
||||
@@ -99,14 +99,17 @@ class EventService:
|
||||
async def check_and_create_scheduled_events(self, guild: Guild):
|
||||
server = self._servers.get_server_by_discord_id(guild.id)
|
||||
scheduled_events_from_db = self._events.get_scheduled_events_by_server_id(server.id)
|
||||
self._logger.debug(__name__, f"Checking {scheduled_events_from_db.count()} events for server {guild.id}")
|
||||
for scheduled_event in scheduled_events_from_db:
|
||||
scheduled_event: ScheduledEvent = scheduled_event
|
||||
from_guild = List(DiscordEvent, guild.scheduled_events).where(
|
||||
lambda x: x.name == scheduled_event.name
|
||||
and x.description == scheduled_event.description
|
||||
and x.entity_type == scheduled_event.entity_type
|
||||
and x.status == EventStatus.scheduled
|
||||
)
|
||||
if from_guild.count() != 0:
|
||||
self._logger.debug(__name__, f"Event {scheduled_event.name} already exists on discord server")
|
||||
continue
|
||||
|
||||
kwargs = {"name": scheduled_event.name, "description": scheduled_event.description}
|
||||
@@ -119,14 +122,14 @@ class EventService:
|
||||
scheduled_event.interval, scheduled_event.start_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
|
||||
)
|
||||
kwargs["start_time"] = start_time
|
||||
scheduled_event.start_time = scheduled_event.start_time.replace(tzinfo=None)
|
||||
scheduled_event.start_time = start_time.replace(tzinfo=None)
|
||||
|
||||
if scheduled_event.end_time is not None:
|
||||
end_time = self._append_interval(
|
||||
scheduled_event.interval, scheduled_event.end_time.replace(tzinfo=ZoneInfo("Europe/Berlin"))
|
||||
)
|
||||
kwargs["end_time"] = end_time
|
||||
scheduled_event.end_time = scheduled_event.end_time.replace(tzinfo=None)
|
||||
scheduled_event.end_time = end_time.replace(tzinfo=None)
|
||||
|
||||
kwargs["entity_type"] = scheduled_event.entity_type
|
||||
if scheduled_event.location is not None:
|
||||
@@ -135,9 +138,10 @@ class EventService:
|
||||
kwargs["privacy_level"] = PrivacyLevel.guild_only
|
||||
|
||||
try:
|
||||
self._logger.debug(__name__, f"Try to create scheduled event for guild {guild.name}")
|
||||
self._logger.trace(__name__, f"Try to create scheduled event for guild {guild.name}")
|
||||
await guild.create_scheduled_event(**kwargs)
|
||||
self._events.update_scheduled_event(scheduled_event)
|
||||
self._db.save_changes()
|
||||
self._logger.debug(__name__, f"Created scheduled event for guild {guild.name}")
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Watching scheduled events failed", e)
|
||||
|
@@ -37,7 +37,7 @@ class BirthdayWatcher(TaskABC):
|
||||
if not self._is_maintenance():
|
||||
self.watch.start()
|
||||
|
||||
@tasks.loop(time=datetime.time(hour=8, minute=0))
|
||||
@tasks.loop(time=datetime.time(hour=8, minute=0), reconnect=True)
|
||||
async def watch(self):
|
||||
self._logger.info(__name__, "Watching birthdays")
|
||||
try:
|
||||
|
@@ -5,9 +5,12 @@ from cpl_translation import TranslatePipe
|
||||
from discord.ext import tasks
|
||||
|
||||
from bot_core.abc.task_abc import TaskABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.logging.task_logger import TaskLogger
|
||||
from bot_core.service.message_service import MessageService
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.base.service.event_service import EventService
|
||||
|
||||
|
||||
@@ -37,11 +40,18 @@ class ScheduledEventsWatcher(TaskABC):
|
||||
if not self._is_maintenance():
|
||||
self.watch.start()
|
||||
|
||||
@tasks.loop(hours=12)
|
||||
@tasks.loop(hours=3, reconnect=True)
|
||||
async def watch(self):
|
||||
self._logger.info(__name__, "Watching scheduled events")
|
||||
try:
|
||||
for guild in self._bot.guilds:
|
||||
settings: ServerConfig = self._config.get_configuration(f"ServerConfig_{guild.id}")
|
||||
if not FeatureFlagsSettings.get_flag_from_dict(
|
||||
settings.feature_flags, FeatureFlagsEnum.scheduled_events
|
||||
):
|
||||
self._logger.debug(__name__, f"Skipping scheduled event check for {guild.id}. Feature is disabled.")
|
||||
continue
|
||||
|
||||
await self._events.check_and_create_scheduled_events(guild)
|
||||
except Exception as e:
|
||||
self._logger.error(__name__, f"Watching scheduled events failed", e)
|
||||
|
@@ -10,6 +10,7 @@ from discord import guild
|
||||
from bot_core.abc.message_service_abc import MessageServiceABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from bot_data.model.technician_config import TechnicianConfig
|
||||
|
||||
@@ -18,7 +19,7 @@ class BootLogOnReadyEvent(OnReadyABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
message_service: MessageServiceABC,
|
||||
translate: TranslatePipe,
|
||||
|
@@ -1,8 +1,8 @@
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
from cpl_discord.events import OnReadyABC
|
||||
from cpl_discord.service import DiscordBotServiceABC
|
||||
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_core.service.config_service import ConfigService
|
||||
from bot_core.service.data_integrity_service import DataIntegrityService
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
@@ -12,7 +12,7 @@ class ConfigOnReadyEvent(OnReadyABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
servers: ServerRepositoryABC,
|
||||
config_service: ConfigService,
|
||||
|
@@ -5,13 +5,14 @@ from cpl_discord.events import OnMemberJoinABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_core.logging.message_logger import MessageLogger
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.level.service.level_service import LevelService
|
||||
|
||||
|
||||
class LevelOnMemberJoinEvent(OnMemberJoinABC):
|
||||
def __init__(self, config: ConfigurationABC, logger: MessageLogger, level: LevelService):
|
||||
def __init__(self, config: ConfigurationABC, logger: EventLogger, level: LevelService):
|
||||
OnMemberJoinABC.__init__(self)
|
||||
self._config = config
|
||||
self._logger = logger
|
||||
|
@@ -7,6 +7,7 @@ from discord import RawReactionActionEvent
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.level.service.level_service import LevelService
|
||||
|
||||
@@ -15,7 +16,7 @@ class LevelOnRawReactionAddEvent(OnRawReactionAddABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
level: LevelService,
|
||||
):
|
||||
|
@@ -7,6 +7,7 @@ from discord import RawReactionActionEvent
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.level.service.level_service import LevelService
|
||||
|
||||
@@ -15,7 +16,7 @@ class LevelOnRawReactionRemoveEvent(OnRawReactionRemoveABC):
|
||||
def __init__(
|
||||
self,
|
||||
config: ConfigurationABC,
|
||||
logger: LoggerABC,
|
||||
logger: EventLogger,
|
||||
bot: DiscordBotServiceABC,
|
||||
level: LevelService,
|
||||
):
|
||||
|
@@ -6,12 +6,13 @@ from cpl_discord.events import OnVoiceStateUpdateABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
|
||||
from bot_core.helper.event_checks import EventChecks
|
||||
from bot_core.logging.event_logger import EventLogger
|
||||
from bot_data.model.server_config import ServerConfig
|
||||
from modules.level.service.level_service import LevelService
|
||||
|
||||
|
||||
class LevelOnVoiceStateUpdateEvent(OnVoiceStateUpdateABC):
|
||||
def __init__(self, config: ConfigurationABC, logger: LoggerABC, level: LevelService):
|
||||
def __init__(self, config: ConfigurationABC, logger: EventLogger, level: LevelService):
|
||||
OnVoiceStateUpdateABC.__init__(self)
|
||||
self._config = config
|
||||
self._logger = logger
|
||||
|
@@ -17,6 +17,6 @@ class SteamSpecialOffersModule(ModuleABC):
|
||||
pass
|
||||
|
||||
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
|
||||
services.add_singleton(TaskABC, SteamOfferWatcher)
|
||||
services.add_transient(TaskABC, SteamOfferWatcher)
|
||||
# commands
|
||||
# events
|
||||
|
@@ -187,7 +187,7 @@ class SteamOfferWatcher(TaskABC):
|
||||
self._logger.trace(__name__, "Finished watching")
|
||||
return offers_for_notifications
|
||||
|
||||
@tasks.loop(hours=4)
|
||||
@tasks.loop(hours=4, reconnect=True)
|
||||
async def watch(self):
|
||||
self._logger.info(__name__, "Watching steam special offers")
|
||||
try:
|
||||
|
@@ -18,6 +18,7 @@ export interface User extends DataWithHistory {
|
||||
ontime?: number;
|
||||
gameOntime?: number;
|
||||
level?: Level;
|
||||
activityScore?: number;
|
||||
server?: Server;
|
||||
leftServer?: boolean;
|
||||
|
||||
@@ -35,6 +36,8 @@ export interface User extends DataWithHistory {
|
||||
|
||||
userWarningCount?: number;
|
||||
userWarnings?: UserWarning[];
|
||||
|
||||
profilePictureURL?: string;
|
||||
}
|
||||
|
||||
export interface UserFilter {
|
||||
|
@@ -362,6 +362,7 @@ export class Queries {
|
||||
xp
|
||||
ontime
|
||||
gameOntime
|
||||
activityScore
|
||||
level {
|
||||
id
|
||||
name
|
||||
@@ -388,6 +389,7 @@ export class Queries {
|
||||
birthday
|
||||
ontime
|
||||
gameOntime
|
||||
activityScore
|
||||
level {
|
||||
id
|
||||
name
|
||||
@@ -404,6 +406,7 @@ export class Queries {
|
||||
joinedOn
|
||||
leavedOn
|
||||
}
|
||||
profilePictureURL
|
||||
|
||||
createdAt
|
||||
modifiedAt
|
||||
|
@@ -40,6 +40,7 @@ import { TabViewModule } from "primeng/tabview";
|
||||
import { RadioButtonModule } from "primeng/radiobutton";
|
||||
import { InputTextareaModule } from "primeng/inputtextarea";
|
||||
import { InputMaskModule } from "primeng/inputmask";
|
||||
import { KnobModule } from "primeng/knob";
|
||||
|
||||
|
||||
const PrimeNGModules = [
|
||||
@@ -73,7 +74,8 @@ const PrimeNGModules = [
|
||||
TabViewModule,
|
||||
RadioButtonModule,
|
||||
InputTextareaModule,
|
||||
InputMaskModule
|
||||
InputMaskModule,
|
||||
KnobModule
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@@ -74,6 +74,13 @@
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th hideable-th="activity" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.activity' | translate}}</div>
|
||||
<p-sortIcon field="activityScore" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th hideable-th="left_server" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.left_server' | translate}}</div>
|
||||
@@ -127,6 +134,7 @@
|
||||
<th hideable-th="xp" [parent]="this"></th>
|
||||
<th hideable-th="ontime" [parent]="this"></th>
|
||||
<th hideable-th="game_ontime" [parent]="this"></th>
|
||||
<th hideable-th="activity" [parent]="this"></th>
|
||||
<th hideable-th="left_server" [parent]="this" class="table-header-small-dropdown">
|
||||
<form [formGroup]="filterForm">
|
||||
<p-dropdown formControlName="leftServer" [options]="leftServerOptions"
|
||||
@@ -213,6 +221,17 @@
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td hideable-th="activity" [parent]="this">
|
||||
<span class="p-column-title">{{'common.activity' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
{{member.activityScore}}
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{member.activityScore}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td hideable-th="left_server" [parent]="this">
|
||||
<span class="p-column-title">{{'common.left_server' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
|
@@ -89,7 +89,7 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe
|
||||
private data: DataService,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
super("member", ["id", "discord_id", "name", "xp", "ontime", "game_ontime", "left_server", "level"]);
|
||||
super("member", ["id", "discord_id", "name", "xp", "ontime", "game_ontime", "activity", "left_server", "level"]);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@@ -2,112 +2,95 @@
|
||||
{{'view.server.profile.header' | translate}}
|
||||
</h1>
|
||||
<div class="content-wrapper">
|
||||
<div class="content-header">
|
||||
<h2>
|
||||
{{user.name}}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.id' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.id}}</div>
|
||||
<div class="logo">
|
||||
<img *ngIf="user ? user.profilePictureURL : ''" [src]="user ? user.profilePictureURL : ''">
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.discord_id' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.discordId}}</div>
|
||||
<div class="content">
|
||||
<div class="content-column">
|
||||
<h1>{{user.name}}</h1>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.id' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.id}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.discord_id' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.discordId}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.message_count' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.messageCount}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.reaction_count' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.reactionCount}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.birthday' | translate}}:</div>
|
||||
<div *ngIf="!isEditing" class="content-data-value">{{user.birthday}}</div>
|
||||
<div *ngIf="isEditing" class="content-data-value">
|
||||
<p-calendar [(ngModel)]="user.birthday" dateFormat="dd.mm.yy"
|
||||
[showIcon]="true"></p-calendar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-divider"></div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.left_server' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.leftServer | bool}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.created_at' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.modified_at' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.modifiedAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name" style="flex-direction: column; justify-content: start;">
|
||||
<p-knob valueTemplate="{value} {{'view.server.profile.xp' | translate}}" [(ngModel)]="user.xp" [size]="150"
|
||||
[strokeWidth]="10"
|
||||
[max]="maxXp" valueColor="SlateGray" rangeColor="MediumTurquoise"
|
||||
[readonly]="isModerator && !isEditing"></p-knob>
|
||||
</div>
|
||||
<div class="content-data-value" style="flex-direction: column; justify-content: start;">
|
||||
<p-knob valueTemplate="Lvl {value}" [(ngModel)]="activeLevelIndex"
|
||||
[size]="150"
|
||||
[strokeWidth]="10"
|
||||
[min]="1"
|
||||
[max]="levels ? levels.length : 0" valueColor="SlateGray" rangeColor="MediumTurquoise"
|
||||
[readonly]="isModerator && !isEditing"></p-knob>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.name' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.xp' | translate}}:</div>
|
||||
<div *ngIf="!isEditing" class="content-data-value">{{user.xp}}</div>
|
||||
<div *ngIf="isModerator && isEditing" class="content-data-value"><input class="table-edit-input" pInputText
|
||||
min="0" type="number"
|
||||
[(ngModel)]="user.xp"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.message_count' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.messageCount}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.reaction_count' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.reactionCount}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.birthday' | translate}}:</div>
|
||||
<div *ngIf="!isEditing" class="content-data-value">{{user.birthday}}</div>
|
||||
<div *ngIf="isEditing" class="content-data-value">
|
||||
<p-calendar [(ngModel)]="user.birthday" dateFormat="dd.mm.yy" [showIcon]="true"></p-calendar>
|
||||
<div *ngIf="user.level">
|
||||
{{user.level.name}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-divider"></div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.ontime' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.ontime}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.game_ontime' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.gameOntime}}</div>
|
||||
</div>
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.activity' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.activityScore}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.ontime' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.ontime}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.game_ontime' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.gameOntime}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.level' | translate}}:</div>
|
||||
<div *ngIf="!isEditing" class="content-data-value">{{user.level?.name}}</div>
|
||||
<div *ngIf="isModerator && isEditing" class="content-data-value">
|
||||
<p-dropdown [options]="levels" [(ngModel)]="user.level" dataKey="id"
|
||||
placeholder="{{'common.level' | translate}}">
|
||||
</p-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'view.server.profile.left_server' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.leftServer | bool}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.created_at' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.createdAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-row">
|
||||
<div class="content-column">
|
||||
<div class="content-data-name">{{'common.modified_at' | translate}}:</div>
|
||||
<div class="content-data-value">{{user.modifiedAt | date:'dd.MM.yyyy HH:mm:ss'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div>
|
||||
<div class="content-divider"></div>
|
||||
<p-table #dt [value]="(user.userWarnings ?? [])" [responsive]="true" responsiveLayout="stack"
|
||||
@@ -192,7 +175,8 @@
|
||||
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash"
|
||||
(click)="deleteUserWarning(ri)"></button>
|
||||
|
||||
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check"
|
||||
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn"
|
||||
icon="pi pi-check"
|
||||
(click)="editSaveUserWarning(value, ri)"></button>
|
||||
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn"
|
||||
icon="pi pi-times"
|
||||
|
@@ -0,0 +1,6 @@
|
||||
.logo {
|
||||
img {
|
||||
width: 12.5vw;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
@@ -15,10 +15,10 @@ import { catchError, takeUntil } from "rxjs/operators";
|
||||
import { Table } from "primeng/table";
|
||||
import { UpdateUserMutationResult } from "../../../../models/graphql/result.model";
|
||||
import { Mutations } from "../../../../models/graphql/mutations.model";
|
||||
import { MenuItem } from "primeng/api";
|
||||
import { UserWarning } from "../../../../models/data/user_warning.model";
|
||||
import moment from "moment";
|
||||
import { SidebarService } from "../../../../services/sidebar/sidebar.service";
|
||||
import { Level } from "../../../../models/data/level.model";
|
||||
|
||||
@Component({
|
||||
selector: "app-profile",
|
||||
@@ -28,7 +28,7 @@ import { SidebarService } from "../../../../services/sidebar/sidebar.service";
|
||||
export class ProfileComponent implements OnInit, OnDestroy {
|
||||
|
||||
user: User = { createdAt: "", modifiedAt: "" };
|
||||
levels!: MenuItem[];
|
||||
levels!: { label: string, value: Level }[];
|
||||
private server: Server = {};
|
||||
private author?: UserDTO;
|
||||
private clonedUserWarnings: UserWarning[] = [];
|
||||
@@ -36,6 +36,21 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
public isEditing: boolean = false;
|
||||
public isModerator: boolean = false;
|
||||
public hasTechnicianAccess: boolean = false;
|
||||
public maxXp: number = 0;
|
||||
private _activeLevelIndex: number = 0;
|
||||
|
||||
public get activeLevelIndex(): number {
|
||||
return this._activeLevelIndex;
|
||||
}
|
||||
|
||||
public set activeLevelIndex(value: number) {
|
||||
if (value < 1) {
|
||||
value = 1;
|
||||
}
|
||||
|
||||
this._activeLevelIndex = value;
|
||||
this.user.level = this.levels.map(x => x.value)[value - 1];
|
||||
}
|
||||
|
||||
private unsubscriber = new Subject<void>();
|
||||
|
||||
@@ -48,7 +63,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
private toast: ToastService,
|
||||
private translate: TranslateService,
|
||||
private toastService: ToastService,
|
||||
private sidebarService: SidebarService,
|
||||
private sidebarService: SidebarService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -74,7 +89,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
).subscribe(data => {
|
||||
this.levels = data.levels.map(level => {
|
||||
return { label: level.name, value: level };
|
||||
return { label: level.name ?? "", value: level };
|
||||
});
|
||||
});
|
||||
|
||||
@@ -100,6 +115,11 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate([`/server/${server.id}`]);
|
||||
}
|
||||
this.user = users.users[0];
|
||||
const minXps = this.levels.reverse().map(x => x.value.minXp ?? 0);
|
||||
this.maxXp = minXps.filter(x => this.user.xp && x > this.user.xp)[0] ?? this.user.xp;
|
||||
if (this.user.level) {
|
||||
this.activeLevelIndex = this.levels.map(l => l.value.id).indexOf(this.user.level.id) + 1;
|
||||
}
|
||||
|
||||
this.data.query<UserWarningQuery>(Queries.userProfileWarnings, {
|
||||
serverId: this.server.id,
|
||||
@@ -128,7 +148,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
this.data.mutation<UpdateUserMutationResult>(Mutations.updateUser, {
|
||||
id: this.user.id,
|
||||
xp: this.user.xp,
|
||||
birthday: moment(this.user.birthday).format("DD.MM.YYYY"),
|
||||
birthday: moment(this.user.birthday, "DD.MM.YYYY").format("DD.MM.YYYY"),
|
||||
levelId: this.user.level?.id,
|
||||
userWarnings: this.user.userWarnings?.map(userWarning => {
|
||||
return {
|
||||
|
@@ -127,6 +127,7 @@
|
||||
"abort": "Abbrechen",
|
||||
"actions": "Aktionen",
|
||||
"active": "Aktiv",
|
||||
"activity": "Aktivität",
|
||||
"add": "Hinzufügen",
|
||||
"attribute": "Attribut",
|
||||
"auth_role": "Rolle",
|
||||
@@ -540,6 +541,7 @@
|
||||
},
|
||||
"left_server": "Hat Server verlassen",
|
||||
"level": "Level",
|
||||
"lvl": "Lvl",
|
||||
"message_count": "Anzahl Nachrichten",
|
||||
"minecraft_id": "Minecraft Id",
|
||||
"name": "Name",
|
||||
|
@@ -127,6 +127,7 @@
|
||||
"abort": "Abort",
|
||||
"actions": "Actions",
|
||||
"active": "Active",
|
||||
"activity": "Activity",
|
||||
"add": "Add",
|
||||
"attribute": "Attribute",
|
||||
"auth_role": "Role",
|
||||
@@ -540,6 +541,7 @@
|
||||
},
|
||||
"left_server": "Leaved server",
|
||||
"level": "Level",
|
||||
"lvl": "Lvl",
|
||||
"message_count": "Message count",
|
||||
"minecraft_id": "Minecraft Id",
|
||||
"name": "Name",
|
||||
|
@@ -177,40 +177,40 @@ header {
|
||||
flex: 1;
|
||||
margin: 5px 0;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.content-column {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 5px;
|
||||
.content-column {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.content-data-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 18px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.content-data-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 18px;
|
||||
flex: 1;
|
||||
|
||||
input {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content-data-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.content-data-value-row {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
font-size: 18px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.content-data-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 18px;
|
||||
flex: 1;
|
||||
|
||||
input {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content-data-value-row {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
font-size: 18px;
|
||||
}
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.content-divider {
|
||||
|
@@ -814,4 +814,22 @@
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
p-knob {
|
||||
.p-knob {
|
||||
svg {
|
||||
.p-knob-value {
|
||||
stroke: $primaryHeaderColor !important;
|
||||
}
|
||||
|
||||
.p-knob-range {
|
||||
stroke: $secondaryBackgroundColor !important;
|
||||
}
|
||||
|
||||
.p-knob-text {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user