@for (player of players(); track player.id; let index = $index) {
0"
>
- @if (player.alias) {
- {{ player.alias }}
- } @else {
- <{{ translations.events_timeslot_unknownPlayer() }}>
-
({{ player.id }})
- }
+
+ @if (player.alias) {
+ {{ player.alias }}
+ } @else {
+ <{{ translations.events_timeslot_unknownPlayer() }}>
+ ({{ player.id }})
+ }
+
+
}
@if (timeslot.playerIds.length === 0) {
diff --git a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
index e98ac9d..a26e1e4 100644
--- a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
+++ b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
@@ -6,11 +6,13 @@ import { Router, ActivatedRoute } from '@angular/router';
import { Actions, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { AccordionModule } from 'primeng/accordion';
-import { ConfirmationService } from 'primeng/api';
+import { ConfirmationService, MessageService } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { CardModule } from 'primeng/card';
import { DropdownModule } from 'primeng/dropdown';
+import { ListboxModule } from 'primeng/listbox';
import { MessagesModule } from 'primeng/messages';
+import { OverlayPanelModule } from 'primeng/overlaypanel';
import { ProgressSpinnerModule } from 'primeng/progressspinner';
import { TooltipModule } from 'primeng/tooltip';
import { map } from 'rxjs';
@@ -35,17 +37,27 @@ import {
selectUsersActionState,
userSelectors,
} from '../../../+state/users';
-import { EventInstancePreconfiguration, User } from '../../../models/parsed-models';
+import { EventsService } from '../../../api/services';
+import {
+ EventInstance,
+ EventInstancePreconfiguration,
+ EventTimeslot,
+ User,
+} from '../../../models/parsed-models';
import { TranslateService } from '../../../services/translate.service';
-import { ifTruthy, isNullish } from '../../../utils/common.utils';
+import { ifTruthy, isNullish, notNullish } from '../../../utils/common.utils';
import { dateWithTime, timeToString } from '../../../utils/date.utils';
import { errorToastEffect, selectSignal } from '../../../utils/ngrx.utils';
+import { UserItemComponent } from '../../users/user-item/user-item.component';
import { EventTimeslotDialogComponent } from '../event-timeslot-dialog/event-timeslot-dialog.component';
function asString(value: unknown): string | null {
return typeof value === 'string' ? value : null;
}
+type EventInstances = { timeslot: EventTimeslot; instances: EventInstance[] }[];
+type EventPlayer = Partial
& { id: string };
+
@Component({
selector: 'app-event-timeslot',
standalone: true,
@@ -57,9 +69,12 @@ function asString(value: unknown): string | null {
DropdownModule,
EventTimeslotDialogComponent,
FormsModule,
+ ListboxModule,
MessagesModule,
+ OverlayPanelModule,
ProgressSpinnerModule,
TooltipModule,
+ UserItemComponent,
],
templateUrl: './event-timeslot.component.html',
styleUrl: './event-timeslot.component.scss',
@@ -71,6 +86,8 @@ export class EventTimeslotComponent {
private readonly _activatedRoute = inject(ActivatedRoute);
private readonly _translateService = inject(TranslateService);
private readonly _confirmationService = inject(ConfirmationService);
+ private readonly _eventService = inject(EventsService);
+ private readonly _messageService = inject(MessageService);
protected readonly translations = this._translateService.translations;
protected readonly locale = this._translateService.language;
@@ -110,11 +127,16 @@ export class EventTimeslotComponent {
this.timeslot(),
timeslot =>
timeslot.playerIds
- .map & { id: string }>(x => this.allUsers()[x] ?? { id: x })
+ .map(x => this.allUsers()[x] ?? { id: x })
.sort((a, b) => (a?.alias ?? '').localeCompare(b?.alias ?? '')),
[]
)
);
+ protected readonly availablePlayers = computed(() =>
+ Object.values(this.allUsers())
+ .filter(notNullish)
+ .filter(u => !this.players().some(p => p.id === u.id))
+ );
protected readonly preconfigPlayerOptions = computed(() =>
this.players().filter(
x => !this.timeslot()?.preconfigurations.some(p => p.playerIds.includes(x.id))
@@ -168,6 +190,61 @@ export class EventTimeslotComponent {
}
}
+ protected async addPlayer(player: User) {
+ const eventId = this.eventId();
+ const timeslotId = this.timeslotId();
+
+ if (isNullish(eventId) || isNullish(timeslotId)) return;
+
+ const response = await this._eventService.patchPlayerEventRegistrations({
+ eventId,
+ body: { userId: player.id, timeslotId: timeslotId, isRegistered: true },
+ });
+ if (response.ok) {
+ this._messageService.add({
+ severity: 'success',
+ summary: this.translations.events_timeslot_playerAdded(),
+ life: 2000,
+ });
+ }
+ }
+
+ protected async removeUser(user: EventPlayer) {
+ const eventId = this.eventId();
+ const timeslotId = this.timeslotId();
+
+ if (isNullish(eventId) || isNullish(timeslotId)) return;
+
+ this._confirmationService.confirm({
+ header: this.translations.events_timeslot_playerRemoveDialog_header(user),
+ message: this.translations.events_timeslot_playerRemoveDialog_message(),
+ acceptLabel: this.translations.shared_delete(),
+ acceptButtonStyleClass: 'p-button-danger',
+ acceptIcon: 'p-button-icon-left i-[mdi--delete]',
+ rejectLabel: this.translations.shared_cancel(),
+ rejectButtonStyleClass: 'p-button-text',
+ accept: async () => {
+ const response = await this._eventService.patchPlayerEventRegistrations({
+ eventId,
+ body: { userId: user.id, timeslotId: timeslotId, isRegistered: false },
+ });
+ if (response.ok) {
+ this._messageService.add({
+ severity: 'success',
+ summary: this.translations.events_timeslot_playerRemoveDialog_playerRemoved(),
+ life: 2000,
+ });
+ } else {
+ this._messageService.add({
+ severity: 'error',
+ summary: this.translations.events_timeslot_playerRemoveDialog_error_playerRemoved(),
+ life: 2000,
+ });
+ }
+ },
+ });
+ }
+
protected addPreconfig() {
const eventId = this.eventId();
const timeslotId = this.timeslotId();
diff --git a/src/client/src/app/i18n/de.json b/src/client/src/app/i18n/de.json
index 1722956..571c308 100644
--- a/src/client/src/app/i18n/de.json
+++ b/src/client/src/app/i18n/de.json
@@ -101,7 +101,19 @@
"time": "Startzeit",
"mapToPlay": "Zu spielende Bahn",
"map": "Bahn",
- "isFallbackAllowed": "Spieler können einen Ausweichzeitslot festlegen"
+ "isFallbackAllowed": "Spieler können einen Ausweichzeitslot festlegen",
+ "playerAdded": "Spieler wurde diesem Zeitslot hinzugefügt",
+ "playerRemoveDialog": {
+ "header": "Spieler \"{{alias}}\" entfernen?",
+ "message": "Möchtest du den Spieler wirklich aus dem Zeitslot entfernen?",
+ "playerRemoved": "Spieler wurde aus diesem Zeitslot entfernt",
+ "error": {
+ "playerRemoved": "Spieler wurde aus diesem Zeitslot nicht entfernt"
+ }
+ },
+ "error": {
+ "playerAdded": "Spieler wurde diesem Zeitslot nicht hinzugefügt"
+ }
},
"createDialog": {
"title": "Veranstaltung erstellen",
diff --git a/src/client/src/app/i18n/en.json b/src/client/src/app/i18n/en.json
index ca65307..b6d4c47 100644
--- a/src/client/src/app/i18n/en.json
+++ b/src/client/src/app/i18n/en.json
@@ -101,7 +101,19 @@
"time": "Start time",
"mapToPlay": "Map to be played",
"map": "Map",
- "isFallbackAllowed": "Players can define a fallback timeslot"
+ "isFallbackAllowed": "Players can define a fallback timeslot",
+ "playerAdded": "Player has been added to this timeslot",
+ "playerRemoveDialog": {
+ "header": "Remove Player \"{{alias}}\"",
+ "message": "Do you really want to remove the player from this timeslot?",
+ "playerRemoved": "Player has been removed from this timeslot",
+ "error": {
+ "playerRemoved": "Player has not been removed from this timeslot"
+ }
+ },
+ "error": {
+ "playerAdded": "Player has not been added to this timeslot"
+ }
},
"createDialog": {
"title": "Create event",
diff --git a/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
new file mode 100644
index 0000000..782a3ef
--- /dev/null
+++ b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
@@ -0,0 +1,190 @@
+using System.ComponentModel.DataAnnotations;
+using FastEndpoints;
+using FluentValidation;
+using MaSch.Core.Extensions;
+using Microsoft.AspNetCore.Server.HttpSys;
+using Microsoft.EntityFrameworkCore;
+using MinigolfFriday.Data;
+using MinigolfFriday.Data.Entities;
+using MinigolfFriday.Domain.Models;
+using MinigolfFriday.Domain.Models.RealtimeEvents;
+using MinigolfFriday.Host.Common;
+using MinigolfFriday.Host.Services;
+
+namespace MinigolfFriday.Host.Endpoints.Events;
+
+/// The id of the event to change registration.
+/// The registration to change.
+/// The registration state to change the timeslot to.
+/// The userId to patch. Only available as Admin.
+public record PatchPlayerEventRegistrationsRequest(
+ [property: Required] string EventId,
+ [property: Required] string TimeslotId,
+ [property: Required] bool IsRegistered,
+ [property: Required] string UserId
+);
+
+public class PatchPlayerEventRegistrationsRequestValidator
+ : Validator
+{
+ public PatchPlayerEventRegistrationsRequestValidator(IIdService idService)
+ {
+ RuleFor(x => x.EventId).NotEmpty().ValidSqid(idService.Event);
+ RuleFor(x => x.TimeslotId).NotEmpty().ValidSqid(idService.EventTimeslot);
+ }
+}
+
+public class PatchPlayerEventRegistrationsEndpoint(
+ DatabaseContext databaseContext,
+ IRealtimeEventsService realtimeEventsService,
+ IIdService idService,
+ IJwtService jwtService
+) : Endpoint
+{
+ public override void Configure()
+ {
+ Patch("{eventId}/registrations");
+ Group();
+ this.ProducesErrors(
+ EndpointErrors.UserIdNotInClaims,
+ EndpointErrors.EventNotFound,
+ EndpointErrors.EventRegistrationElapsed,
+ EndpointErrors.EventAlreadyStarted,
+ EndpointErrors.UserNotFound
+ );
+ }
+
+ public override async Task HandleAsync(
+ PatchPlayerEventRegistrationsRequest req,
+ CancellationToken ct
+ )
+ {
+ if (!jwtService.TryGetUserId(User, out var userId))
+ {
+ Logger.LogWarning(EndpointErrors.UserIdNotInClaims);
+ await this.SendErrorAsync(EndpointErrors.UserIdNotInClaims, ct);
+ return;
+ }
+ if (!jwtService.HasRole(User, Role.Admin))
+ {
+ return;
+ }
+ userId = idService.User.DecodeSingle(req.UserId);
+
+ var user = await databaseContext.Users.FirstOrDefaultAsync(x => x.Id == userId, ct);
+ if (user == null)
+ {
+ Logger.LogWarning(EndpointErrors.UserNotFound, userId);
+ await this.SendErrorAsync(
+ EndpointErrors.UserNotFound,
+ idService.User.Encode(userId),
+ ct
+ );
+ return;
+ }
+
+ var eventId = idService.Event.DecodeSingle(req.EventId);
+ var eventInfo = await databaseContext
+ .Events.Where(x => x.Id == eventId)
+ .Select(x => new { Started = x.StartedAt != null, x.RegistrationDeadline })
+ .FirstOrDefaultAsync(ct);
+
+ if (eventInfo == null)
+ {
+ Logger.LogWarning(EndpointErrors.EventNotFound, eventId);
+ await this.SendErrorAsync(EndpointErrors.EventNotFound, req.EventId, ct);
+ return;
+ }
+
+ if (eventInfo.RegistrationDeadline < DateTimeOffset.Now)
+ {
+ Logger.LogWarning(
+ EndpointErrors.EventRegistrationElapsed,
+ eventId,
+ eventInfo.RegistrationDeadline
+ );
+ await this.SendErrorAsync(
+ EndpointErrors.EventRegistrationElapsed,
+ req.EventId,
+ eventInfo.RegistrationDeadline,
+ ct
+ );
+ return;
+ }
+
+ if (eventInfo.Started)
+ {
+ Logger.LogWarning(EndpointErrors.EventAlreadyStarted, eventId);
+ await this.SendErrorAsync(EndpointErrors.EventAlreadyStarted, req.EventId, ct);
+ return;
+ }
+
+ var registrations = await databaseContext
+ .EventTimeslotRegistrations.Where(x =>
+ x.Player.Id == userId && x.EventTimeslot.EventId == eventId
+ )
+ .ToArrayAsync(ct);
+ var targetRegistration = new
+ {
+ TimeslotId = idService.EventTimeslot.DecodeSingle(req.TimeslotId)
+ };
+ var timeslotToModify = registrations.FirstOrDefault(x =>
+ x.EventTimeslotId == targetRegistration.TimeslotId
+ );
+ if (timeslotToModify == null && req.IsRegistered)
+ {
+ // not existent but wants to -> then add
+ databaseContext.EventTimeslotRegistrations.Add(
+ new EventTimeslotRegistrationEntity
+ {
+ EventTimeslot = databaseContext.EventTimeslotById(
+ targetRegistration.TimeslotId
+ ),
+ Player = databaseContext.UserById(userId),
+ FallbackEventTimeslot = null
+ }
+ );
+ }
+ else if (timeslotToModify != null && !req.IsRegistered)
+ {
+ // is existent but does not want to -> remove
+ databaseContext.EventTimeslotRegistrations.RemoveRange(
+ registrations.Where(x => targetRegistration.TimeslotId == x.EventTimeslotId)
+ );
+ }
+ await databaseContext.SaveChangesAsync(ct);
+ await SendAsync(null, cancellation: ct);
+
+ await realtimeEventsService.SendEventAsync(
+ new RealtimeEvent.PlayerEventRegistrationChanged(
+ idService.User.Encode(userId),
+ idService.Event.Encode(eventId)
+ ),
+ ct
+ );
+ var userAlias = await databaseContext
+ .Users.Where(x => x.Id == userId)
+ .Select(x => x.Alias)
+ .FirstOrDefaultAsync(ct);
+ var changeEvents = registrations
+ .Where(x => targetRegistration.TimeslotId == x.EventTimeslotId)
+ .Select(x => new RealtimeEvent.PlayerEventTimeslotRegistrationChanged(
+ idService.Event.Encode(eventId),
+ idService.EventTimeslot.Encode(x.EventTimeslotId),
+ idService.User.Encode(userId),
+ userAlias,
+ req.IsRegistered
+ ))
+ .Concat(
+ new RealtimeEvent.PlayerEventTimeslotRegistrationChanged(
+ idService.Event.Encode(eventId),
+ idService.EventTimeslot.Encode(targetRegistration.TimeslotId),
+ idService.User.Encode(userId),
+ userAlias,
+ req.IsRegistered
+ )
+ );
+ foreach (var changeEvent in changeEvents)
+ await realtimeEventsService.SendEventAsync(changeEvent, ct);
+ }
+}
From d316c9a6e7b751c70916a0605a661d01845ea9a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Schmidt?=
<9435005+AnSch1510@users.noreply.github.com>
Date: Sun, 28 Jul 2024 21:04:21 +0200
Subject: [PATCH 2/5] refactor sendNotificationEndpoint
---
.../Endpoints/Notifications/SendNotificationEndpoint.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/server/host/Endpoints/Notifications/SendNotificationEndpoint.cs b/src/server/host/Endpoints/Notifications/SendNotificationEndpoint.cs
index 625195c..a951bf1 100644
--- a/src/server/host/Endpoints/Notifications/SendNotificationEndpoint.cs
+++ b/src/server/host/Endpoints/Notifications/SendNotificationEndpoint.cs
@@ -48,14 +48,12 @@ public override async Task HandleAsync(SendNotificationRequest req, Cancellation
await this.SendErrorAsync(EndpointErrors.UserIdNotInClaims, ct);
return;
}
- if (!req.UserId.IsNullOrEmpty() && jwtService.HasRole(User, Role.Admin))
+ if (req.UserId != null && jwtService.HasRole(User, Role.Admin))
{
userId = idService.User.DecodeSingle(req.UserId);
}
- var user = await databaseContext
- .Users.Include(x => x.Settings)
- .FirstOrDefaultAsync(x => x.Id == userId, ct);
+ var user = await databaseContext.Users.FirstOrDefaultAsync(x => x.Id == userId, ct);
if (user == null)
{
From 98b674a6a6be8d1c70610da888bc40a581971d7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Schmidt?=
<9435005+AnSch1510@users.noreply.github.com>
Date: Sun, 28 Jul 2024 21:16:49 +0200
Subject: [PATCH 3/5] fix add not working issue
---
.../events/event-timeslot/event-timeslot.component.ts | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
index a26e1e4..c82af66 100644
--- a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
+++ b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
@@ -190,7 +190,7 @@ export class EventTimeslotComponent {
}
}
- protected async addPlayer(player: User) {
+ protected async addPlayer(userId: string) {
const eventId = this.eventId();
const timeslotId = this.timeslotId();
@@ -198,7 +198,7 @@ export class EventTimeslotComponent {
const response = await this._eventService.patchPlayerEventRegistrations({
eventId,
- body: { userId: player.id, timeslotId: timeslotId, isRegistered: true },
+ body: { userId: userId, timeslotId: timeslotId, isRegistered: true },
});
if (response.ok) {
this._messageService.add({
@@ -206,6 +206,12 @@ export class EventTimeslotComponent {
summary: this.translations.events_timeslot_playerAdded(),
life: 2000,
});
+ } else {
+ this._messageService.add({
+ severity: 'error',
+ summary: this.translations.events_timeslot_error_playerAdded(),
+ life: 2000,
+ });
}
}
From 84d57803363e1c70263960cd5ab7a327cc586af5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Schmidt?=
<9435005+AnSch1510@users.noreply.github.com>
Date: Wed, 31 Jul 2024 20:38:36 +0200
Subject: [PATCH 4/5] apply suggestions
---
.../event-timeslot.component.ts | 9 +---
src/client/src/app/i18n/de.json | 4 +-
src/client/src/app/i18n/en.json | 4 +-
.../Events/EventsAdministrationGroup.cs | 19 +++++++++
.../PatchPlayerEventRegistrationsEndpoint.cs | 41 ++++---------------
5 files changed, 33 insertions(+), 44 deletions(-)
create mode 100644 src/server/host/Endpoints/Events/EventsAdministrationGroup.cs
diff --git a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
index c82af66..0f1f3f1 100644
--- a/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
+++ b/src/client/src/app/components/events/event-timeslot/event-timeslot.component.ts
@@ -38,12 +38,7 @@ import {
userSelectors,
} from '../../../+state/users';
import { EventsService } from '../../../api/services';
-import {
- EventInstance,
- EventInstancePreconfiguration,
- EventTimeslot,
- User,
-} from '../../../models/parsed-models';
+import { EventInstancePreconfiguration, User } from '../../../models/parsed-models';
import { TranslateService } from '../../../services/translate.service';
import { ifTruthy, isNullish, notNullish } from '../../../utils/common.utils';
import { dateWithTime, timeToString } from '../../../utils/date.utils';
@@ -54,8 +49,6 @@ import { EventTimeslotDialogComponent } from '../event-timeslot-dialog/event-tim
function asString(value: unknown): string | null {
return typeof value === 'string' ? value : null;
}
-
-type EventInstances = { timeslot: EventTimeslot; instances: EventInstance[] }[];
type EventPlayer = Partial & { id: string };
@Component({
diff --git a/src/client/src/app/i18n/de.json b/src/client/src/app/i18n/de.json
index 571c308..c674efb 100644
--- a/src/client/src/app/i18n/de.json
+++ b/src/client/src/app/i18n/de.json
@@ -108,11 +108,11 @@
"message": "Möchtest du den Spieler wirklich aus dem Zeitslot entfernen?",
"playerRemoved": "Spieler wurde aus diesem Zeitslot entfernt",
"error": {
- "playerRemoved": "Spieler wurde aus diesem Zeitslot nicht entfernt"
+ "playerRemoved": "Fehler beim entfernen aufgetreten."
}
},
"error": {
- "playerAdded": "Spieler wurde diesem Zeitslot nicht hinzugefügt"
+ "playerAdded": "Fehler beim hinzufpgen aufgetreten."
}
},
"createDialog": {
diff --git a/src/client/src/app/i18n/en.json b/src/client/src/app/i18n/en.json
index b6d4c47..43f4488 100644
--- a/src/client/src/app/i18n/en.json
+++ b/src/client/src/app/i18n/en.json
@@ -108,11 +108,11 @@
"message": "Do you really want to remove the player from this timeslot?",
"playerRemoved": "Player has been removed from this timeslot",
"error": {
- "playerRemoved": "Player has not been removed from this timeslot"
+ "playerRemoved": "Error while removing Ppayer from timeslot"
}
},
"error": {
- "playerAdded": "Player has not been added to this timeslot"
+ "playerAdded": "Error while adding player to timeslot"
}
},
"createDialog": {
diff --git a/src/server/host/Endpoints/Events/EventsAdministrationGroup.cs b/src/server/host/Endpoints/Events/EventsAdministrationGroup.cs
new file mode 100644
index 0000000..270f922
--- /dev/null
+++ b/src/server/host/Endpoints/Events/EventsAdministrationGroup.cs
@@ -0,0 +1,19 @@
+using FastEndpoints;
+using MinigolfFriday.Domain.Models;
+
+namespace MinigolfFriday.Host.Endpoints.Events;
+
+public class EventsAdministrationGroup : Group
+{
+ public EventsAdministrationGroup()
+ {
+ Configure(
+ "events",
+ x =>
+ {
+ x.Roles(nameof(Role.Admin));
+ x.Description(x => x.WithTags("Events"));
+ }
+ );
+ }
+}
diff --git a/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
index 782a3ef..df6a50d 100644
--- a/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
+++ b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
@@ -2,11 +2,9 @@
using FastEndpoints;
using FluentValidation;
using MaSch.Core.Extensions;
-using Microsoft.AspNetCore.Server.HttpSys;
using Microsoft.EntityFrameworkCore;
using MinigolfFriday.Data;
using MinigolfFriday.Data.Entities;
-using MinigolfFriday.Domain.Models;
using MinigolfFriday.Domain.Models.RealtimeEvents;
using MinigolfFriday.Host.Common;
using MinigolfFriday.Host.Services;
@@ -37,14 +35,13 @@ public PatchPlayerEventRegistrationsRequestValidator(IIdService idService)
public class PatchPlayerEventRegistrationsEndpoint(
DatabaseContext databaseContext,
IRealtimeEventsService realtimeEventsService,
- IIdService idService,
- IJwtService jwtService
+ IIdService idService
) : Endpoint
{
public override void Configure()
{
Patch("{eventId}/registrations");
- Group();
+ Group();
this.ProducesErrors(
EndpointErrors.UserIdNotInClaims,
EndpointErrors.EventNotFound,
@@ -59,17 +56,7 @@ public override async Task HandleAsync(
CancellationToken ct
)
{
- if (!jwtService.TryGetUserId(User, out var userId))
- {
- Logger.LogWarning(EndpointErrors.UserIdNotInClaims);
- await this.SendErrorAsync(EndpointErrors.UserIdNotInClaims, ct);
- return;
- }
- if (!jwtService.HasRole(User, Role.Admin))
- {
- return;
- }
- userId = idService.User.DecodeSingle(req.UserId);
+ var userId = idService.User.DecodeSingle(req.UserId);
var user = await databaseContext.Users.FirstOrDefaultAsync(x => x.Id == userId, ct);
if (user == null)
@@ -166,25 +153,15 @@ await realtimeEventsService.SendEventAsync(
.Users.Where(x => x.Id == userId)
.Select(x => x.Alias)
.FirstOrDefaultAsync(ct);
- var changeEvents = registrations
- .Where(x => targetRegistration.TimeslotId == x.EventTimeslotId)
- .Select(x => new RealtimeEvent.PlayerEventTimeslotRegistrationChanged(
+ await realtimeEventsService.SendEventAsync(
+ new RealtimeEvent.PlayerEventTimeslotRegistrationChanged(
idService.Event.Encode(eventId),
- idService.EventTimeslot.Encode(x.EventTimeslotId),
+ idService.EventTimeslot.Encode(targetRegistration.TimeslotId),
idService.User.Encode(userId),
userAlias,
req.IsRegistered
- ))
- .Concat(
- new RealtimeEvent.PlayerEventTimeslotRegistrationChanged(
- idService.Event.Encode(eventId),
- idService.EventTimeslot.Encode(targetRegistration.TimeslotId),
- idService.User.Encode(userId),
- userAlias,
- req.IsRegistered
- )
- );
- foreach (var changeEvent in changeEvents)
- await realtimeEventsService.SendEventAsync(changeEvent, ct);
+ ),
+ ct
+ );
}
}
From 23facfdbd68547a19954a83c03a21bb44941eb7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Schmidt?=
<9435005+AnSch1510@users.noreply.github.com>
Date: Wed, 31 Jul 2024 20:39:04 +0200
Subject: [PATCH 5/5] be able to add/remove player to/from a timeslot even if
the event has already started
---
.../PatchPlayerEventRegistrationsEndpoint.cs | 23 -------------------
1 file changed, 23 deletions(-)
diff --git a/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
index df6a50d..b2a0d71 100644
--- a/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
+++ b/src/server/host/Endpoints/Events/PatchPlayerEventRegistrationsEndpoint.cs
@@ -83,29 +83,6 @@ await this.SendErrorAsync(
return;
}
- if (eventInfo.RegistrationDeadline < DateTimeOffset.Now)
- {
- Logger.LogWarning(
- EndpointErrors.EventRegistrationElapsed,
- eventId,
- eventInfo.RegistrationDeadline
- );
- await this.SendErrorAsync(
- EndpointErrors.EventRegistrationElapsed,
- req.EventId,
- eventInfo.RegistrationDeadline,
- ct
- );
- return;
- }
-
- if (eventInfo.Started)
- {
- Logger.LogWarning(EndpointErrors.EventAlreadyStarted, eventId);
- await this.SendErrorAsync(EndpointErrors.EventAlreadyStarted, req.EventId, ct);
- return;
- }
-
var registrations = await databaseContext
.EventTimeslotRegistrations.Where(x =>
x.Player.Id == userId && x.EventTimeslot.EventId == eventId