Added user warnings to WI

This commit is contained in:
Sven Heidemann 2024-01-25 19:27:45 +01:00
parent f209e45905
commit 77f759a9ca
18 changed files with 670 additions and 14 deletions

View File

@ -18,6 +18,10 @@ class UserWarningsRepositoryABC(ABC):
def get_user_warnings_by_id(self, id: int) -> UserWarnings:
pass
@abstractmethod
def get_user_warnings_by_server_id(self, server_id: int) -> List[UserWarnings]:
pass
@abstractmethod
def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]:
pass

View File

@ -59,6 +59,17 @@ class UserWarnings(TableABC):
"""
)
@staticmethod
def get_select_by_server_id_string(id: int) -> str:
return str(
f"""
SELECT `UserWarnings`.* FROM `UserWarnings`
INNER JOIN `Users`
ON `Users`.`UserId` = `UserWarnings`.`UserId`
WHERE `Users`.`ServerId` = {id};
"""
)
@staticmethod
def get_select_by_user_id_string(id: int) -> str:
return str(

View File

@ -56,6 +56,20 @@ class UserWarningsRepositoryService(UserWarningsRepositoryABC):
self._logger.trace(__name__, f"Send SQL command: {UserWarnings.get_select_by_id_string(id)}")
return self._from_result(self._context.select(UserWarnings.get_select_by_id_string(id))[0])
def get_user_warnings_by_server_id(self, server_id: int) -> List[UserWarnings]:
self._logger.trace(
__name__,
f"Send SQL command: {UserWarnings.get_select_by_server_id_string(server_id)}",
)
return List(
UserWarnings,
[
self._from_result(warning)
for warning in self._context.select(UserWarnings.get_select_by_server_id_string(server_id))
],
)
def get_user_warnings_by_user_id(self, user_id: int) -> List[UserWarnings]:
self._logger.trace(
__name__,

View File

@ -29,6 +29,9 @@ type Server implements TableWithHistoryQuery {
activeUserCount: Int
users(filter: UserFilter, page: Page, sort: Sort): [User]
userWarningCount: Int
userWarnings(filter: UserWarningFilter, page: Page, sort: Sort): [UserWarning]
achievementCount: Int
achievements(filter: AchievementFilter, page: Page, sort: Sort): [Achievement]

View File

@ -86,5 +86,9 @@ class UserMutation(QueryABC):
continue
member = self._bot.get_guild(user.server.discord_id).get_member(user.discord_id)
author = self._users.get_user_by_id(int(warning["author"]))
if "author" not in warning:
author = Route.get_user().users.where(lambda u: u.server.id == user.server.id).single()
else:
author = self._users.get_user_by_id(int(warning["author"]))
self._user_warning_service.add_warnings(member, warning["description"], author.discord_id)

View File

@ -17,6 +17,7 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import (
UserJoinedVoiceChannelRepositoryABC,
)
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC
from bot_data.model.server import Server
from bot_data.model.server_config import ServerConfig
from bot_data.model.server_history import ServerHistory
@ -28,6 +29,7 @@ from bot_graphql.filter.level_filter import LevelFilter
from bot_graphql.filter.scheduled_event_filter import ScheduledEventFilter
from bot_graphql.filter.short_role_name_filter import ShortRoleNameFilter
from bot_graphql.filter.user_filter import UserFilter
from bot_graphql.filter.user_warning_filter import UserWarningFilter
from bot_graphql.model.server_statistics import ServerStatistics
@ -48,6 +50,7 @@ class ServerQuery(DataQueryWithHistoryABC):
short_role_names: ShortRoleNameRepositoryABC,
scheduled_events: ScheduledEventRepositoryABC,
server_configs: ServerConfigRepositoryABC,
user_warnings: UserWarningsRepositoryABC,
):
DataQueryWithHistoryABC.__init__(self, "Server", "ServersHistory", ServerHistory, db)
@ -89,6 +92,11 @@ class ServerQuery(DataQueryWithHistoryABC):
lambda server, *_: self._users.get_users_with_activity_by_server_id(server.id),
UserFilter,
)
self.add_collection(
"userWarning",
lambda server, *_: user_warnings.get_user_warnings_by_server_id(server.id),
UserWarningFilter,
)
self.add_collection(
"gameServer",
lambda server, *_: game_servers.get_game_servers_by_server_id(server.id),

View File

@ -377,6 +377,22 @@ export class Queries {
}
`;
static liteUsersQuery = `
query UsersList($serverId: ID, $filter: UserFilter, $page: Page, $sort: Sort) {
servers(filter: {id: $serverId}) {
userCount
users(filter: $filter, page: $page, sort: $sort) {
id
discordId
name
createdAt
modifiedAt
}
}
}
`;
static userProfile = `
query UserProfile($serverId: ID, $userId: ID, $page: Page, $sort: Sort) {
userCount
@ -503,6 +519,29 @@ export class Queries {
}
`;
static userWarningsQuery = `
query userWarnings($serverId: ID, $page: Page, $sort: Sort) {
servers(filter: {id: $serverId}) {
userWarningCount
userWarnings(page: $page, sort: $sort) {
id
user {
id
name
}
description
author {
id
name
}
createdAt
modifiedAt
}
}
}
`;
static autoRolesQuery = `
query AutoRoleQuery($serverId: ID, $filter: AutoRoleFilter, $page: Page, $sort: Sort) {
servers(filter: {id: $serverId}) {

View File

@ -64,7 +64,9 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe
level: FormControl<Level | null>
}>;
filter: UserFilter = {};
filter: UserFilter = {
leftServer: false
};
page: Page = {
pageSize: undefined,
pageIndex: undefined
@ -145,7 +147,7 @@ export class MembersComponent extends ComponentWithTable implements OnInit, OnDe
id: new FormControl<number | null>(null),
discordId: new FormControl<number | null>(null),
name: [""],
leftServer: new FormControl<boolean | null>(null),
leftServer: new FormControl<boolean | null>(false),
level: new FormControl<Level | null>(null)
});

View File

@ -8,19 +8,55 @@ import { MemberRoles } from "../../../models/auth/auth-user.dto";
const routes: Routes = [
{ path: "", component: ServerDashboardComponent },
{ path: "members", component: MembersComponent, canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
{
path: "members",
component: MembersComponent,
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{ path: "members/:memberId", component: ProfileComponent },
{
path: "user-warnings",
loadChildren: () => import("./user-warning/user-warning.module").then(m => m.UserWarningModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{
path: "auto-roles",
loadChildren: () => import("./auto-role/auto-role.module").then(m => m.AutoRoleModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{ path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
{ path: "short-role-names", loadChildren: () => import("./short-role-name/short-role-name.module").then(m => m.ShortRoleNameModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
{ path: "scheduled-events", loadChildren: () => import("./scheduled-events/scheduled-events.module").then(m => m.ScheduledEventsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
{ path: "config", loadChildren: () => import("./config/config.module").then(m => m.ConfigModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Admin } }
{
path: "levels",
loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{
path: "achievements",
loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{
path: "short-role-names",
loadChildren: () => import("./short-role-name/short-role-name.module").then(m => m.ShortRoleNameModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{
path: "scheduled-events",
loadChildren: () => import("./scheduled-events/scheduled-events.module").then(m => m.ScheduledEventsModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Moderator }
},
{
path: "config",
loadChildren: () => import("./config/config.module").then(m => m.ConfigModule),
canActivate: [AuthGuard],
data: { memberRole: MemberRoles.Admin }
}
];
@NgModule({

View File

@ -0,0 +1,213 @@
<h1>
{{'common.user_warnings' | translate}}
</h1>
<div class="content-wrapper">
<div class="content">
<p-table #dt [value]="userWarnings" [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)">
<ng-template pTemplate="caption">
<div class="table-caption">
<div class="table-caption-table-info">
<div class="table-caption-text">
<ng-container *ngIf="!loading">{{userWarnings.length}} {{'common.of' | translate}}
{{dt.totalRecords}}
</ng-container>
{{'common.user_warnings' | translate}}
</div>
<app-multi-select-columns [table]="name" [columns]="columns"
[(hiddenColumns)]="hiddenColumns"></app-multi-select-columns>
</div>
<div class="table-caption-btn-wrapper btn-wrapper">
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
icon="pi pi-plus" (click)="addUserWarning(dt)"
[disabled]="isEditingNew || !user?.isModerator && !user?.isAdmin">
</button>
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
class="icon-btn btn" (click)="resetFilters()">
</button>
<app-data-import-and-export name="userWarnings" [(data)]="userWarnings"
[callback]="callback" [validator]="validator"></app-data-import-and-export>
</div>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th hideable-th="id" [parent]="this" [sortable]="true">
<div class="table-header-label">
<div class="table-header-text">{{'common.id' | translate}}</div>
<p-sortIcon field="id" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th hideable-th="description" [parent]="this" [sortable]="true">
<div class="table-header-label">
<div class="table-header-text">{{'common.description' | translate}}</div>
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th hideable-th="user" [parent]="this" [sortable]="true">
<div class="table-header-label">
<div class="table-header-text">{{'common.member' | translate}}</div>
<p-sortIcon field="attribute" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th hideable-th="author" [parent]="this" [sortable]="true">
<div class="table-header-label">
<div class="table-header-text">{{'common.author' | translate}}</div>
<p-sortIcon field="operator" class="table-header-icon"></p-sortIcon>
</div>
</th>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.created_at' | translate}}</div>
</div>
</th>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.modified_at' | translate}}</div>
</div>
</th>
<th>
<div class="table-header-label">
<div class="table-header-text">{{'common.actions' | translate}}</div>
</div>
</th>
</tr>
<tr>
<th hideable-th="id" [parent]="this" class="table-header-small">
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="id"
placeholder="{{'common.id' | translate}}">
</form>
</th>
<th hideable-th="description" [parent]="this">
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="description"
placeholder="{{'common.description' | translate}}">
</form>
</th>
<th hideable-th="user" [parent]="this">
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="user"
placeholder="{{'common.member' | translate}}">
</form>
</th>
<th hideable-th="author" [parent]="this">
<form [formGroup]="filterForm">
<input type="text" pInputText formControlName="author"
placeholder="{{'common.author' | translate}}">
</form>
</th>
<th class="table-header-small-dropdown"></th>
<th class="table-header-small-dropdown"></th>
<th class="table-header-actions"></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-userWarning let-editing="editing" let-ri="rowIndex">
<tr [pEditableRow]="userWarning">
<td hideable-td="id" [parent]="this">
<span class="p-column-title">{{'common.id' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
{{userWarning.id}}
</ng-template>
<ng-template pTemplate="output">
{{userWarning.id}}
</ng-template>
</p-cellEditor>
</td>
<td hideable-td="description" [parent]="this">
<span class="p-column-title">{{'common.description' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
<input *ngIf="isEditingNew; else description" class="table-edit-input" pInputText type="text"
[(ngModel)]="userWarning.description">
<ng-template #description>{{userWarning.description}}</ng-template>
</ng-template>
<ng-template pTemplate="output">
{{userWarning.description}}
</ng-template>
</p-cellEditor>
</td>
<td hideable-td="user" [parent]="this">
<span class="p-column-title">{{'common.user' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
<p-dropdown *ngIf="isEditingNew; else userName" optionLabel="name" [options]="users"
[(ngModel)]="userWarning.user"
placeholder="{{'common.member' | translate}}"></p-dropdown>
<ng-template #userName>{{userWarning.user.name}}</ng-template>
</ng-template>
<ng-template pTemplate="output">
{{userWarning.user.name}}
</ng-template>
</p-cellEditor>
</td>
<td hideable-td="author" [parent]="this">
<span class="p-column-title">{{'common.author' | translate}}:</span>
<p-cellEditor>
<ng-template pTemplate="input">
{{'common.you' | translate}}
</ng-template>
<ng-template pTemplate="output">
{{userWarning.author.name}}
</ng-template>
</p-cellEditor>
</td>
<td>
<span class="p-column-title">{{'common.created_at' | translate}}:</span>
{{userWarning.createdAt | date:'dd.MM.yy HH:mm'}}
</td>
<td>
<span class="p-column-title">{{'common.modified_at' | translate}}:</span>
{{userWarning.modifiedAt | date:'dd.MM.yy HH:mm'}}
</td>
<td>
<div class="btn-wrapper">
<button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash"
(click)="deleteUserWarning(userWarning)"
[disabled]="!user || !user.isModerator && !user.isAdmin"></button>
<button *ngIf="editing" pButton pSaveEditableRow class="btn icon-btn"
icon="pi pi-check-circle" (click)="onRowEditSave(userWarning, ri)"
[disabled]="!user || !user.isModerator && !user.isAdmin"></button>
<button *ngIf="editing" pButton pCancelEditableRow class="btn icon-btn danger-icon-btn"
icon="pi pi-times-circle" (click)="onRowEditCancel(ri)"
[disabled]="!user || !user.isModerator && !user.isAdmin"></button>
</div>
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage">
<tr></tr>
<tr>
<td colspan="10">{{'common.no_entries_found' | translate}}</td>
</tr>
<tr></tr>
</ng-template>
<ng-template pTemplate="paginatorleft">
</ng-template>
</p-table>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserWarningComponent } from "./user-warning.component";
describe("AchievementComponent", () => {
let component: UserWarningComponent;
let fixture: ComponentFixture<UserWarningComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [UserWarningComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UserWarningComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,240 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder, FormControl, FormGroup } from "@angular/forms";
import { Page } from "../../../../../../models/graphql/filter/page.model";
import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model";
import { Subject, throwError } from "rxjs";
import { Server } from "../../../../../../models/data/server.model";
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
import { Queries } from "../../../../../../models/graphql/queries.model";
import { AuthService } from "../../../../../../services/auth/auth.service";
import { SpinnerService } from "../../../../../../services/spinner/spinner.service";
import { ToastService } from "../../../../../../services/toast/toast.service";
import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service";
import { TranslateService } from "@ngx-translate/core";
import { DataService } from "../../../../../../services/data/data.service";
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
import { ActivatedRoute } from "@angular/router";
import { Query, UserListQuery, UserWarningQuery } from "../../../../../../models/graphql/query.model";
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
import { LazyLoadEvent } from "primeng/api";
import { Table } from "primeng/table";
import { User } from "../../../../../../models/data/user.model";
import { UpdateUserMutationResult } from "../../../../../../models/graphql/result.model";
import { Mutations } from "../../../../../../models/graphql/mutations.model";
import { ComponentWithTable } from "../../../../../../base/component-with-table";
import { UserWarning, UserWarningFilter } from "../../../../../../models/data/user_warning.model";
@Component({
selector: "app-user-warning",
templateUrl: "./user-warning.component.html",
styleUrls: ["./user-warning.component.scss"]
})
export class UserWarningComponent extends ComponentWithTable implements OnInit, OnDestroy {
public userWarnings: UserWarning[] = [];
public users: User[] = [];
public loading = true;
public filterForm!: FormGroup<{
id: FormControl<number | null>,
description: FormControl<string | null>,
user: FormControl<string | null>,
author: FormControl<string | null>,
}>;
public filter: UserWarningFilter = {};
public page: Page = {
pageSize: undefined,
pageIndex: undefined
};
public sort: Sort = {
sortColumn: undefined,
sortDirection: undefined
};
public totalRecords: number = 0;
public clonedUserWarning: { [s: string]: UserWarning; } = {};
private unsubscriber = new Subject<void>();
private server: Server = {};
public user: UserDTO | null = null;
query: string = Queries.userWarningsQuery;
public constructor(
private authService: AuthService,
private spinner: SpinnerService,
private toastService: ToastService,
private confirmDialog: ConfirmationDialogService,
private fb: FormBuilder,
private translate: TranslateService,
private data: DataService,
private sidebar: SidebarService,
private route: ActivatedRoute) {
super("UserWarning", ["id", "name"],
(oldElement: UserWarning, newElement: UserWarning) => {
return oldElement.id === newElement.id;
});
}
public ngOnInit(): void {
this.loading = true;
this.setFilterForm();
this.data.getServerFromRoute(this.route).then(async server => {
this.server = server;
let authUser = await this.authService.getLoggedInUser();
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
});
}
public ngOnDestroy(): void {
this.unsubscriber.next();
this.unsubscriber.complete();
}
public loadNextPage(): void {
this.data.query<UserWarningQuery>(Queries.userWarningsQuery, {
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
},
(data: Query) => {
return data.servers[0];
}
).subscribe(data => {
this.totalRecords = data.userWarningCount;
this.userWarnings = data.userWarnings;
this.data.query<UserListQuery>(Queries.liteUsersQuery, {
serverId: this.server.id, filter: {
leftServer: false
}
},
(x: { servers: Server[] }) => {
return x.servers[0];
}
).subscribe(data => {
this.users = data.users;
this.spinner.hideSpinner();
this.loading = false;
});
});
}
public setFilterForm(): void {
this.filterForm = this.fb.group({
id: new FormControl<number | null>(null),
description: new FormControl<string | null>(null),
user: new FormControl<string | null>(null),
author: new FormControl<string | null>(null)
});
this.filterForm.valueChanges.pipe(
takeUntil(this.unsubscriber),
debounceTime(600)
).subscribe(changes => {
if (changes.id) {
this.filter.id = changes.id;
} else {
this.filter.id = undefined;
}
if (this.page.pageSize)
this.page.pageSize = 10;
if (this.page.pageIndex)
this.page.pageIndex = 0;
this.loadNextPage();
});
}
public newUserWarningTemplate: UserWarning = {
createdAt: "",
modifiedAt: ""
};
public nextPage(event: LazyLoadEvent): void {
this.page.pageSize = event.rows ?? 0;
if (event.first != null && event.rows != null)
this.page.pageIndex = event.first / event.rows;
this.sort.sortColumn = event.sortField ?? undefined;
this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC;
this.loadNextPage();
}
public resetFilters(): void {
this.filterForm.reset();
}
public onRowEditInit(table: Table, user: User, index: number): void {
this.clonedUserWarning[index] = { ...user };
}
public override onRowEditSave(newUserWarning: UserWarning, index: number): void {
if (this.isEditingNew && JSON.stringify(newUserWarning) === JSON.stringify(this.newUserWarningTemplate)) {
this.isEditingNew = false;
this.userWarnings.splice(index, 1);
return;
}
if (!newUserWarning.id && !this.isEditingNew) {
return;
}
this.updateUserByWarning(newUserWarning.user?.id ?? 0, this.userWarnings.filter(uw => uw.user?.id == newUserWarning.user?.id));
}
public onRowEditCancel(index: number): void {
if (this.isEditingNew) {
this.userWarnings.splice(index, 1);
delete this.clonedUserWarning[index];
this.isEditingNew = false;
return;
}
this.userWarnings[index] = this.clonedUserWarning[index];
delete this.clonedUserWarning[index];
}
public addUserWarning(table: Table): void {
const newUserWarning = JSON.parse(JSON.stringify(this.newUserWarningTemplate));
this.userWarnings = [newUserWarning, ...this.userWarnings];
table.initRowEdit(newUserWarning);
const index = this.userWarnings.findIndex(l => l.id == newUserWarning.id);
this.onRowEditInit(table, newUserWarning, index);
this.isEditingNew = true;
}
public deleteUserWarning(userWarning: UserWarning): void {
this.userWarnings.splice(this.userWarnings.findIndex(uw => uw.id == userWarning.id), 1);
this.updateUserByWarning(userWarning.user?.id ?? 0, this.userWarnings.filter(uw => uw.user?.id == userWarning.user?.id));
}
public updateUserByWarning(userId: number, userWarnings: UserWarning[]) {
this.spinner.showSpinner();
this.data.mutation<UpdateUserMutationResult>(Mutations.updateUser, {
id: userId,
userWarnings: userWarnings?.map(userWarning => {
return {
id: userWarning.id,
user: userWarning.user?.id ?? undefined,
description: userWarning.description,
author: userWarning.author?.id ?? undefined
};
})
}
).pipe(catchError(err => {
this.spinner.hideSpinner();
return throwError(err);
})).subscribe(_ => {
this.spinner.hideSpinner();
this.toastService.success(this.translate.instant("view.server.user_warning.message.user_warning_updated"), this.translate.instant("view.server.user_warning.message.user_warning_updated"));
this.loadNextPage();
});
}
}

View File

@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { UserWarningComponent } from "./components/user-warning/user-warning.component";
const routes: Routes = [
{ path: "", component: UserWarningComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserWarningRoutingModule {
}

View File

@ -0,0 +1,19 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { UserWarningRoutingModule } from "./user-warning-routing.module";
import { SharedModule } from "../../../shared/shared.module";
import { UserWarningComponent } from "./components/user-warning/user-warning.component";
@NgModule({
declarations: [
UserWarningComponent
],
imports: [
CommonModule,
UserWarningRoutingModule,
SharedModule
]
})
export class UserWarningModule {
}

View File

@ -27,6 +27,7 @@ export class SidebarService {
serverDashboard: MenuItem = {};
serverProfile: MenuItem = {};
serverMembers: MenuItem = {};
serverUserWarnings: MenuItem = {};
serverAutoRoles: MenuItem = {};
serverLevels: MenuItem = {};
serverAchievements: MenuItem = {};
@ -89,6 +90,12 @@ export class SidebarService {
visible: true,
routerLink: `server/${this.server?.id}/members`
};
this.serverUserWarnings = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.user_warnings") : "",
icon: "pi pi-exclamation-triangle",
visible: true,
routerLink: `server/${this.server?.id}/user-warnings`
};
this.serverAutoRoles = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.auto_roles") : "",
@ -137,7 +144,7 @@ export class SidebarService {
icon: "pi pi-server",
visible: false,
expanded: true,
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverScheduledEvents, this.serverShortRoleNames, this.serverConfig]
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverUserWarnings, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverScheduledEvents, this.serverShortRoleNames, this.serverConfig]
};
this.adminConfig = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
@ -194,6 +201,7 @@ export class SidebarService {
if (this.server) {
this.serverMenu.visible = true;
this.serverMembers.visible = isTechnicianAndFullAccessActive || user?.isModerator;
this.serverUserWarnings.visible = isTechnicianAndFullAccessActive || user?.isModerator;
this.serverAutoRoles.visible = isTechnicianAndFullAccessActive || this.hasFeature("AutoRoleModule") && user?.isModerator;
this.serverLevels.visible = isTechnicianAndFullAccessActive || this.hasFeature("LevelModule") && user?.isModerator;
this.serverAchievements.visible = isTechnicianAndFullAccessActive || this.hasFeature("AchievementsModule") && user?.isModerator;

View File

@ -190,6 +190,7 @@
"left_server": "Aktiv",
"level": "Level",
"location": "Ort",
"member": "Mitglied",
"message_id": "Nachricht Id",
"min_xp": "Min. XP",
"modified_at": "Bearbeitet am",
@ -218,7 +219,8 @@
"user_warnings": "Verwarnungen",
"users": "Benutzer",
"value": "Wert",
"xp": "XP"
"xp": "XP",
"you": "Du"
},
"dialog": {
"abort": "Abbrechen",
@ -348,7 +350,8 @@
"members": "Mitglieder",
"profile": "Dein Profil",
"scheduled_events": "Geplante Events",
"short_role_names": "Rollen Kürzel"
"short_role_names": "Rollen Kürzel",
"user_warnings": "Verwarnungen"
},
"server_empty": "Kein Server ausgewählt",
"settings": "Einstellungen",
@ -622,6 +625,11 @@
"short_role_names_update_failed_d": "Die Bearbeitung des Levels ist fehlgeschlagen!"
},
"short_role_names": "Rollen Kürzel"
},
"user_warning": {
"message": {
"user_warning_updated": "Verwarnungen wurde bearbeitet"
}
}
},
"user_settings": {

View File

@ -190,6 +190,7 @@
"left_server": "Active",
"level": "Level",
"location": "Location",
"member": "Member",
"message_id": "Message Id",
"min_xp": "Min. XP",
"modified_at": "Modified at",
@ -218,7 +219,8 @@
"user_warnings": "User warnings",
"users": "User",
"value": "Value",
"xp": "XP"
"xp": "XP",
"you": "You"
},
"dialog": {
"abort": "Abort",
@ -348,7 +350,8 @@
"members": "Members",
"profile": "Your profile",
"scheduled_events": "Scheduled events",
"short_role_names": "Short role names"
"short_role_names": "Short role names",
"user_warnings": "User warnings"
},
"server_empty": "No server selected",
"settings": "Settings",
@ -622,6 +625,11 @@
"short_role_names_update_failed_d": "Short role name editing failed!"
},
"short_role_names": "Level"
},
"user_warning": {
"message": {
"user_warning_updated": "Updated user warnings"
}
}
},
"user_settings": {