Added logic to edit technician config in WI #127

This commit is contained in:
Sven Heidemann 2023-08-14 11:58:36 +02:00
parent eac367c611
commit 8922524f44
7 changed files with 234 additions and 39 deletions

View File

@ -174,7 +174,7 @@ class DataIntegrityService:
self._logger.warn(__name__, f"User not found in database: {u.id}") self._logger.warn(__name__, f"User not found in database: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}") self._logger.debug(__name__, f"Add user: {u.id}")
self._users.add_user(User(u.id, 0, server)) self._users.add_user(User(u.id, 0, 0, 0, server))
self._db_context.save_changes() self._db_context.save_changes()
self._logger.debug(__name__, f"Added User: {u.id}") self._logger.debug(__name__, f"Added User: {u.id}")

View File

@ -74,6 +74,6 @@ class TechnicianPingUrlConfig(TableABC):
return str( return str(
f""" f"""
DELETE FROM `CFG_TechnicianPingUrls` DELETE FROM `CFG_TechnicianPingUrls`
WHERE `URL` = {self._ping_url}; WHERE `URL` = '{self._ping_url}';
""" """
) )

View File

@ -1,6 +1,8 @@
from cpl_core.database.context import DatabaseContextABC from cpl_core.database.context import DatabaseContextABC
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from bot_api.logging.api_logger import ApiLogger
from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
from bot_data.model.technician_config import TechnicianConfig from bot_data.model.technician_config import TechnicianConfig
@ -13,6 +15,7 @@ from bot_graphql.abc.query_abc import QueryABC
class TechnicianConfigMutation(QueryABC): class TechnicianConfigMutation(QueryABC):
def __init__( def __init__(
self, self,
logger: ApiLogger,
bot: DiscordBotServiceABC, bot: DiscordBotServiceABC,
servers: ServerRepositoryABC, servers: ServerRepositoryABC,
technician_configs: TechnicianConfigRepositoryABC, technician_configs: TechnicianConfigRepositoryABC,
@ -20,6 +23,7 @@ class TechnicianConfigMutation(QueryABC):
): ):
QueryABC.__init__(self, "TechnicianConfigMutation") QueryABC.__init__(self, "TechnicianConfigMutation")
self._logger = logger
self._bot = bot self._bot = bot
self._servers = servers self._servers = servers
self._technician_configs = technician_configs self._technician_configs = technician_configs
@ -45,9 +49,13 @@ class TechnicianConfigMutation(QueryABC):
technician_config.cache_max_messages = ( technician_config.cache_max_messages = (
input["cacheMaxMessages"] if "cacheMaxMessages" in input else technician_config.cache_max_messages input["cacheMaxMessages"] if "cacheMaxMessages" in input else technician_config.cache_max_messages
) )
technician_config.ping_urls = input["pingURLs"] if "pingURLs" in input else technician_config.ping_urls technician_config.ping_urls = (
List(str, input["pingURLs"]) if "pingURLs" in input else technician_config.ping_urls
)
technician_config.technician_ids = ( technician_config.technician_ids = (
input["technicianIds"] if "technicianIds" in input else technician_config.technician_ids List(int).extend([int(x) for x in input["technicianIds"]])
if "technicianIds" in input
else technician_config.technician_ids
) )
self._technician_configs.update_technician_config(technician_config) self._technician_configs.update_technician_config(technician_config)
@ -76,14 +84,19 @@ class TechnicianConfigMutation(QueryABC):
def _update_technician_ids(self, new_config: TechnicianConfig): def _update_technician_ids(self, new_config: TechnicianConfig):
old_config = self._technician_configs.get_technician_config() old_config = self._technician_configs.get_technician_config()
for url in old_config.technician_ids: for technician_id in old_config.technician_ids:
if url in new_config.technician_ids: if technician_id in new_config.technician_ids:
continue continue
self._technician_configs.delete_technician_id_config(TechnicianIdConfig(url)) self._technician_configs.delete_technician_id_config(TechnicianIdConfig(technician_id))
for url in new_config.technician_ids: for technician_id in new_config.technician_ids:
if url in old_config.technician_ids: user = self._bot.get_user(technician_id)
if user is None:
raise ValueError(f"Invalid technicianId")
for technician_id in new_config.technician_ids:
if technician_id in old_config.technician_ids:
continue continue
self._technician_configs.add_technician_id_config(TechnicianIdConfig(url)) self._technician_configs.add_technician_id_config(TechnicianIdConfig(technician_id))

View File

@ -160,6 +160,100 @@
</div> </div>
</div> </div>
<div class="content-divider"></div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">
{{'admin.settings.bot.ping_urls' | translate}}:
</div>
<div class="content-data-value-row">
<p-table #dt [value]="pingUrls" dataKey="id" editMode="row">
<ng-template pTemplate="caption">
<div class="table-caption">
<div class="table-caption-btn-wrapper btn-wrapper">
<button pButton class="icon-btn btn"
icon="pi pi-plus" (click)="pingUrlsAddNew(dt)">
</button>
</div>
</div>
</ng-template>
<ng-template pTemplate="body" let-pingUrl let-editing="editing" let-ri="rowIndex">
<tr [pEditableRow]="pingUrl">
<td>
<p-cellEditor>
<ng-template pTemplate="input">
<input class="table-edit-input" pInputText type="text" [(ngModel)]="pingUrl.value">
</ng-template>
<ng-template pTemplate="output">
{{pingUrl.value}}
</ng-template>
</p-cellEditor>
</td>
<td>
<div class="btn-wrapper">
<button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="pingUrlsEditInit(pingUrl, ri)"></button>
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="pingUrlsDelete(ri)"></button>
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="pingUrlsEditSave(pingUrl, ri)"></button>
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
(click)="pingUrlsEditCancel(pingUrl, ri)"></button>
</div>
</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
</div>
<div class="content-divider"></div>
<div class="content-row">
<div class="content-column">
<div class="content-data-name">
{{'admin.settings.bot.technicianIds' | translate}}:
</div>
<div class="content-data-value-row">
<p-table #dt [value]="technicianIds" dataKey="id" editMode="row">
<ng-template pTemplate="caption">
<div class="table-caption">
<div class="table-caption-btn-wrapper btn-wrapper">
<button pButton class="icon-btn btn"
icon="pi pi-plus" (click)="technicianIdsAddNew(dt)">
</button>
</div>
</div>
</ng-template>
<ng-template pTemplate="body" let-technicianId let-editing="editing" let-ri="rowIndex">
<tr [pEditableRow]="technicianId">
<td>
<p-cellEditor>
<ng-template pTemplate="input">
<input class="table-edit-input" pInputText type="text" [(ngModel)]="technicianId.value">
</ng-template>
<ng-template pTemplate="output">
{{technicianId.value}}
</ng-template>
</p-cellEditor>
</td>
<td>
<div class="btn-wrapper">
<button *ngIf="!editing" pButton type="button" pInitEditableRow class="btn icon-btn" icon="pi pi-pencil" (click)="technicianIdsEditInit(technicianId, ri)"></button>
<button *ngIf="!editing" pButton type="button" class="btn danger-icon-btn" icon="pi pi-trash" (click)="technicianIdsDelete(ri)"></button>
<button *ngIf="editing" pButton type="button" pSaveEditableRow class="btn icon-btn" icon="pi pi-check" (click)="technicianIdsEditSave(technicianId, ri)"></button>
<button *ngIf="editing" pButton type="button" pCancelEditableRow class="btn danger-icon-btn" icon="pi pi-times"
(click)="technicianIdsEditCancel(technicianId, ri)"></button>
</div>
</td>
</tr>
</ng-template>
</p-table>
</div>
</div>
</div>
<div class="content-divider"></div>
<div class="content-row"> <div class="content-row">
<button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn" <button pButton icon="pi pi-save" label="{{'common.save' | translate}}" class="btn login-form-submit-btn"
(click)="saveTechnicianConfig()" [disabled]="technicianConfigForm.invalid"></button> (click)="saveTechnicianConfig()" [disabled]="technicianConfigForm.invalid"></button>

View File

@ -14,12 +14,20 @@ import { TechnicianConfig } from "../../../../../models/config/technician-config
import { TechnicianConfigQuery } from "../../../../../models/graphql/query.model"; import { TechnicianConfigQuery } from "../../../../../models/graphql/query.model";
import { Queries } from "../../../../../models/graphql/queries.model"; import { Queries } from "../../../../../models/graphql/queries.model";
import { DataService } from "../../../../../services/data/data.service"; import { DataService } from "../../../../../services/data/data.service";
import { LevelMutationResult, TechnicianConfigMutationResult } from "../../../../../models/graphql/result.model"; import { TechnicianConfigMutationResult } from "../../../../../models/graphql/result.model";
import { Mutations } from "../../../../../models/graphql/mutations.model"; import { Mutations } from "../../../../../models/graphql/mutations.model";
import { AuthService } from "../../../../../services/auth/auth.service"; import { AuthService } from "../../../../../services/auth/auth.service";
import { ConfirmationDialogService } from "../../../../../services/confirmation-dialog/confirmation-dialog.service"; import { Table } from "primeng/table";
import { SidebarService } from "../../../../../services/sidebar/sidebar.service";
import { ActivatedRoute } from "@angular/router"; type PingUrl = {
id: number;
value: string;
};
type TechnicianId = {
id: number;
value: string;
};
@Component({ @Component({
selector: "app-settings", selector: "app-settings",
@ -33,9 +41,12 @@ export class SettingsComponent implements OnInit {
helpCommandReferenceUrl: [null, [Validators.required]], helpCommandReferenceUrl: [null, [Validators.required]],
waitForRestart: [null, [Validators.required]], waitForRestart: [null, [Validators.required]],
waitForShutdown: [null, [Validators.required]], waitForShutdown: [null, [Validators.required]],
cacheMaxMessages: [null, [Validators.required]], cacheMaxMessages: [null, [Validators.required]]
pingUrls: this.formBuilder.array([])
}); });
pingUrls: PingUrl[] = [];
clonedPingUrls: { [s: number]: PingUrl } = {};
technicianIds: TechnicianId[] = [];
clonedTechnicianIds: { [s: number]: TechnicianId } = {};
data: SettingsDTO = { data: SettingsDTO = {
webVersion: "", webVersion: "",
apiVersion: "", apiVersion: "",
@ -71,7 +82,7 @@ export class SettingsComponent implements OnInit {
private toastService: ToastService, private toastService: ToastService,
private translate: TranslateService, private translate: TranslateService,
private authService: AuthService, private authService: AuthService,
private spinner: SpinnerService, private spinner: SpinnerService
) { ) {
} }
@ -107,12 +118,18 @@ export class SettingsComponent implements OnInit {
helpCommandReferenceUrl: [this.config.helpCommandReferenceUrl, [Validators.required]], helpCommandReferenceUrl: [this.config.helpCommandReferenceUrl, [Validators.required]],
waitForRestart: [this.config.waitForRestart, [Validators.required]], waitForRestart: [this.config.waitForRestart, [Validators.required]],
waitForShutdown: [this.config.waitForShutdown, [Validators.required]], waitForShutdown: [this.config.waitForShutdown, [Validators.required]],
cacheMaxMessages: [this.config.cacheMaxMessages, [Validators.required]], cacheMaxMessages: [this.config.cacheMaxMessages, [Validators.required]]
pingUrls: this.formBuilder.array([])
}); });
const pingUrls = <FormArray>this.technicianConfigForm.controls["pingUrls"]; let id = 0;
for (const url of this.config.pingURLs ?? []) { for (const url of this.config.pingURLs ?? []) {
pingUrls.push(new FormControl(url, [Validators.required])); this.pingUrls.push({ id: id, value: url });
id++;
}
id = 0;
for (const technicianId of this.config.technicianIds ?? []) {
this.technicianIds.push({ id: id, value: technicianId });
id++;
} }
} }
@ -165,22 +182,93 @@ export class SettingsComponent implements OnInit {
saveTechnicianConfig() { saveTechnicianConfig() {
this.spinner.showSpinner(); this.spinner.showSpinner();
this.dataService.mutation<TechnicianConfigMutationResult>(Mutations.updateTechnicianConfig, { this.dataService.mutation<TechnicianConfigMutationResult>(Mutations.updateTechnicianConfig, {
helpCommandReferenceUrl: this.config.helpCommandReferenceUrl, helpCommandReferenceUrl: this.config.helpCommandReferenceUrl,
waitForRestart: this.config.waitForRestart, waitForRestart: this.config.waitForRestart,
waitForShutdown: this.config.waitForShutdown, waitForShutdown: this.config.waitForShutdown,
cacheMaxMessages: this.config.cacheMaxMessages, cacheMaxMessages: this.config.cacheMaxMessages,
pingURLs: this.config.pingURLs, pingURLs: this.pingUrls.filter(value => value.value).map(value => {
technicianIds: this.config.technicianIds, return value.value;
} }),
).pipe(catchError(err => { technicianIds: this.technicianIds.filter(value => value.value).map(value => {
this.spinner.hideSpinner(); return value.value;
this.toastService.error(this.translate.instant("admin.settings.message.technician_config_create_failed"), this.translate.instant("admin.settings.message.technician_config_create_failed_d")); })
return throwError(err); }
})).subscribe(result => { ).pipe(catchError(err => {
this.spinner.hideSpinner(); this.spinner.hideSpinner();
this.toastService.success(this.translate.instant("admin.settings.message.technician_config_create"), this.translate.instant("admin.settings.message.technician_config_create_d")); this.toastService.error(this.translate.instant("admin.settings.message.technician_config_create_failed"), this.translate.instant("admin.settings.message.technician_config_create_failed_d"));
}); return throwError(err);
})).subscribe(result => {
this.spinner.hideSpinner();
this.toastService.success(this.translate.instant("admin.settings.message.technician_config_create"), this.translate.instant("admin.settings.message.technician_config_create_d"));
});
}
pingUrlsAddNew(table: Table) {
const id = Math.max.apply(Math, this.pingUrls.map(url => {
return url.id ?? 0;
})) + 1;
const newItem = { id: id, value: "" };
this.pingUrls.push(newItem);
table.initRowEdit(newItem);
const index = this.pingUrls.findIndex(l => l.id == newItem.id);
this.pingUrlsEditInit(newItem, index);
}
pingUrlsEditInit(url: PingUrl, index: number) {
this.clonedPingUrls[index] = { ...url };
}
pingUrlsDelete(index: number) {
this.pingUrls.splice(index, 1);
}
pingUrlsEditSave(url: PingUrl, index: number) {
if (!url.value || this.pingUrls[index] == this.clonedPingUrls[index]) {
return;
}
delete this.clonedPingUrls[index];
}
pingUrlsEditCancel(url: PingUrl, index: number) {
this.pingUrls[index] = this.clonedPingUrls[index];
delete this.clonedPingUrls[index];
}
technicianIdsAddNew(table: Table) {
const id = Math.max.apply(Math, this.technicianIds.map(url => {
return url.id ?? 0;
})) + 1;
const newItem = { id: id, value: "" };
this.technicianIds.push(newItem);
table.initRowEdit(newItem);
const index = this.technicianIds.findIndex(l => l.id == newItem.id);
this.technicianIdsEditInit(newItem, index);
}
technicianIdsEditInit(url: PingUrl, index: number) {
this.clonedTechnicianIds[index] = { ...url };
}
technicianIdsDelete(index: number) {
this.technicianIds.splice(index, 1);
}
technicianIdsEditSave(url: PingUrl, index: number) {
if (!url.value || this.technicianIds[index] == this.clonedTechnicianIds[index]) {
return;
}
delete this.clonedTechnicianIds[index];
}
technicianIdsEditCancel(url: PingUrl, index: number) {
this.technicianIds[index] = this.clonedTechnicianIds[index];
delete this.clonedTechnicianIds[index];
} }
} }