Improved ontime loading & added game ontime #446 #449
| @@ -2,6 +2,7 @@ from datetime import datetime, date | ||||
| from typing import Optional | ||||
|  | ||||
| from cpl_core.database import TableABC | ||||
| from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_core.dependency_injection import ServiceProviderABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| from cpl_query.extension import List | ||||
| @@ -92,10 +93,32 @@ class User(TableABC): | ||||
|     @property | ||||
|     @ServiceProviderABC.inject | ||||
|     def ontime(self, services: ServiceProviderABC) -> float: | ||||
|         from bot_core.abc.client_utils_abc import ClientUtilsABC | ||||
|         db: DatabaseContextABC = services.get_service(DatabaseContextABC) | ||||
|         result = db.select( | ||||
|             f""" | ||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedVoiceChannel.LeavedOn, UserJoinedVoiceChannel.JoinedOn)) / 3600),2) | ||||
|             FROM UserJoinedVoiceChannel | ||||
|             WHERE UserId = {self._user_id}; | ||||
|         """ | ||||
|         )[0][0] | ||||
|         if result is None: | ||||
|             return 0 | ||||
|         return float(result) | ||||
|  | ||||
|         client_utils: ClientUtilsABC = services.get_service(ClientUtilsABC) | ||||
|         return client_utils.get_ontime_for_user(self) | ||||
|     @property | ||||
|     @ServiceProviderABC.inject | ||||
|     def game_ontime(self, services: ServiceProviderABC) -> float: | ||||
|         db: DatabaseContextABC = services.get_service(DatabaseContextABC) | ||||
|         result = db.select( | ||||
|             f""" | ||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600),2) | ||||
|             FROM UserJoinedGameServer | ||||
|             WHERE UserId = {self._user_id}; | ||||
|         """ | ||||
|         )[0][0] | ||||
|         if result is None: | ||||
|             return 0 | ||||
|         return float(result) | ||||
|  | ||||
|     @property | ||||
|     @ServiceProviderABC.inject | ||||
|   | ||||
| @@ -7,6 +7,7 @@ type User implements TableWithHistoryQuery { | ||||
|     reactionCount: Int | ||||
|     birthday: String | ||||
|     ontime: Float | ||||
|     gameOntime: Float | ||||
|     level: Level | ||||
|  | ||||
|     joinedServers(filter: UserJoinedServerFilter, page: Page, sort: Sort): [UserJoinedServer] | ||||
|   | ||||
| @@ -132,7 +132,7 @@ class ServerStatisticQuery(QueryABC): | ||||
|  | ||||
|     def _resolve_game_server_ontime(self, server, *_): | ||||
|         query = f""" | ||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600),{server.server.id}) FROM UserJoinedGameServer | ||||
|             SELECT ROUND(SUM(TIME_TO_SEC(TIMEDIFF(UserJoinedGameServer.LeavedOn, UserJoinedGameServer.JoinedOn)) / 3600),2) FROM UserJoinedGameServer | ||||
|             INNER JOIN Users ON UserJoinedGameServer.UserId = Users.UserId | ||||
|             WHERE Users.ServerId = {server.server.id} | ||||
|               AND UserJoinedGameServer.CreatedAt >= "{self._get_date(**server.kwargs)}"; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ from cpl_core.database.context import DatabaseContextABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
|  | ||||
| from bot_core.abc.client_utils_abc import ClientUtilsABC | ||||
| from bot_core.abc.permission_service_abc import PermissionServiceABC | ||||
| from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC | ||||
| from bot_data.abc.user_joined_game_server_repository_abc import ( | ||||
|     UserJoinedGameServerRepositoryABC, | ||||
| @@ -11,7 +12,6 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import ( | ||||
|     UserJoinedVoiceChannelRepositoryABC, | ||||
| ) | ||||
| from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC | ||||
| from bot_data.model.user import User | ||||
| from bot_data.model.user_history import UserHistory | ||||
| from bot_graphql.abc.data_query_with_history_abc import DataQueryWithHistoryABC | ||||
| from bot_graphql.filter.achievement_filter import AchievementFilter | ||||
| @@ -22,7 +22,6 @@ from bot_graphql.filter.user_joined_voice_channel_filter import ( | ||||
| ) | ||||
| from bot_graphql.filter.user_warning_filter import UserWarningFilter | ||||
| from modules.level.service.level_service import LevelService | ||||
| from bot_core.abc.permission_service_abc import PermissionServiceABC | ||||
|  | ||||
|  | ||||
| class UserQuery(DataQueryWithHistoryABC): | ||||
| @@ -50,15 +49,16 @@ class UserQuery(DataQueryWithHistoryABC): | ||||
|         self._permissions = permissions | ||||
|         self._achievements = achievements | ||||
|  | ||||
|         self.set_field("id", self.resolve_id) | ||||
|         self.set_field("discordId", self.resolve_discord_id) | ||||
|         self.set_field("name", self.resolve_name) | ||||
|         self.set_field("xp", self.resolve_xp) | ||||
|         self.set_field("id", lambda user, *_: user.id) | ||||
|         self.set_field("discordId", lambda user, *_: user.discord_id) | ||||
|         self.set_field("name", lambda user, *_: user.name) | ||||
|         self.set_field("xp", lambda user, *_: user.xp) | ||||
|         self.set_field("messageCount", lambda x, *_: x.message_count) | ||||
|         self.set_field("reactionCount", lambda x, *_: x.reaction_count) | ||||
|         self.set_field("birthday", lambda x, *_: None if x.birthday is None else x.birthday.strftime("%d.%m.%Y")) | ||||
|         self.set_field("ontime", self.resolve_ontime) | ||||
|         self.set_field("level", self.resolve_level) | ||||
|         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.add_collection( | ||||
|             "joinedServer", | ||||
|             lambda user, *_: self._ujs.get_user_joined_servers_by_user_id(user.id), | ||||
| @@ -85,37 +85,5 @@ class UserQuery(DataQueryWithHistoryABC): | ||||
|             UserWarningFilter, | ||||
|         ) | ||||
|  | ||||
|         self.set_field("server", self.resolve_server) | ||||
|         self.set_field("leftServer", self.resolve_left_server) | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_id(user: User, *_): | ||||
|         return user.id | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_discord_id(user: User, *_): | ||||
|         return user.discord_id | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_name(user: User, *_): | ||||
|         return user.name | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_xp(user: User, *_): | ||||
|         return user.xp | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_ontime(user: User, *_): | ||||
|         return user.ontime | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_level(user: User, *_): | ||||
|         return user.level | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_server(user: User, *_): | ||||
|         return user.server | ||||
|  | ||||
|     @staticmethod | ||||
|     def resolve_left_server(user: User, *_): | ||||
|         return user.left_server | ||||
|         self.set_field("server", lambda user, *_: user.server) | ||||
|         self.set_field("leftServer", lambda user, *_: user.left_server) | ||||
|   | ||||
| @@ -16,6 +16,7 @@ export interface User extends DataWithHistory { | ||||
|   reactionCount?: number; | ||||
|   birthday?: string; | ||||
|   ontime?: number; | ||||
|   gameOntime?: number; | ||||
|   level?: Level; | ||||
|   server?: Server; | ||||
|   leftServer?: boolean; | ||||
|   | ||||
| @@ -361,6 +361,7 @@ export class Queries { | ||||
|           name | ||||
|           xp | ||||
|           ontime | ||||
|           gameOntime | ||||
|           level { | ||||
|             id | ||||
|             name | ||||
| @@ -386,6 +387,7 @@ export class Queries { | ||||
|         reactionCount | ||||
|         birthday | ||||
|         ontime | ||||
|         gameOntime | ||||
|         level { | ||||
|           id | ||||
|           name | ||||
|   | ||||
| @@ -3,7 +3,8 @@ | ||||
| </h1> | ||||
| <div class="content-wrapper"> | ||||
|   <div class="content"> | ||||
|     <p-table #dt [value]="members" [responsive]="true" responsiveLayout="stack" [breakpoint]="'720px'" dataKey="id" editMode="row" [rowHover]="true" [rows]="10" | ||||
|     <p-table #dt [value]="members" [responsive]="true" responsiveLayout="stack" [breakpoint]="'720px'" dataKey="id" | ||||
|              editMode="row" [rowHover]="true" [rows]="10" | ||||
|              [rowsPerPageOptions]="[10,25,50]" [paginator]="true" [loading]="loading" [totalRecords]="totalRecords" | ||||
|              [lazy]="true" (onLazyLoad)="nextPage($event)"> | ||||
|  | ||||
| @@ -17,7 +18,8 @@ | ||||
|               {{'view.server.members.members' | translate}} | ||||
|             </div> | ||||
|  | ||||
|             <app-multi-select-columns [table]="name" [columns]="columns" [(hiddenColumns)]="hiddenColumns"></app-multi-select-columns> | ||||
|             <app-multi-select-columns [table]="name" [columns]="columns" | ||||
|                                       [(hiddenColumns)]="hiddenColumns"></app-multi-select-columns> | ||||
|           </div> | ||||
|  | ||||
|           <div class="table-caption-btn-wrapper btn-wrapper"> | ||||
| @@ -65,6 +67,13 @@ | ||||
|             </div> | ||||
|           </th> | ||||
|  | ||||
|           <th hideable-th="game_ontime" [parent]="this" [sortable]="true"> | ||||
|             <div class="table-header-label"> | ||||
|               <div class="table-header-text">{{'common.game_ontime' | translate}}</div> | ||||
|               <p-sortIcon field="game_ontime" 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> | ||||
| @@ -106,7 +115,8 @@ | ||||
|           </th> | ||||
|           <th hideable-th="discord_id" [parent]="this" class="table-header-medium"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <input type="text" pInputText formControlName="discordId" placeholder="{{'common.discord_id' | translate}}"> | ||||
|               <input type="text" pInputText formControlName="discordId" | ||||
|                      placeholder="{{'common.discord_id' | translate}}"> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th hideable-th="name" [parent]="this"> | ||||
| @@ -116,14 +126,17 @@ | ||||
|           </th> | ||||
|           <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="left_server" [parent]="this" class="table-header-small-dropdown"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <p-dropdown formControlName="leftServer" [options]="leftServerOptions" placeholder="{{'common.left_server' | translate}}"></p-dropdown> | ||||
|               <p-dropdown formControlName="leftServer" [options]="leftServerOptions" | ||||
|                           placeholder="{{'common.left_server' | translate}}"></p-dropdown> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th hideable-th="level" [parent]="this" class="table-header-small-dropdown"> | ||||
|             <form [formGroup]="filterForm"> | ||||
|               <p-dropdown formControlName="level" [options]="levels" placeholder="{{'common.level' | translate}}"></p-dropdown> | ||||
|               <p-dropdown formControlName="level" [options]="levels" | ||||
|                           placeholder="{{'common.level' | translate}}"></p-dropdown> | ||||
|             </form> | ||||
|           </th> | ||||
|           <th></th> | ||||
| @@ -189,6 +202,17 @@ | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|           <td hideable-th="game_ontime" [parent]="this"> | ||||
|             <span class="p-column-title">{{'common.game_ontime' | translate}}:</span> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 {{member.gameOntime}} | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{member.gameOntime}} | ||||
|               </ng-template> | ||||
|             </p-cellEditor> | ||||
|           </td> | ||||
|           <td hideable-th="left_server" [parent]="this"> | ||||
|             <span class="p-column-title">{{'common.left_server' | translate}}:</span> | ||||
|             <p-cellEditor> | ||||
| @@ -204,7 +228,8 @@ | ||||
|             <span class="p-column-title">{{'common.level' | translate}}:</span> | ||||
|             <p-cellEditor> | ||||
|               <ng-template pTemplate="input"> | ||||
|                 <p-dropdown [options]="levels" [(ngModel)]="member.level" dataKey="id" placeholder="{{'common.level' | translate}}"></p-dropdown> | ||||
|                 <p-dropdown [options]="levels" [(ngModel)]="member.level" dataKey="id" | ||||
|                             placeholder="{{'common.level' | translate}}"></p-dropdown> | ||||
|               </ng-template> | ||||
|               <ng-template pTemplate="output"> | ||||
|                 {{member.level.name}} | ||||
| @@ -235,7 +260,8 @@ | ||||
|           </td> | ||||
|           <td> | ||||
|             <div class="btn-wrapper"> | ||||
|               <app-history-btn *ngIf="!isEditingNew" [id]="member.id" [query]="query" translationKey="view.server.members.header"></app-history-btn> | ||||
|               <app-history-btn *ngIf="!isEditingNew" [id]="member.id" [query]="query" | ||||
|                                translationKey="view.server.members.header"></app-history-btn> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" | ||||
|                       (click)="onRowEditInit(dt, member, ri)"></button> | ||||
|               <button *ngIf="!editing" pButton pInitEditableRow class="btn icon-btn" icon="pi pi-user" | ||||
|   | ||||
| @@ -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", "left_server", "level"]); | ||||
|     super("member", ["id", "discord_id", "name", "xp", "ontime", "game_ontime", "left_server", "level"]); | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|   | ||||
| @@ -63,11 +63,18 @@ | ||||
|  | ||||
|     <div class="content-row"> | ||||
|       <div class="content-column"> | ||||
|         <div class="content-data-name">{{'view.server.profile.ontime' | translate}}:</div> | ||||
|         <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> | ||||
| @@ -266,7 +273,7 @@ | ||||
|             <div class="content-data-name">{{'common.id' | translate}}:</div> | ||||
|             <div class="content-data-value">{{join.id}}</div> | ||||
|           </div> | ||||
|            | ||||
|  | ||||
|           <div class="content-column" style="flex: 0.75;"> | ||||
|             <div class="content-data-name" | ||||
|                  style="flex: 0.35;">{{'view.server.profile.joined_game_server.time' | translate}}: | ||||
|   | ||||
| @@ -154,6 +154,7 @@ | ||||
|       "uploaded": "Daten wurden erfolgreich importiert." | ||||
|     }, | ||||
|     "first_name": "Vorname", | ||||
|     "game_ontime": "Spiel Ontime", | ||||
|     "hidden_columns": "Ausgeblendete Spalten", | ||||
|     "history": { | ||||
|       "attribute": "Attribut", | ||||
| @@ -542,7 +543,6 @@ | ||||
|         "message_count": "Anzahl Nachrichten", | ||||
|         "minecraft_id": "Minecraft Id", | ||||
|         "name": "Name", | ||||
|         "ontime": "Ontime", | ||||
|         "permission_denied": "Zugriff verweigert!", | ||||
|         "permission_denied_d": "Du musst Moderator sein, um andere Profile sehen zu können!", | ||||
|         "reaction_count": "Anzahl Reaktionen", | ||||
|   | ||||
| @@ -154,6 +154,7 @@ | ||||
|       "uploaded": "Data was imported successfully." | ||||
|     }, | ||||
|     "first_name": "First name", | ||||
|     "game_ontime": "Game ontime", | ||||
|     "hidden_columns": "Hidden columns", | ||||
|     "history": { | ||||
|       "attribute": "Attribute", | ||||
| @@ -542,7 +543,6 @@ | ||||
|         "message_count": "Message count", | ||||
|         "minecraft_id": "Minecraft Id", | ||||
|         "name": "Name", | ||||
|         "ontime": "Ontime", | ||||
|         "permission_denied": "Access denied!", | ||||
|         "permission_denied_d": "You have to be moderator to see other profiles!", | ||||
|         "reaction_count": "Reaction count", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user