mirror of
https://github.com/CannedNet/CannedNet.git
synced 2026-10-27 07:58:59 -07:00
attempt to fix notifications for ConsumableMappingAdded
it didnt work
This commit is contained in:
@@ -28,7 +28,11 @@ public class NotificationsHub : Hub
|
|||||||
|
|
||||||
public async Task SubscribeToPlayers(SubscriptionList subscriptionList)
|
public async Task SubscribeToPlayers(SubscriptionList subscriptionList)
|
||||||
{
|
{
|
||||||
await _notificationService.SubscribeToPlayers(Context.ConnectionId, subscriptionList);
|
var hubContext = GetService<IHubContext<NotificationsHub>>();
|
||||||
|
if (hubContext != null)
|
||||||
|
{
|
||||||
|
await _notificationService.SubscribeToPlayers(Context.ConnectionId, subscriptionList, hubContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<HashSet<int>> GetSubscriptions()
|
public Task<HashSet<int>> GetSubscriptions()
|
||||||
@@ -40,4 +44,9 @@ public class NotificationsHub : Hub
|
|||||||
{
|
{
|
||||||
return _notificationService;
|
return _notificationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private T? GetService<T>() where T : class
|
||||||
|
{
|
||||||
|
return Context.GetHttpContext()?.RequestServices.GetService(typeof(T)) as T;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,21 @@ public class BuyItemRequest
|
|||||||
public int? CouponConsumablePlayerMappingId { get; set; }
|
public int? CouponConsumablePlayerMappingId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("Gift")]
|
[JsonPropertyName("Gift")]
|
||||||
public object? Gift { get; set; }
|
public GiftRequest? Gift { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GiftRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("ToPlayerId")]
|
||||||
|
public int ToPlayerId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("Message")]
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("Anonymous")]
|
||||||
|
public bool Anonymous { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("GiftContext")]
|
||||||
|
public int GiftContext { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class NotificationMessage
|
|||||||
public string? NotificationId { get; set; }
|
public string? NotificationId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("notificationType")]
|
[JsonPropertyName("notificationType")]
|
||||||
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
public PushNotificationId? NotificationType { get; set; }
|
public PushNotificationId? NotificationType { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
|
|||||||
@@ -1353,15 +1353,26 @@ public class APIController
|
|||||||
db.TokenBalances.Update(tokenBalance);
|
db.TokenBalances.Update(tokenBalance);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Store each gift in the database as a received gift with all properties
|
var receiverAccountId = id;
|
||||||
|
int? senderPlayerId = null;
|
||||||
|
|
||||||
|
if (buyRequest.Gift != null)
|
||||||
|
{
|
||||||
|
receiverAccountId = buyRequest.Gift.ToPlayerId;
|
||||||
|
if (!buyRequest.Gift.Anonymous)
|
||||||
|
{
|
||||||
|
senderPlayerId = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var storedGifts = new List<ReceivedGift>();
|
var storedGifts = new List<ReceivedGift>();
|
||||||
foreach (var giftDrop in storefrontItem.GiftDrops)
|
foreach (var giftDrop in storefrontItem.GiftDrops)
|
||||||
{
|
{
|
||||||
var receivedGift = new ReceivedGift
|
var receivedGift = new ReceivedGift
|
||||||
{
|
{
|
||||||
ReceiverAccountId = id,
|
ReceiverAccountId = receiverAccountId,
|
||||||
FromPlayerId = null,
|
FromPlayerId = senderPlayerId,
|
||||||
Message = "A gift for you <3",
|
Message = buyRequest.Gift?.Message ?? "A gift for you <3",
|
||||||
ConsumableItemDesc = giftDrop.ConsumableItemDesc ?? string.Empty,
|
ConsumableItemDesc = giftDrop.ConsumableItemDesc ?? string.Empty,
|
||||||
AvatarItemDesc = giftDrop.AvatarItemDesc ?? string.Empty,
|
AvatarItemDesc = giftDrop.AvatarItemDesc ?? string.Empty,
|
||||||
FriendlyName = giftDrop.FriendlyName ?? string.Empty,
|
FriendlyName = giftDrop.FriendlyName ?? string.Empty,
|
||||||
@@ -1375,7 +1386,7 @@ public class APIController
|
|||||||
Platform = -1,
|
Platform = -1,
|
||||||
PlatformsToSpawnOn = -1,
|
PlatformsToSpawnOn = -1,
|
||||||
BalanceType = 0,
|
BalanceType = 0,
|
||||||
GiftContext = giftDrop.Context,
|
GiftContext = buyRequest.Gift?.GiftContext ?? giftDrop.Context,
|
||||||
GiftRarity = giftDrop.Rarity,
|
GiftRarity = giftDrop.Rarity,
|
||||||
ReceivedAt = DateTime.UtcNow,
|
ReceivedAt = DateTime.UtcNow,
|
||||||
IsConsumed = false
|
IsConsumed = false
|
||||||
@@ -1386,7 +1397,6 @@ public class APIController
|
|||||||
}
|
}
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Build the response with stored gift IDs
|
|
||||||
var giftData = storedGifts.Select(rg => new GiftData
|
var giftData = storedGifts.Select(rg => new GiftData
|
||||||
{
|
{
|
||||||
Id = rg.Id,
|
Id = rg.Id,
|
||||||
@@ -1424,28 +1434,27 @@ public class APIController
|
|||||||
Platform = -1
|
Platform = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send notification for purchase
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hubContext = app.Services.GetService<IHubContext>();
|
var purchaseNotification = notificationService.CreateNotification(
|
||||||
if (hubContext != null)
|
PushNotificationId.StorefrontBalancePurchase,
|
||||||
{
|
id: storefrontItem.Id,
|
||||||
var purchaseNotification = notificationService.CreateNotification(
|
toAccountId: id,
|
||||||
PushNotificationId.StorefrontBalancePurchase,
|
data: new Dictionary<string, object>
|
||||||
id: storefrontItem.Id,
|
{
|
||||||
toAccountId: id,
|
{ "ItemId", buyRequest.PurchasableItemId },
|
||||||
data: new Dictionary<string, object>
|
{ "Price", price.Price },
|
||||||
{
|
{ "CurrencyType", buyRequest.CurrencyType },
|
||||||
{ "ItemId", buyRequest.PurchasableItemId },
|
{ "NewBalance", tokenBalance.Balance }
|
||||||
{ "Price", price.Price },
|
}
|
||||||
{ "CurrencyType", buyRequest.CurrencyType },
|
);
|
||||||
{ "NewBalance", tokenBalance.Balance }
|
await notificationService.SendNotificationToPlayer(id, purchaseNotification);
|
||||||
}
|
|
||||||
);
|
|
||||||
await notificationService.SendNotificationToPlayer(null, hubContext, id, purchaseNotification);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception notifEx)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error sending purchase notification: {notifEx.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return Results.Ok(response);
|
return Results.Ok(response);
|
||||||
}
|
}
|
||||||
@@ -1501,7 +1510,6 @@ public class APIController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all earnable rewards for this context
|
|
||||||
var earnableRewards = await db.EarnableRewards
|
var earnableRewards = await db.EarnableRewards
|
||||||
.Where(er => er.RewardContext == giftContext)
|
.Where(er => er.RewardContext == giftContext)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -1515,30 +1523,25 @@ public class APIController
|
|||||||
int giftRarity = 0;
|
int giftRarity = 0;
|
||||||
string consumableItemDesc = "";
|
string consumableItemDesc = "";
|
||||||
|
|
||||||
// 60/40 roll - 60% earnable item, 40% tokens
|
|
||||||
bool isEarnableItem = random.Next(0, 100) < 60;
|
bool isEarnableItem = random.Next(0, 100) < 60;
|
||||||
|
|
||||||
if (isEarnableItem && earnableRewards.Any())
|
if (isEarnableItem && earnableRewards.Any())
|
||||||
{
|
{
|
||||||
// Get rewards that are avatar items (have avatarItemDesc set)
|
|
||||||
var avatarRewards = earnableRewards.Where(er => !string.IsNullOrEmpty(er.AvatarItemDesc)).ToList();
|
var avatarRewards = earnableRewards.Where(er => !string.IsNullOrEmpty(er.AvatarItemDesc)).ToList();
|
||||||
|
|
||||||
if (avatarRewards.Any())
|
if (avatarRewards.Any())
|
||||||
{
|
{
|
||||||
// Get all avatar items the player currently owns
|
|
||||||
var ownedAvatarItems = await db.AvatarItems
|
var ownedAvatarItems = await db.AvatarItems
|
||||||
.Where(ai => ai.OwnerAccountId == id)
|
.Where(ai => ai.OwnerAccountId == id)
|
||||||
.Select(ai => ai.AvatarItemDesc)
|
.Select(ai => ai.AvatarItemDesc)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
// Filter to rewards the player doesn't own
|
|
||||||
var unownedRewards = avatarRewards
|
var unownedRewards = avatarRewards
|
||||||
.Where(ar => !ownedAvatarItems.Contains(ar.AvatarItemDesc))
|
.Where(ar => !ownedAvatarItems.Contains(ar.AvatarItemDesc))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (unownedRewards.Any())
|
if (unownedRewards.Any())
|
||||||
{
|
{
|
||||||
// Randomly select one of the unowned rewards
|
|
||||||
var selectedReward = unownedRewards[random.Next(unownedRewards.Count)];
|
var selectedReward = unownedRewards[random.Next(unownedRewards.Count)];
|
||||||
avatarItemDesc = selectedReward.AvatarItemDesc;
|
avatarItemDesc = selectedReward.AvatarItemDesc;
|
||||||
friendlyName = selectedReward.FriendlyName;
|
friendlyName = selectedReward.FriendlyName;
|
||||||
@@ -1547,28 +1550,23 @@ public class APIController
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Player owns all avatar items, give token box instead
|
|
||||||
isEarnableItem = false;
|
isEarnableItem = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No avatar rewards, give token box instead
|
|
||||||
isEarnableItem = false;
|
isEarnableItem = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not earnable item or player owns all items, generate a token box
|
|
||||||
if (!isEarnableItem)
|
if (!isEarnableItem)
|
||||||
{
|
{
|
||||||
int[] tokenAmounts = { 10, 25, 50, 100, 250, 500 };
|
int[] tokenAmounts = {10, 25, 50, 100, 250, 500};
|
||||||
currency = tokenAmounts[random.Next(tokenAmounts.Length)];
|
currency = tokenAmounts[random.Next(tokenAmounts.Length)];
|
||||||
currencyType = 2;
|
currencyType = 2;
|
||||||
consumableItemDesc = $"TokenBox_{currency}";
|
|
||||||
giftRarity = 20;
|
giftRarity = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the received gift record
|
|
||||||
var receivedGift = new ReceivedGift
|
var receivedGift = new ReceivedGift
|
||||||
{
|
{
|
||||||
ReceiverAccountId = id,
|
ReceiverAccountId = id,
|
||||||
@@ -1640,7 +1638,6 @@ public class APIController
|
|||||||
if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId.AsSpan(), out var id))
|
if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId.AsSpan(), out var id))
|
||||||
return Results.Unauthorized();
|
return Results.Unauthorized();
|
||||||
|
|
||||||
// Parse form data
|
|
||||||
request.EnableBuffering();
|
request.EnableBuffering();
|
||||||
request.Body.Position = 0;
|
request.Body.Position = 0;
|
||||||
using var reader = new StreamReader(request.Body);
|
using var reader = new StreamReader(request.Body);
|
||||||
@@ -1669,7 +1666,6 @@ public class APIController
|
|||||||
return Results.BadRequest(new { success = false, error = "Invalid gift ID" });
|
return Results.BadRequest(new { success = false, error = "Invalid gift ID" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for the ReceivedGift
|
|
||||||
var receivedGift = await db.ReceivedGifts
|
var receivedGift = await db.ReceivedGifts
|
||||||
.FirstOrDefaultAsync(rg => rg.Id == giftId && rg.ReceiverAccountId == id);
|
.FirstOrDefaultAsync(rg => rg.Id == giftId && rg.ReceiverAccountId == id);
|
||||||
|
|
||||||
@@ -1678,7 +1674,6 @@ public class APIController
|
|||||||
return Results.NotFound(new { success = false, error = "Gift not found" });
|
return Results.NotFound(new { success = false, error = "Gift not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the gift based on its properties
|
|
||||||
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
||||||
{
|
{
|
||||||
var existingConsumable = await db.ConsumableItems
|
var existingConsumable = await db.ConsumableItems
|
||||||
@@ -1719,44 +1714,69 @@ public class APIController
|
|||||||
};
|
};
|
||||||
db.AvatarItems.Add(avatarItem);
|
db.AvatarItems.Add(avatarItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(receivedGift.Currency.ToString()) && receivedGift.CurrencyType == 2)
|
||||||
|
{
|
||||||
|
var tokenBalance = await db.TokenBalances
|
||||||
|
.FirstOrDefaultAsync(tb => tb.Id == id &&
|
||||||
|
tb.CurrencyType == receivedGift.CurrencyType &&
|
||||||
|
tb.BalanceType == -1);
|
||||||
|
|
||||||
|
if (tokenBalance == null)
|
||||||
|
{
|
||||||
|
tokenBalance = new TokenBalance
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
CurrencyType = receivedGift.CurrencyType,
|
||||||
|
BalanceType = -1,
|
||||||
|
Balance = receivedGift.Currency
|
||||||
|
};
|
||||||
|
db.TokenBalances.Add(tokenBalance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tokenBalance.Balance += receivedGift.Currency;
|
||||||
|
db.TokenBalances.Update(tokenBalance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mark the gift as consumed
|
|
||||||
receivedGift.IsConsumed = true;
|
receivedGift.IsConsumed = true;
|
||||||
receivedGift.ConsumedAt = DateTime.UtcNow;
|
receivedGift.ConsumedAt = DateTime.UtcNow;
|
||||||
db.ReceivedGifts.Update(receivedGift);
|
db.ReceivedGifts.Update(receivedGift);
|
||||||
|
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Send notifications based on what was added
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var hubContext = app.Services.GetService<IHubContext>();
|
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
||||||
if (hubContext != null)
|
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
var consumableNotification = notificationService.CreateNotification(
|
||||||
{
|
PushNotificationId.ConsumableMappingAdded,
|
||||||
var consumableNotification = notificationService.CreateNotification(
|
id: giftId,
|
||||||
PushNotificationId.ConsumableMappingAdded,
|
toAccountId: id,
|
||||||
id: giftId,
|
data: new Dictionary<string, object>
|
||||||
toAccountId: id,
|
{
|
||||||
data: new Dictionary<string, object>
|
{ "Id", giftId },
|
||||||
{
|
{ "ConsumableType", "JfnVXFmilU6ysv-VbTAe3A" },
|
||||||
{ "Id", (long)giftId },
|
{ "PlatformMask", 4294967295 },
|
||||||
{ "ConsumableItemDesc", receivedGift.ConsumableItemDesc },
|
{ "Count", 1 },
|
||||||
{ "PlatformMask", -1 },
|
{ "InitialCount", 1 },
|
||||||
{ "CreatedAt", DateTime.UtcNow },
|
{ "UnlockedLevel", 0 },
|
||||||
{ "Count", 1 },
|
{ "CreatedAt", DateTime.UtcNow },
|
||||||
{ "InitialCount", 1 },
|
{ "IsActive", false },
|
||||||
{ "UnlockedLevel", 0 },
|
{ "ActiveDurationMinutes", null },
|
||||||
{ "IsActive", false },
|
{ "Category", 0 },
|
||||||
{ "ActiveDurationMinutes", null }
|
{ "IsPlatformLocked", false }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await notificationService.SendNotificationToPlayer(null, hubContext, id, consumableNotification);
|
await notificationService.SendNotificationToPlayer(id, consumableNotification);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception notifEx)
|
||||||
|
{
|
||||||
|
// Log the error but don't fail the gift consumption
|
||||||
|
Console.WriteLine($"Error sending notification: {notifEx.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
return Results.Ok(new { success = true });
|
return Results.Ok(new { success = true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class AccountsController
|
|||||||
return Results.Ok("FUCKL MYSJDIOJD");
|
return Results.Ok("FUCKL MYSJDIOJD");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapGet("/account/me", (HttpRequest request, AppDbContext db) =>
|
app.MapGet("/account/me", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var authHeader = request.Headers.Authorization.ToString();
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
@@ -32,17 +32,21 @@ public class AccountsController
|
|||||||
if (!int.TryParse(accountId.AsSpan(), out var id))
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
return Results.Unauthorized();
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var account = await db.Accounts.FindAsync(id);
|
||||||
|
if (account == null)
|
||||||
|
return Results.NotFound();
|
||||||
|
|
||||||
var selfAccount = new SelfAccount
|
var selfAccount = new SelfAccount
|
||||||
{
|
{
|
||||||
AccountId = id,
|
AccountId = id,
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
IsJunior = false,
|
IsJunior = account.IsJunior,
|
||||||
Platforms = 0,
|
Platforms = account.Platforms ?? 0,
|
||||||
PersonalPronouns = 0,
|
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||||
IdentityFlags = 0,
|
IdentityFlags = account.IdentityFlags ?? 0,
|
||||||
Username = $"Player{id}",
|
Username = account.Username ?? $"Player{id}",
|
||||||
DisplayName = $"Player{id}",
|
DisplayName = account.DisplayName ?? $"Player{id}",
|
||||||
CreatedAt = DateTime.UtcNow,
|
CreatedAt = account.CreatedAt,
|
||||||
Email = null,
|
Email = null,
|
||||||
Phone = null,
|
Phone = null,
|
||||||
JuniorState = null,
|
JuniorState = null,
|
||||||
@@ -54,54 +58,62 @@ public class AccountsController
|
|||||||
return Results.Ok(selfAccount);
|
return Results.Ok(selfAccount);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapGet("/account/bulk", (HttpRequest request) =>
|
app.MapGet("/account/bulk", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var ids = request.Query["id"];
|
var ids = request.Query["id"];
|
||||||
var accounts = new List<Account>();
|
var accountIds = new List<int>();
|
||||||
|
|
||||||
foreach (var id in ids)
|
foreach (var id in ids)
|
||||||
{
|
{
|
||||||
if (int.TryParse(id, out var accountId))
|
if (int.TryParse(id, out var accountId))
|
||||||
{
|
{
|
||||||
accounts.Add(new Account
|
accountIds.Add(accountId);
|
||||||
{
|
|
||||||
AccountId = accountId,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{accountId}",
|
|
||||||
DisplayName = $"Player{accountId}",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Results.Json(accounts);
|
var accounts = await db.Accounts
|
||||||
|
.Where(a => accountIds.Contains(a.AccountId.Value))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var result = accounts.Select(a => new Account
|
||||||
|
{
|
||||||
|
AccountId = a.AccountId,
|
||||||
|
ProfileImage = a.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = a.IsJunior,
|
||||||
|
Platforms = a.Platforms ?? 0,
|
||||||
|
PersonalPronouns = a.PersonalPronouns ?? 0,
|
||||||
|
IdentityFlags = a.IdentityFlags ?? 0,
|
||||||
|
Username = a.Username ?? $"Player{a.AccountId}",
|
||||||
|
DisplayName = a.DisplayName ?? $"Player{a.AccountId}",
|
||||||
|
CreatedAt = a.CreatedAt
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
return Results.Json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapGet("/account/{id}", (HttpRequest request, string id) =>
|
app.MapGet("/account/{id}", async (HttpRequest request, string id, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var accounts = new Account();
|
if (!int.TryParse(id, out var accountId))
|
||||||
|
return Results.BadRequest();
|
||||||
if (int.TryParse(id, out var accountId))
|
|
||||||
{
|
|
||||||
accounts = new Account
|
|
||||||
{
|
|
||||||
AccountId = accountId,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{accountId}",
|
|
||||||
DisplayName = $"Player{accountId}",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return Results.Json(accounts);
|
var account = await db.Accounts.FindAsync(accountId);
|
||||||
|
if (account == null)
|
||||||
|
return Results.NotFound();
|
||||||
|
|
||||||
|
var result = new Account
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = account.IsJunior,
|
||||||
|
Platforms = account.Platforms ?? 0,
|
||||||
|
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||||
|
IdentityFlags = account.IdentityFlags ?? 0,
|
||||||
|
Username = account.Username ?? $"Player{account.AccountId}",
|
||||||
|
DisplayName = account.DisplayName ?? $"Player{account.AccountId}",
|
||||||
|
CreatedAt = account.CreatedAt
|
||||||
|
};
|
||||||
|
|
||||||
|
return Results.Json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapPost("/account/create", async (HttpRequest httpRequest, AppDbContext db) =>
|
app.MapPost("/account/create", async (HttpRequest httpRequest, AppDbContext db) =>
|
||||||
@@ -175,7 +187,7 @@ public class AccountsController
|
|||||||
var maxRoomId = await db.Rooms.MaxAsync(r => (int?)r.RoomId) ?? 0;
|
var maxRoomId = await db.Rooms.MaxAsync(r => (int?)r.RoomId) ?? 0;
|
||||||
var maxId = await db.Rooms.MaxAsync(r => (int?)r.Id) ?? 0;
|
var maxId = await db.Rooms.MaxAsync(r => (int?)r.Id) ?? 0;
|
||||||
var dormRoomId = maxRoomId + 1;
|
var dormRoomId = maxRoomId + 1;
|
||||||
var dormRoom = new Room
|
var dormRoom = new Room
|
||||||
{
|
{
|
||||||
Id = maxId + 1,
|
Id = maxId + 1,
|
||||||
RoomId = dormRoomId,
|
RoomId = dormRoomId,
|
||||||
@@ -300,7 +312,146 @@ public class AccountsController
|
|||||||
account.DisplayName = newDisplayName;
|
account.DisplayName = newDisplayName;
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
return Results.Ok();
|
return Results.Ok(RecNetResult.Ok());
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPut("/account/me/username", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
string newAccountName = "";
|
||||||
|
|
||||||
|
if (request.ContentLength.HasValue && request.ContentLength > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
request.EnableBuffering();
|
||||||
|
using var reader = new StreamReader(request.Body, leaveOpen: true);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(body))
|
||||||
|
{
|
||||||
|
foreach (var pair in body.Split('&'))
|
||||||
|
{
|
||||||
|
var keyValue = pair.Split('=');
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||||
|
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||||
|
|
||||||
|
if (key == "username")
|
||||||
|
newAccountName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.Body.Position = 0;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var account = await db.Accounts.FindAsync(id);
|
||||||
|
if (account == null)
|
||||||
|
return Results.NotFound();
|
||||||
|
|
||||||
|
account.Username = newAccountName;
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Results.Ok(RecNetResult.Ok());
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/account/{id}/bio", async (HttpRequest request, string id, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
if (!int.TryParse(id, out var accountId))
|
||||||
|
return Results.BadRequest();
|
||||||
|
|
||||||
|
var bio = await db.PlayerBios.FirstOrDefaultAsync(b => b.accountId == accountId);
|
||||||
|
|
||||||
|
if (bio == null)
|
||||||
|
{
|
||||||
|
return Results.Json(new { accountId = accountId, bio = "" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Json(new { accountId = bio.accountId, bio = bio.bio });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPut("/account/me/bio", async (HttpRequest request, AppDbContext db) =>
|
||||||
|
{
|
||||||
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
var token = authHeader.Substring("Bearer ".Length);
|
||||||
|
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accountId))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||||
|
return Results.Unauthorized();
|
||||||
|
|
||||||
|
string newBio = "";
|
||||||
|
|
||||||
|
if (request.ContentLength.HasValue && request.ContentLength > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
request.EnableBuffering();
|
||||||
|
using var reader = new StreamReader(request.Body, leaveOpen: true);
|
||||||
|
var body = await reader.ReadToEndAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(body))
|
||||||
|
{
|
||||||
|
foreach (var pair in body.Split('&'))
|
||||||
|
{
|
||||||
|
var keyValue = pair.Split('=');
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||||
|
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||||
|
|
||||||
|
if (key == "bio")
|
||||||
|
newBio = Uri.UnescapeDataString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.Body.Position = 0;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var bio = await db.PlayerBios.FirstOrDefaultAsync(b => b.accountId == id);
|
||||||
|
|
||||||
|
if (bio == null)
|
||||||
|
{
|
||||||
|
bio = new PlayerBio
|
||||||
|
{
|
||||||
|
accountId = id,
|
||||||
|
bio = newBio
|
||||||
|
};
|
||||||
|
db.PlayerBios.Add(bio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bio.bio = newBio;
|
||||||
|
db.PlayerBios.Update(bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Results.Json(new { success = true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,32 +17,39 @@ public class MatchmakingController
|
|||||||
|
|
||||||
app.MapPost("/player/login", () => Results.Ok());
|
app.MapPost("/player/login", () => Results.Ok());
|
||||||
|
|
||||||
app.MapGet("/player", (HttpRequest request) =>
|
app.MapGet("/player", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
/*
|
var id = request.Query["id"].FirstOrDefault();
|
||||||
var id = request.Query["id"];
|
if (string.IsNullOrEmpty(id) || !int.TryParse(id, out var accountId))
|
||||||
var accounts = new List<Account>();
|
|
||||||
|
|
||||||
if (int.TryParse(id, out var accountId))
|
|
||||||
{
|
{
|
||||||
accounts.Add(new Account
|
var json = File.ReadAllText("JSON/getplayer.json");
|
||||||
{
|
return Results.Content(json, "application/json");
|
||||||
AccountId = accountId,
|
|
||||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
|
||||||
IsJunior = false,
|
|
||||||
Platforms = 0,
|
|
||||||
PersonalPronouns = 0,
|
|
||||||
IdentityFlags = 0,
|
|
||||||
Username = $"Player{accountId}",
|
|
||||||
DisplayName = $"Player{accountId}",
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Results.Json(accounts);*/
|
var account = await db.Accounts.FindAsync(accountId);
|
||||||
|
if (account == null)
|
||||||
var json = File.ReadAllText("JSON/getplayer.json");
|
{
|
||||||
return Results.Content(json, "application/json");
|
var json = File.ReadAllText("JSON/getplayer.json");
|
||||||
|
return Results.Content(json, "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new List<Account>
|
||||||
|
{
|
||||||
|
new Account
|
||||||
|
{
|
||||||
|
AccountId = account.AccountId,
|
||||||
|
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||||
|
IsJunior = account.IsJunior,
|
||||||
|
Platforms = account.Platforms ?? 0,
|
||||||
|
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||||
|
IdentityFlags = account.IdentityFlags ?? 0,
|
||||||
|
Username = account.Username ?? $"Player{account.AccountId}",
|
||||||
|
DisplayName = account.DisplayName ?? $"Player{account.AccountId}",
|
||||||
|
CreatedAt = account.CreatedAt
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Results.Json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapPost("/goto/room/{room}", async (HttpRequest request, string room, AppDbContext db) =>
|
app.MapPost("/goto/room/{room}", async (HttpRequest request, string room, AppDbContext db) =>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using CannedNet.Hubs;
|
using CannedNet.Hubs;
|
||||||
using CannedNet.Services.Infrastructure;
|
using CannedNet.Services.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
namespace CannedNet.Services.Controllers;
|
namespace CannedNet.Services.Controllers;
|
||||||
|
|
||||||
@@ -10,5 +11,8 @@ public class NotifyController
|
|||||||
public void MapEndpoints(WebApplication app)
|
public void MapEndpoints(WebApplication app)
|
||||||
{
|
{
|
||||||
app.MapHub<NotificationsHub>("/hub/v1");
|
app.MapHub<NotificationsHub>("/hub/v1");
|
||||||
|
|
||||||
|
var hubContext = app.Services.GetRequiredService<IHubContext<NotificationsHub>>();
|
||||||
|
NotificationService.SetHubContext(hubContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using CannedNet.Hubs;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
namespace CannedNet.Services;
|
namespace CannedNet.Services;
|
||||||
|
|
||||||
public class NotificationService
|
public class NotificationService
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, HashSet<int>> _connectionSubscriptions = new();
|
private static readonly ConcurrentDictionary<string, HashSet<int>> _connectionSubscriptions = new();
|
||||||
private readonly ConcurrentDictionary<int, HashSet<string>> _playerConnections = new();
|
private static readonly ConcurrentDictionary<int, HashSet<string>> _playerConnections = new();
|
||||||
|
private static readonly ConcurrentDictionary<int, Queue<NotificationMessage>> _pendingNotifications = new();
|
||||||
|
private static IHubContext<NotificationsHub>? _hubContext;
|
||||||
private readonly ILogger<NotificationService> _logger;
|
private readonly ILogger<NotificationService> _logger;
|
||||||
|
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||||
|
|
||||||
public NotificationService(ILogger<NotificationService> logger)
|
public NotificationService(ILogger<NotificationService> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetHubContext(IHubContext<NotificationsHub> hubContext)
|
||||||
|
{
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
|
||||||
public void OnConnected(string connectionId)
|
public void OnConnected(string connectionId)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation($"Client connected: {connectionId}");
|
||||||
_connectionSubscriptions.TryAdd(connectionId, new HashSet<int>());
|
_connectionSubscriptions.TryAdd(connectionId, new HashSet<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDisconnected(string connectionId)
|
public void OnDisconnected(string connectionId)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation($"Client disconnected: {connectionId}");
|
||||||
if (_connectionSubscriptions.TryRemove(connectionId, out var subscriptions))
|
if (_connectionSubscriptions.TryRemove(connectionId, out var subscriptions))
|
||||||
{
|
{
|
||||||
foreach (var playerId in subscriptions)
|
foreach (var playerId in subscriptions)
|
||||||
@@ -37,11 +50,13 @@ public class NotificationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SubscribeToPlayers(string connectionId, SubscriptionList subscriptionList)
|
public async Task SubscribeToPlayers(string connectionId, SubscriptionList subscriptionList, IHubContext<NotificationsHub> hubContext)
|
||||||
{
|
{
|
||||||
var oldSubscriptions = _connectionSubscriptions.GetValueOrDefault(connectionId, new HashSet<int>());
|
var oldSubscriptions = _connectionSubscriptions.GetValueOrDefault(connectionId, new HashSet<int>());
|
||||||
var newPlayerIds = subscriptionList.PlayerIds ?? new List<int>();
|
var newPlayerIds = subscriptionList.PlayerIds ?? new List<int>();
|
||||||
|
|
||||||
|
_logger.LogInformation($"Connection {connectionId} subscribing to players: {string.Join(", ", newPlayerIds)}");
|
||||||
|
|
||||||
_connectionSubscriptions[connectionId] = new HashSet<int>(newPlayerIds);
|
_connectionSubscriptions[connectionId] = new HashSet<int>(newPlayerIds);
|
||||||
|
|
||||||
foreach (var playerId in newPlayerIds)
|
foreach (var playerId in newPlayerIds)
|
||||||
@@ -54,6 +69,22 @@ public class NotificationService
|
|||||||
existing.Add(connectionId);
|
existing.Add(connectionId);
|
||||||
return existing;
|
return existing;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (_pendingNotifications.TryRemove(playerId, out var pendingQueue))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Found {pendingQueue.Count} pending notifications for player {playerId}. Sending to connection {connectionId}");
|
||||||
|
while (pendingQueue.TryDequeue(out var notification))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SendToConnection(hubContext, connectionId, notification);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Error sending pending notification to player {playerId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var playerId in oldSubscriptions)
|
foreach (var playerId in oldSubscriptions)
|
||||||
@@ -63,8 +94,6 @@ public class NotificationService
|
|||||||
connections.Remove(connectionId);
|
connections.Remove(connectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<int>? GetSubscriptions(string connectionId)
|
public HashSet<int>? GetSubscriptions(string connectionId)
|
||||||
@@ -90,25 +119,45 @@ public class NotificationService
|
|||||||
return Enumerable.Empty<int>();
|
return Enumerable.Empty<int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendNotificationToPlayer(string callerConnectionId, IHubContext hubContext, int playerId, NotificationMessage notification)
|
public async Task SendNotificationToPlayer(int playerId, NotificationMessage notification)
|
||||||
{
|
{
|
||||||
|
if (_hubContext == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No hub context available. Cannot send notification.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var connections = GetConnectionsForPlayer(playerId);
|
var connections = GetConnectionsForPlayer(playerId).ToList();
|
||||||
foreach (var connectionId in connections)
|
_logger.LogInformation($"Attempting to send notification to player {playerId}. Found {connections.Count} connections. NotificationType: {notification.NotificationType}");
|
||||||
{
|
|
||||||
if (connectionId == callerConnectionId)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try
|
if (connections.Any())
|
||||||
|
{
|
||||||
|
foreach (var connectionId in connections)
|
||||||
{
|
{
|
||||||
await hubContext.Clients.Client(connectionId).SendAsync("Notification", notification);
|
try
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
await SendToConnection(_hubContext, connectionId, notification);
|
||||||
{
|
}
|
||||||
_logger.LogError(ex, $"Error sending notification to player {playerId} on connection {connectionId}. NotificationType: {notification.NotificationType}");
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Error sending notification to player {playerId} on connection {connectionId}. NotificationType: {notification.NotificationType}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"No connections found for player {playerId}. Queueing notification for later delivery. NotificationType: {notification.NotificationType}");
|
||||||
|
_pendingNotifications.AddOrUpdate(
|
||||||
|
playerId,
|
||||||
|
_ => new Queue<NotificationMessage>(new[] { notification }),
|
||||||
|
(_, queue) =>
|
||||||
|
{
|
||||||
|
queue.Enqueue(notification);
|
||||||
|
return queue;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -116,11 +165,23 @@ public class NotificationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task BroadcastNotification(IHubContext hubContext, NotificationMessage notification)
|
public async Task BroadcastNotification(NotificationMessage notification)
|
||||||
{
|
{
|
||||||
|
if (_hubContext == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("No hub context available. Cannot broadcast notification.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await hubContext.Clients.All.SendAsync("Notification", notification);
|
foreach (var kvp in _playerConnections)
|
||||||
|
{
|
||||||
|
foreach (var connectionId in kvp.Value)
|
||||||
|
{
|
||||||
|
await SendToConnection(_hubContext, connectionId, notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -141,4 +202,58 @@ public class NotificationService
|
|||||||
Data = data
|
Data = data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task SendToConnection(IHubContext<NotificationsHub> hubContext, string connectionId, NotificationMessage notification)
|
||||||
|
{
|
||||||
|
var notificationData = BuildNotificationObject(notification);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(notificationData);
|
||||||
|
System.Console.WriteLine($"[NotificationService] Sending notification to {connectionId}: {json}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Console.WriteLine($"[NotificationService] Error serializing notification: {ex.Message}");
|
||||||
|
}
|
||||||
|
await hubContext.Clients.Client(connectionId).SendAsync("Notification", notificationData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, object?> BuildNotificationObject(NotificationMessage notification)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object?>
|
||||||
|
{
|
||||||
|
{ "notificationId", notification.NotificationId ?? "" },
|
||||||
|
{ "notificationType", (int?)notification.NotificationType ?? 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only add optional fields if they have values
|
||||||
|
if (notification.Id.HasValue)
|
||||||
|
dict.Add("id", notification.Id.Value);
|
||||||
|
if (notification.FromAccountId.HasValue)
|
||||||
|
dict.Add("fromAccountId", notification.FromAccountId.Value);
|
||||||
|
if (notification.ToAccountId.HasValue)
|
||||||
|
dict.Add("toAccountId", notification.ToAccountId.Value);
|
||||||
|
if (notification.CreatedAt.HasValue)
|
||||||
|
dict.Add("createdAt", notification.CreatedAt.Value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||||
|
|
||||||
|
// Properly serialize the data dictionary, converting DateTime objects to ISO 8601 strings
|
||||||
|
var serializedData = new Dictionary<string, object>();
|
||||||
|
if (notification.Data != null && notification.Data.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var kvp in notification.Data)
|
||||||
|
{
|
||||||
|
if (kvp.Value is DateTime dt)
|
||||||
|
{
|
||||||
|
serializedData[kvp.Key] = dt.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
|
||||||
|
}
|
||||||
|
else if (kvp.Value != null)
|
||||||
|
{
|
||||||
|
serializedData[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.Add("data", serializedData);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user