Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: more detailed notification when an event starts #93

Merged
merged 1 commit into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 77 additions & 12 deletions src/server/domain/Models/Push/PushNotificationData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Globalization;
using System.Text;
using System.Text.Json.Serialization;

namespace MinigolfFriday.Domain.Models.Push;

Expand All @@ -11,6 +13,13 @@ public interface IPushNotificationData
string GetBody(string lang);
}

public record NotificationTimeslotInfo(
TimeOnly Time,
string GroupCode,
string MapName,
int PlayerCount
);

public static class PushNotificationData
{
private static readonly CultureInfo DeCulture = CultureInfo.GetCultureInfo("de");
Expand Down Expand Up @@ -42,7 +51,10 @@ public string GetBody(string lang) =>
};
}

public record EventStarted(string EventId) : IPushNotificationData
public record EventStarted(
string EventId,
[property: JsonIgnore] NotificationTimeslotInfo[] Timeslots
) : IPushNotificationData
{
public string Type => "event-started";

Expand All @@ -56,15 +68,43 @@ public string GetTitle(string lang) =>
_ => "The rooms have been assigned!",
};

public string GetBody(string lang) =>
NormalizeLang(lang) switch
public string GetBody(string lang)
{
lang = NormalizeLang(lang);
var builder = new StringBuilder();
foreach (var timeslot in Timeslots)
{
"de" => "Schaue nach in welchen Räumen du spielst.",
_ => "Check which rooms you are playing in.",
};
builder.Append(
lang switch
{
"de"
=> string.Create(
DeCulture,
$"um {timeslot.Time:t} Uhr spielst du in \"{timeslot.GroupCode.ToUpper(DeCulture)}\" auf \"{timeslot.MapName}\" in einem Spiel mit {timeslot.PlayerCount} Spielern.\n"
),
_
=> string.Create(
EnCulture,
$"at {timeslot.Time:t} you play in \"{timeslot.GroupCode.ToUpper(EnCulture)}\" on \"{timeslot.MapName}\" in a game with {timeslot.PlayerCount} players.\n"
),
}
);
}
builder.Append(
lang switch
{
"de" => "Viel Spaß!",
_ => "Have fun!",
}
);
return builder.ToString();
}
}

public record EventInstanceUpdated(string EventId) : IPushNotificationData
public record EventInstanceUpdated(
string EventId,
[property: JsonIgnore] NotificationTimeslotInfo[] Timeslots
) : IPushNotificationData
{
public string Type => "event-instance-updated";

Expand All @@ -78,12 +118,37 @@ public string GetTitle(string lang) =>
_ => "Your room has changed!",
};

public string GetBody(string lang) =>
NormalizeLang(lang) switch
public string GetBody(string lang)
{
lang = NormalizeLang(lang);
var builder = new StringBuilder();
foreach (var timeslot in Timeslots)
{
"de" => "Schaue nach in welchen Räumen du jetzt spielst.",
_ => "Check which rooms you are playing in now.",
};
builder.Append(
lang switch
{
"de"
=> string.Create(
DeCulture,
$"um {timeslot.Time:t} Uhr spielst du in \"{timeslot.GroupCode.ToUpper(DeCulture)}\" auf \"{timeslot.MapName}\" in einem Spiel mit {timeslot.PlayerCount} Spielern.\n"
),
_
=> string.Create(
EnCulture,
$"at {timeslot.Time:t} you play in \"{timeslot.GroupCode.ToUpper(EnCulture)}\" on \"{timeslot.MapName}\" in a game with {timeslot.PlayerCount} players.\n"
),
}
);
}
builder.Append(
lang switch
{
"de" => "Viel Spaß!",
_ => "Have fun!",
}
);
return builder.ToString();
}
}

public record EventTimeslotStarting(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.Linq;
using FastEndpoints;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using MinigolfFriday.Data;
using MinigolfFriday.Data.Entities;
using MinigolfFriday.Domain.Models;
using MinigolfFriday.Domain.Models.Push;
using MinigolfFriday.Domain.Models.RealtimeEvents;
using MinigolfFriday.Host.Common;
using MinigolfFriday.Host.Mappers;
using MinigolfFriday.Host.Services;
using WebPush;

namespace MinigolfFriday.Host.Endpoints.Administration.Events;

Expand All @@ -27,7 +31,7 @@
DatabaseContext databaseContext,
IRealtimeEventsService realtimeEventsService,
IIdService idService,
IUserPushSubscriptionMapper userPushSubscriptionMapper,

Check warning on line 34 in src/server/host/Endpoints/Administration/Events/StartEventEndpoint.cs

View workflow job for this annotation

GitHub Actions / Build

Parameter 'userPushSubscriptionMapper' is unread.

Check warning on line 34 in src/server/host/Endpoints/Administration/Events/StartEventEndpoint.cs

View workflow job for this annotation

GitHub Actions / Build

Parameter 'userPushSubscriptionMapper' is unread.

Check warning on line 34 in src/server/host/Endpoints/Administration/Events/StartEventEndpoint.cs

View workflow job for this annotation

GitHub Actions / Build

Parameter 'userPushSubscriptionMapper' is unread.
IWebPushService webPushService
) : Endpoint<StartEventRequest>
{
Expand Down Expand Up @@ -125,22 +129,36 @@
ct
);

var pushSubscription = await databaseContext
.Events.Where(x => x.Id == eventId)
.SelectMany(x => x.Timeslots)
.SelectMany(x => x.Instances)
.SelectMany(x => x.Players)
.SelectMany(x => x.PushSubscriptions)
.Where(x =>
x.User.Settings == null
|| (x.User.Settings.EnableNotifications && x.User.Settings.NotifyOnEventStart)
)
.Select(userPushSubscriptionMapper.MapUserPushSubscriptionExpression)
.ToListAsync(ct);
await webPushService.SendAsync(
pushSubscription,
new PushNotificationData.EventStarted(idService.Event.Encode(eventId)),
ct
);
var notifications = await databaseContext
.Users.Where(u => u.EventInstances.Any(i => i.EventTimeslot.EventId == eventId))
.Select(u => new
{
Subscriptions = u.PushSubscriptions.Select(x => new UserPushSubscription(
x.Id,
x.UserId,
x.Lang,
x.Endpoint,
x.P256DH,
x.Auth
)),
NotificationData = new PushNotificationData.EventStarted(
idService.Event.Encode(eventId),
u.EventInstances.Where(i => i.EventTimeslot.EventId == eventId)
.Select(i => new NotificationTimeslotInfo(
i.EventTimeslot.Time,
i.GroupCode,
i.EventTimeslot.Map!.Name,
i.Players.Count
))
.ToArray()
)
})
.ToArrayAsync(ct);
foreach (var notification in notifications)
await webPushService.SendAsync(
notification.Subscriptions,
notification.NotificationData,
ct
);
}
}
Loading