Lightfinder-profiles

Reviewed-on: #18
This commit was merged in pull request #18.
This commit is contained in:
2025-10-16 22:25:51 +02:00
2 changed files with 139 additions and 2 deletions

View File

@@ -72,7 +72,7 @@ public partial class LightlessHub
var existingData = await GetPairInfo(UserUID, otherUser.UID).ConfigureAwait(false);
var permissions = existingData?.OwnPermissions;
if (permissions == null || !permissions.Sticky)
if (permissions == null || !permissions.Sticky)
{
var ownDefaultPermissions = await DbContext.UserDefaultPreferredPermissions.AsNoTracking().SingleOrDefaultAsync(f => f.UserUID == UserUID, cancellationToken: RequestAbortedToken).ConfigureAwait(false);
@@ -523,6 +523,52 @@ public partial class LightlessHub
}
}
private async Task<(BroadcastRedisEntry? Entry, TimeSpan? Expiry)> TryGetBroadcastEntryAsync(string hashedCid)
{
var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
RedisValueWithExpiry value;
try
{
value = await _redis.Database.StringGetWithExpiryAsync(key).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileLookupFailed", "CID", hashedCid, "Error", ex));
return (null, null);
}
if (value.Value.IsNullOrEmpty || value.Expiry is null || value.Expiry <= TimeSpan.Zero)
{
return (null, value.Expiry);
}
BroadcastRedisEntry? entry;
try
{
entry = JsonSerializer.Deserialize<BroadcastRedisEntry>(value.Value!);
}
catch (Exception ex)
{
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileDeserializeFailed", "CID", hashedCid, "Raw", value.Value.ToString(), "Error", ex));
return (null, value.Expiry);
}
if (entry is null || !string.Equals(entry.HashedCID, hashedCid, StringComparison.Ordinal))
{
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileEntryMismatch", "CID", hashedCid, "EntryCID", entry?.HashedCID ?? "null"));
return (null, value.Expiry);
}
return (entry, value.Expiry);
}
private static bool HasActiveBroadcast(BroadcastRedisEntry? entry, TimeSpan? expiry) =>
entry?.HasOwner() == true && expiry.HasValue && expiry.Value > TimeSpan.Zero;
private static bool IsActiveBroadcastForUser(BroadcastRedisEntry? entry, TimeSpan? expiry, string userUid) =>
HasActiveBroadcast(entry, expiry) && entry!.OwnedBy(userUid);
private static bool IsValidHashedCid(string? cid)
{
if (string.IsNullOrWhiteSpace(cid))
@@ -792,6 +838,97 @@ public partial class LightlessHub
return new UserProfileDto(user.User, false, data.IsNSFW, data.Base64ProfileImage, data.UserDescription);
}
[Authorize(Policy = "Identified")]
public async Task<UserProfileDto?> UserGetLightfinderProfile(string hashedCid)
{
_logger.LogCallInfo(LightlessHubLogger.Args("LightfinderProfile", hashedCid));
if (!_broadcastConfiguration.EnableBroadcasting)
{
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Lightfinder is currently disabled.").ConfigureAwait(false);
return null;
}
if (!IsValidHashedCid(hashedCid))
{
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileInvalidCid", hashedCid));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "Invalid Lightfinder target.").ConfigureAwait(false);
return null;
}
var viewerCid = UserCharaIdent;
if (!IsValidHashedCid(viewerCid))
{
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You must be using Lightfinder to open player profiles.").ConfigureAwait(false);
return null;
}
var (viewerEntry, viewerExpiry) = await TryGetBroadcastEntryAsync(viewerCid).ConfigureAwait(false);
if (!IsActiveBroadcastForUser(viewerEntry, viewerExpiry, UserUID))
{
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You must be using Lightfinder to open player profiles.").ConfigureAwait(false);
return null;
}
var (targetEntry, targetExpiry) = await TryGetBroadcastEntryAsync(hashedCid).ConfigureAwait(false);
if (!HasActiveBroadcast(targetEntry, targetExpiry))
{
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "That player is not currently using Lightfinder.").ConfigureAwait(false);
return null;
}
if (string.IsNullOrEmpty(targetEntry!.OwnerUID))
{
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "That player is not currently using Lightfinder.").ConfigureAwait(false);
return null;
}
var targetUser = await DbContext.Users.AsNoTracking()
.SingleOrDefaultAsync(u => u.UID == targetEntry.OwnerUID, cancellationToken: RequestAbortedToken)
.ConfigureAwait(false);
if (targetUser == null)
{
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileMissingUser", hashedCid, "OwnerUID", targetEntry.OwnerUID));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "Unable to load the players profile at this time.").ConfigureAwait(false);
return null;
}
var displayAlias = string.IsNullOrWhiteSpace(targetUser.Alias)
? "LightfinderUser"
: targetUser.Alias;
var userData = new UserData(
UID: hashedCid,
Alias: displayAlias,
IsAdmin: false,
IsModerator: false,
HasVanity: false,
TextColorHex: targetUser.TextColorHex,
TextGlowColorHex: targetUser.TextGlowColorHex);
var profile = await DbContext.UserProfileData.AsNoTracking()
.SingleOrDefaultAsync(u => u.UserUID == targetEntry.OwnerUID, cancellationToken: RequestAbortedToken)
.ConfigureAwait(false);
if (profile == null)
{
return new UserProfileDto(userData, false, null, null, null);
}
if (profile.FlaggedForReport)
{
return new UserProfileDto(userData, true, null, null, "This profile is flagged for report and pending evaluation");
}
if (profile.ProfileDisabled)
{
return new UserProfileDto(userData, true, null, null, "This profile was permanently disabled");
}
return new UserProfileDto(userData, false, profile.IsNSFW, profile.Base64ProfileImage, profile.UserDescription);
}
[Authorize(Policy = "Identified")]
public async Task UserPushData(UserCharaDataMessageDto dto)
{