mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-09-22 09:19:01 +00:00
Initial implementation of recent activity
DB migrations intentionally left out since they aren't finalized
This commit is contained in:
parent
605f9e68c5
commit
23cb1bef1c
86 changed files with 1542 additions and 93 deletions
|
@ -0,0 +1,286 @@
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("LITTLEBIGPLANETPS3_XML/stream")]
|
||||||
|
[Produces("text/xml")]
|
||||||
|
public class ActivityController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly DatabaseContext database;
|
||||||
|
|
||||||
|
public ActivityController(DatabaseContext database)
|
||||||
|
{
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ActivityDto
|
||||||
|
{
|
||||||
|
public required ActivityEntity Activity { get; set; }
|
||||||
|
public int? TargetSlotId { get; set; }
|
||||||
|
public int? TargetUserId { get; set; }
|
||||||
|
public int? TargetPlaylistId { get; set; }
|
||||||
|
public int? SlotCreatorId { get; set; }
|
||||||
|
}
|
||||||
|
//TODO refactor this mess into a separate db file or something
|
||||||
|
|
||||||
|
private static Expression<Func<ActivityEntity, ActivityDto>> ActivityToDto()
|
||||||
|
{
|
||||||
|
return a => new ActivityDto
|
||||||
|
{
|
||||||
|
Activity = a,
|
||||||
|
TargetSlotId = a is LevelActivityEntity
|
||||||
|
? ((LevelActivityEntity)a).SlotId
|
||||||
|
: a is PhotoActivityEntity && ((PhotoActivityEntity)a).Photo.PhotoId != 0
|
||||||
|
? ((PhotoActivityEntity)a).Photo.SlotId
|
||||||
|
: a is CommentActivityEntity && ((CommentActivityEntity)a).Comment.Type == CommentType.Level
|
||||||
|
? ((CommentActivityEntity)a).Comment.TargetId
|
||||||
|
: a is ScoreActivityEntity
|
||||||
|
? ((ScoreActivityEntity)a).Score.SlotId
|
||||||
|
: 0,
|
||||||
|
|
||||||
|
TargetUserId = a is UserActivityEntity
|
||||||
|
? ((UserActivityEntity)a).TargetUserId
|
||||||
|
: a is CommentActivityEntity && ((CommentActivityEntity)a).Comment.Type == CommentType.Profile
|
||||||
|
? ((CommentActivityEntity)a).Comment.TargetId
|
||||||
|
: a is PhotoActivityEntity && ((PhotoActivityEntity)a).Photo.SlotId != 0
|
||||||
|
? ((PhotoActivityEntity)a).Photo.CreatorId
|
||||||
|
: 0,
|
||||||
|
TargetPlaylistId = a is PlaylistActivityEntity ? ((PlaylistActivityEntity)a).PlaylistId : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IQueryable<IGrouping<ActivityGroup, ActivityEntity>> GroupActivities
|
||||||
|
(IQueryable<ActivityEntity> activityQuery)
|
||||||
|
{
|
||||||
|
return activityQuery.Select(ActivityToDto())
|
||||||
|
.GroupBy(dto => new ActivityGroup
|
||||||
|
{
|
||||||
|
Timestamp = dto.Activity.Timestamp.Date,
|
||||||
|
UserId = dto.Activity.UserId,
|
||||||
|
TargetUserId = dto.TargetUserId,
|
||||||
|
TargetSlotId = dto.TargetSlotId,
|
||||||
|
TargetPlaylistId = dto.TargetPlaylistId,
|
||||||
|
},
|
||||||
|
dto => dto.Activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IQueryable<IGrouping<ActivityGroup, ActivityEntity>> GroupActivities
|
||||||
|
(IQueryable<ActivityDto> activityQuery)
|
||||||
|
{
|
||||||
|
return activityQuery.GroupBy(dto => new ActivityGroup
|
||||||
|
{
|
||||||
|
Timestamp = dto.Activity.Timestamp.Date,
|
||||||
|
UserId = dto.Activity.UserId,
|
||||||
|
TargetUserId = dto.TargetUserId,
|
||||||
|
TargetSlotId = dto.TargetSlotId,
|
||||||
|
TargetPlaylistId = dto.TargetPlaylistId,
|
||||||
|
},
|
||||||
|
dto => dto.Activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this is kinda ass, can maybe improve once comment migration is merged
|
||||||
|
private async Task<IQueryable<ActivityEntity>> GetFilters
|
||||||
|
(
|
||||||
|
GameTokenEntity token,
|
||||||
|
bool excludeNews,
|
||||||
|
bool excludeMyLevels,
|
||||||
|
bool excludeFriends,
|
||||||
|
bool excludeFavouriteUsers,
|
||||||
|
bool excludeMyself
|
||||||
|
)
|
||||||
|
{
|
||||||
|
IQueryable<ActivityEntity> query = this.database.Activities.AsQueryable();
|
||||||
|
if (excludeNews) query = query.Where(a => a.Type != EventType.NewsPost);
|
||||||
|
|
||||||
|
IQueryable<ActivityDto> dtoQuery = query.Select(a => new ActivityDto
|
||||||
|
{
|
||||||
|
Activity = a,
|
||||||
|
SlotCreatorId = a is LevelActivityEntity
|
||||||
|
? ((LevelActivityEntity)a).Slot.CreatorId
|
||||||
|
: a is PhotoActivityEntity && ((PhotoActivityEntity)a).Photo.SlotId != 0
|
||||||
|
? ((PhotoActivityEntity)a).Photo.Slot!.CreatorId
|
||||||
|
: a is CommentActivityEntity && ((CommentActivityEntity)a).Comment.Type == CommentType.Level
|
||||||
|
? ((CommentActivityEntity)a).Comment.TargetId
|
||||||
|
: a is ScoreActivityEntity
|
||||||
|
? ((ScoreActivityEntity)a).Score.Slot.CreatorId
|
||||||
|
: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
Expression<Func<ActivityDto, bool>> predicate = PredicateExtensions.False<ActivityDto>();
|
||||||
|
|
||||||
|
predicate = predicate.Or(a => a.SlotCreatorId == 0 || excludeMyLevels
|
||||||
|
? a.SlotCreatorId != token.UserId
|
||||||
|
: a.SlotCreatorId == token.UserId);
|
||||||
|
|
||||||
|
List<int>? friendIds = UserFriendStore.GetUserFriendData(token.UserId)?.FriendIds;
|
||||||
|
if (friendIds != null)
|
||||||
|
{
|
||||||
|
predicate = excludeFriends
|
||||||
|
? predicate.Or(a => !friendIds.Contains(a.Activity.UserId))
|
||||||
|
: predicate.Or(a => friendIds.Contains(a.Activity.UserId));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> favouriteUsers = await this.database.HeartedProfiles.Where(hp => hp.UserId == token.UserId)
|
||||||
|
.Select(hp => hp.HeartedUserId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
predicate = excludeFavouriteUsers
|
||||||
|
? predicate.Or(a => !favouriteUsers.Contains(a.Activity.UserId))
|
||||||
|
: predicate.Or(a => favouriteUsers.Contains(a.Activity.UserId));
|
||||||
|
|
||||||
|
predicate = excludeMyself
|
||||||
|
? predicate.Or(a => a.Activity.UserId != token.UserId)
|
||||||
|
: predicate.Or(a => a.Activity.UserId == token.UserId);
|
||||||
|
|
||||||
|
query = dtoQuery.Where(predicate).Select(dto => dto.Activity);
|
||||||
|
|
||||||
|
return query.OrderByDescending(a => a.Timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<DateTime> GetMostRecentEventTime(GameTokenEntity token, DateTime upperBound)
|
||||||
|
{
|
||||||
|
return this.database.Activities.Where(a => a.UserId == token.UserId)
|
||||||
|
.Where(a => a.Timestamp < upperBound)
|
||||||
|
.OrderByDescending(a => a.Timestamp)
|
||||||
|
.Select(a => a.Timestamp)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GlobalActivity
|
||||||
|
(
|
||||||
|
long timestamp,
|
||||||
|
bool excludeNews,
|
||||||
|
bool excludeMyLevels,
|
||||||
|
bool excludeFriends,
|
||||||
|
bool excludeFavouriteUsers,
|
||||||
|
bool excludeMyself
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
if (token.GameVersion == GameVersion.LittleBigPlanet1) return this.BadRequest();
|
||||||
|
|
||||||
|
if (timestamp > TimeHelper.TimestampMillis || timestamp <= 0) timestamp = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
|
DateTime start = DateTimeExtensions.FromUnixTimeMilliseconds(timestamp);
|
||||||
|
|
||||||
|
DateTime soonestTime = await this.GetMostRecentEventTime(token, start);
|
||||||
|
Console.WriteLine(@"Most recent event occurred at " + soonestTime);
|
||||||
|
soonestTime = soonestTime.Subtract(TimeSpan.FromDays(1));
|
||||||
|
|
||||||
|
long soonestTimestamp = soonestTime.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
long endTimestamp = soonestTimestamp - 86_400_000;
|
||||||
|
|
||||||
|
Console.WriteLine(@$"soonestTime: {soonestTimestamp}, endTime: {endTimestamp}");
|
||||||
|
|
||||||
|
IQueryable<ActivityEntity> activityEvents = await this.GetFilters(token,
|
||||||
|
excludeNews,
|
||||||
|
excludeMyLevels,
|
||||||
|
excludeFriends,
|
||||||
|
excludeFavouriteUsers,
|
||||||
|
excludeMyself);
|
||||||
|
|
||||||
|
DateTime end = DateTimeExtensions.FromUnixTimeMilliseconds(endTimestamp);
|
||||||
|
|
||||||
|
activityEvents = activityEvents.Where(a => a.Timestamp < start && a.Timestamp > end);
|
||||||
|
|
||||||
|
Console.WriteLine($@"start: {start}, end: {end}");
|
||||||
|
|
||||||
|
List<IGrouping<ActivityGroup, ActivityEntity>> groups = await GroupActivities(activityEvents).ToListAsync();
|
||||||
|
|
||||||
|
foreach (IGrouping<ActivityGroup, ActivityEntity> group in groups)
|
||||||
|
{
|
||||||
|
ActivityGroup key = group.Key;
|
||||||
|
Console.WriteLine(
|
||||||
|
$@"{key.GroupType}: Timestamp: {key.Timestamp}, UserId: {key.UserId}, TargetSlotId: {key.TargetSlotId}, " +
|
||||||
|
@$"TargetUserId: {key.TargetUserId}, TargetPlaylistId: {key.TargetPlaylistId}");
|
||||||
|
foreach (ActivityEntity activity in group)
|
||||||
|
{
|
||||||
|
Console.WriteLine($@" {activity.Type}: Timestamp: {activity.Timestamp}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime oldestTime = groups.Any() ? groups.Min(g => g.Any() ? g.Min(a => a.Timestamp) : end) : end;
|
||||||
|
long oldestTimestamp = oldestTime.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
return this.Ok(await GameStream.CreateFromEntityResult(this.database, token, groups, timestamp, oldestTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("slot/{slotType}/{slotId:int}")]
|
||||||
|
public async Task<IActionResult> SlotActivity(string slotType, int slotId, long timestamp)
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
if (token.GameVersion == GameVersion.LittleBigPlanet1) return this.BadRequest();
|
||||||
|
|
||||||
|
if (timestamp > TimeHelper.TimestampMillis || timestamp <= 0) timestamp = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
|
long endTimestamp = timestamp - 864_000;
|
||||||
|
|
||||||
|
if (slotType is not ("developer" or "user")) return this.BadRequest();
|
||||||
|
|
||||||
|
if (slotType == "developer")
|
||||||
|
slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
||||||
|
|
||||||
|
IQueryable<ActivityDto> slotActivity = this.database.Activities.Select(ActivityToDto())
|
||||||
|
.Where(a => a.TargetSlotId == slotId);
|
||||||
|
|
||||||
|
DateTime start = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime;
|
||||||
|
DateTime end = DateTimeOffset.FromUnixTimeMilliseconds(endTimestamp).DateTime;
|
||||||
|
|
||||||
|
slotActivity = slotActivity.Where(a => a.Activity.Timestamp < start && a.Activity.Timestamp > end);
|
||||||
|
|
||||||
|
List<IGrouping<ActivityGroup, ActivityEntity>> groups = await GroupActivities(slotActivity).ToListAsync();
|
||||||
|
|
||||||
|
DateTime oldestTime = groups.Max(g => g.Max(a => a.Timestamp));
|
||||||
|
long oldestTimestamp = new DateTimeOffset(oldestTime).ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
return this.Ok(await GameStream.CreateFromEntityResult(this.database, token, groups, timestamp, oldestTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("user2/{userId:int}/")]
|
||||||
|
public async Task<IActionResult> UserActivity(int userId, long timestamp)
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
if (token.GameVersion == GameVersion.LittleBigPlanet1) return this.BadRequest();
|
||||||
|
|
||||||
|
if (timestamp > TimeHelper.TimestampMillis || timestamp <= 0) timestamp = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
|
long endTimestamp = timestamp - 864_000;
|
||||||
|
|
||||||
|
IQueryable<ActivityDto> userActivity = this.database.Activities.Select(ActivityToDto())
|
||||||
|
.Where(a => a.TargetUserId == userId);
|
||||||
|
|
||||||
|
DateTime start = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime;
|
||||||
|
DateTime end = DateTimeOffset.FromUnixTimeMilliseconds(endTimestamp).DateTime;
|
||||||
|
|
||||||
|
userActivity = userActivity.Where(a => a.Activity.Timestamp < start && a.Activity.Timestamp > end);
|
||||||
|
|
||||||
|
List<IGrouping<ActivityGroup, ActivityEntity>> groups = await GroupActivities(userActivity).ToListAsync();
|
||||||
|
|
||||||
|
DateTime oldestTime = groups.Max(g => g.Max(a => a.Timestamp));
|
||||||
|
long oldestTimestamp = new DateTimeOffset(oldestTime).ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
return this.Ok(
|
||||||
|
await GameStream.CreateFromEntityResult(this.database, token, groups, timestamp, oldestTimestamp));
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Comment;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -44,6 +44,20 @@ public class CommentController : ControllerBase
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("userComment/{username}")]
|
||||||
|
[HttpGet("comment/{slotType}/{slotId:int}")]
|
||||||
|
public async Task<IActionResult> GetSingleComment(string? username, string? slotType, int? slotId, int commentId)
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
if (username == null == (SlotHelper.IsTypeInvalid(slotType) || slotId == null)) return this.BadRequest();
|
||||||
|
|
||||||
|
CommentEntity? comment = await this.database.Comments.FindAsync(commentId);
|
||||||
|
if (comment == null) return this.NotFound();
|
||||||
|
|
||||||
|
return this.Ok(GameComment.CreateFromEntity(comment, token.UserId));
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("comments/{slotType}/{slotId:int}")]
|
[HttpGet("comments/{slotType}/{slotId:int}")]
|
||||||
[HttpGet("userComments/{username}")]
|
[HttpGet("userComments/{username}")]
|
||||||
public async Task<IActionResult> GetComments(string? username, string? slotType, int slotId)
|
public async Task<IActionResult> GetComments(string? username, string? slotType, int slotId)
|
||||||
|
|
|
@ -5,7 +5,7 @@ using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
||||||
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -12,7 +12,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Photo;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -13,6 +13,9 @@ using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -9,7 +9,9 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -4,7 +4,8 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -11,7 +11,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Resources;
|
using LBPUnion.ProjectLighthouse.Types.Resources;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -6,7 +6,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -8,7 +8,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Score;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -8,7 +8,7 @@ using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -13,7 +13,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -6,7 +6,7 @@ using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Filter;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
|
@ -7,7 +7,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
|
|
|
@ -5,6 +5,8 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
|
@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
|
@ -5,6 +5,8 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Levels
|
@using LBPUnion.ProjectLighthouse.Types.Levels
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Serialization
|
@using LBPUnion.ProjectLighthouse.Types.Serialization.Photo
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.PhotoEntity
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.PhotoEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Files
|
@using LBPUnion.ProjectLighthouse.Files
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers
|
@using LBPUnion.ProjectLighthouse.Helpers
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Serialization
|
@using LBPUnion.ProjectLighthouse.Types.Serialization.Review
|
||||||
|
|
||||||
@{
|
@{
|
||||||
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
||||||
|
|
|
@ -11,7 +11,7 @@ using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Integration;
|
using LBPUnion.ProjectLighthouse.Tests.Integration;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
@ -4,7 +4,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
|
@ -5,7 +5,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests.Unit;
|
namespace LBPUnion.ProjectLighthouse.Tests.Unit;
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
140
ProjectLighthouse/Database/ActivityInterceptor.cs
Normal file
140
ProjectLighthouse/Database/ActivityInterceptor.cs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Database;
|
||||||
|
|
||||||
|
public class ActivityInterceptor : SaveChangesInterceptor
|
||||||
|
{
|
||||||
|
private class CustomTrackedEntity
|
||||||
|
{
|
||||||
|
public required EntityState State { get; init; }
|
||||||
|
public required object Entity { get; init; }
|
||||||
|
public required object OldEntity { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<(Type Type, int HashCode), CustomTrackedEntity> unsavedEntities;
|
||||||
|
private readonly IEntityEventHandler eventHandler;
|
||||||
|
|
||||||
|
public ActivityInterceptor(IEntityEventHandler eventHandler)
|
||||||
|
{
|
||||||
|
this.eventHandler = eventHandler;
|
||||||
|
this.unsavedEntities = new ConcurrentDictionary<(Type Type, int HashCode), CustomTrackedEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Hooking stuff
|
||||||
|
|
||||||
|
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
|
||||||
|
{
|
||||||
|
this.SaveNewEntities(eventData);
|
||||||
|
return base.SavingChanges(eventData, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValueTask<InterceptionResult<int>> SavingChangesAsync
|
||||||
|
(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = new())
|
||||||
|
{
|
||||||
|
this.SaveNewEntities(eventData);
|
||||||
|
return base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SavedChanges(SaveChangesCompletedEventData eventData, int result)
|
||||||
|
{
|
||||||
|
this.ParseInsertedEntities(eventData);
|
||||||
|
return base.SavedChanges(eventData, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValueTask<int> SavedChangesAsync
|
||||||
|
(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = new())
|
||||||
|
{
|
||||||
|
this.ParseInsertedEntities(eventData);
|
||||||
|
return base.SavedChangesAsync(eventData, result, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void SaveNewEntities(DbContextEventData eventData)
|
||||||
|
{
|
||||||
|
if (eventData.Context == null) return;
|
||||||
|
|
||||||
|
DbContext context = eventData.Context;
|
||||||
|
|
||||||
|
this.unsavedEntities.Clear();
|
||||||
|
|
||||||
|
foreach (EntityEntry entry in context.ChangeTracker.Entries())
|
||||||
|
{
|
||||||
|
// Ignore activities
|
||||||
|
if (entry.Metadata.BaseType?.ClrType == typeof(ActivityEntity) || entry.Metadata.ClrType == typeof(LastContactEntity)) continue;
|
||||||
|
|
||||||
|
// Ignore tokens
|
||||||
|
if (entry.Metadata.Name.Contains("Token")) continue;
|
||||||
|
|
||||||
|
if (entry.State is not (EntityState.Added or EntityState.Deleted or EntityState.Modified)) continue;
|
||||||
|
|
||||||
|
this.unsavedEntities.TryAdd((entry.Entity.GetType(), entry.Entity.GetHashCode()),
|
||||||
|
new CustomTrackedEntity
|
||||||
|
{
|
||||||
|
State = entry.State,
|
||||||
|
Entity = entry.Entity,
|
||||||
|
OldEntity = entry.OriginalValues.ToObject(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseInsertedEntities(DbContextEventData eventData)
|
||||||
|
{
|
||||||
|
if (eventData.Context is not DatabaseContext context) return;
|
||||||
|
|
||||||
|
HashSet<CustomTrackedEntity> entities = new();
|
||||||
|
|
||||||
|
List<EntityEntry> entries = context.ChangeTracker.Entries().ToList();
|
||||||
|
|
||||||
|
foreach (KeyValuePair<(Type Type, int HashCode), CustomTrackedEntity> kvp in this.unsavedEntities)
|
||||||
|
{
|
||||||
|
EntityEntry entry = entries.FirstOrDefault(e =>
|
||||||
|
e.Metadata.ClrType == kvp.Key.Type && e.Entity.GetHashCode() == kvp.Key.HashCode);
|
||||||
|
switch (kvp.Value.State)
|
||||||
|
{
|
||||||
|
case EntityState.Added:
|
||||||
|
case EntityState.Modified:
|
||||||
|
if (entry != null) entities.Add(kvp.Value);
|
||||||
|
break;
|
||||||
|
case EntityState.Deleted:
|
||||||
|
if (entry == null) entities.Add(kvp.Value);
|
||||||
|
break;
|
||||||
|
case EntityState.Detached:
|
||||||
|
case EntityState.Unchanged:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (CustomTrackedEntity entity in entities)
|
||||||
|
{
|
||||||
|
switch (entity.State)
|
||||||
|
{
|
||||||
|
case EntityState.Added:
|
||||||
|
this.eventHandler.OnEntityInserted(context, entity.Entity);
|
||||||
|
break;
|
||||||
|
case EntityState.Deleted:
|
||||||
|
this.eventHandler.OnEntityDeleted(context, entity.Entity);
|
||||||
|
break;
|
||||||
|
case EntityState.Modified:
|
||||||
|
this.eventHandler.OnEntityChanged(context, entity.OldEntity, entity.Entity);
|
||||||
|
break;
|
||||||
|
case EntityState.Detached:
|
||||||
|
case EntityState.Unchanged:
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
@ -86,16 +87,6 @@ public partial class DatabaseContext : DbContext
|
||||||
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
|
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<LevelActivityEntity>().UseTpcMappingStrategy();
|
|
||||||
modelBuilder.Entity<PhotoActivityEntity>().UseTpcMappingStrategy();
|
|
||||||
modelBuilder.Entity<PlaylistActivityEntity>().UseTpcMappingStrategy();
|
|
||||||
modelBuilder.Entity<ScoreActivityEntity>().UseTpcMappingStrategy();
|
|
||||||
modelBuilder.Entity<UserActivityEntity>().UseTpcMappingStrategy();
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DatabaseContext CreateNewInstance()
|
public static DatabaseContext CreateNewInstance()
|
||||||
{
|
{
|
||||||
DbContextOptionsBuilder<DatabaseContext> builder = new();
|
DbContextOptionsBuilder<DatabaseContext> builder = new();
|
||||||
|
@ -103,4 +94,26 @@ public partial class DatabaseContext : DbContext
|
||||||
MySqlServerVersion.LatestSupportedServerVersion);
|
MySqlServerVersion.LatestSupportedServerVersion);
|
||||||
return new DatabaseContext(builder.Options);
|
return new DatabaseContext(builder.Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Activity
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
//TODO implement reviews
|
||||||
|
modelBuilder.Entity<LevelActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<PhotoActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<PlaylistActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<ScoreActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<UserActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<NewsActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<CommentActivityEntity>().UseTphMappingStrategy();
|
||||||
|
modelBuilder.Entity<UserActivityEntity>().UseTphMappingStrategy();
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
optionsBuilder.AddInterceptors(new ActivityInterceptor(new ActivityEntityEventHandler()));
|
||||||
|
base.OnConfiguring(optionsBuilder);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
12
ProjectLighthouse/Extensions/DateTimeExtensions.cs
Normal file
12
ProjectLighthouse/Extensions/DateTimeExtensions.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
|
||||||
|
public static class DateTimeExtensions
|
||||||
|
{
|
||||||
|
public static long ToUnixTimeMilliseconds(this DateTime dateTime) =>
|
||||||
|
new DateTimeOffset(dateTime).ToUniversalTime().ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
public static DateTime FromUnixTimeMilliseconds(long timestamp) =>
|
||||||
|
DateTimeOffset.FromUnixTimeMilliseconds(timestamp).ToUniversalTime().DateTime;
|
||||||
|
}
|
179
ProjectLighthouse/Types/Activity/ActivityEntityEventHandler.cs
Normal file
179
ProjectLighthouse/Types/Activity/ActivityEntityEventHandler.cs
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
|
||||||
|
//TODO implement missing event triggers
|
||||||
|
public class ActivityEntityEventHandler : IEntityEventHandler
|
||||||
|
{
|
||||||
|
public void OnEntityInserted<T>(DatabaseContext database, T entity) where T : class
|
||||||
|
{
|
||||||
|
Console.WriteLine($@"OnEntityInserted: {entity.GetType().Name}");
|
||||||
|
ActivityEntity? activity = entity switch
|
||||||
|
{
|
||||||
|
SlotEntity slot => new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.PublishLevel,
|
||||||
|
SlotId = slot.SlotId,
|
||||||
|
UserId = slot.CreatorId,
|
||||||
|
},
|
||||||
|
CommentEntity comment => new CommentActivityEntity
|
||||||
|
{
|
||||||
|
Type = comment.Type == CommentType.Level ? EventType.CommentOnLevel : EventType.CommentOnUser,
|
||||||
|
CommentId = comment.CommentId,
|
||||||
|
UserId = comment.PosterUserId,
|
||||||
|
},
|
||||||
|
PhotoEntity photo => new PhotoActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.UploadPhoto,
|
||||||
|
PhotoId = photo.PhotoId,
|
||||||
|
UserId = photo.CreatorId,
|
||||||
|
},
|
||||||
|
ScoreEntity score => new ScoreActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.Score,
|
||||||
|
ScoreId = score.ScoreId,
|
||||||
|
//TODO merge score migration
|
||||||
|
// UserId = int.Parse(score.PlayerIds[0]),
|
||||||
|
},
|
||||||
|
HeartedLevelEntity heartedLevel => new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.HeartLevel,
|
||||||
|
SlotId = heartedLevel.SlotId,
|
||||||
|
UserId = heartedLevel.UserId,
|
||||||
|
},
|
||||||
|
HeartedProfileEntity heartedProfile => new UserActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.HeartUser,
|
||||||
|
TargetUserId = heartedProfile.HeartedUserId,
|
||||||
|
UserId = heartedProfile.UserId,
|
||||||
|
},
|
||||||
|
VisitedLevelEntity visitedLevel => new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.PlayLevel,
|
||||||
|
SlotId = visitedLevel.SlotId,
|
||||||
|
UserId = visitedLevel.UserId,
|
||||||
|
},
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
InsertActivity(database, activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InsertActivity(DatabaseContext database, ActivityEntity? activity)
|
||||||
|
{
|
||||||
|
if (activity == null) return;
|
||||||
|
|
||||||
|
Console.WriteLine("Inserting activity: " + activity.GetType().Name);
|
||||||
|
|
||||||
|
activity.Timestamp = DateTime.UtcNow;
|
||||||
|
database.Activities.Add(activity);
|
||||||
|
database.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEntityChanged<T>(DatabaseContext database, T origEntity, T currentEntity) where T : class
|
||||||
|
{
|
||||||
|
foreach (PropertyInfo propInfo in currentEntity.GetType().GetProperties())
|
||||||
|
{
|
||||||
|
if (!propInfo.CanRead || !propInfo.CanWrite) continue;
|
||||||
|
|
||||||
|
if (propInfo.CustomAttributes.Any(c => c.AttributeType == typeof(NotMappedAttribute))) continue;
|
||||||
|
|
||||||
|
object? origVal = propInfo.GetValue(origEntity);
|
||||||
|
object? newVal = propInfo.GetValue(currentEntity);
|
||||||
|
if ((origVal == null && newVal == null) || (origVal != null && newVal != null && origVal.Equals(newVal)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Console.WriteLine($@"Value for {propInfo.Name} changed");
|
||||||
|
Console.WriteLine($@"Orig val: {origVal?.ToString() ?? "null"}");
|
||||||
|
Console.WriteLine($@"New val: {newVal?.ToString() ?? "null"}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($@"OnEntityChanged: {currentEntity.GetType().Name}");
|
||||||
|
ActivityEntity? activity = null;
|
||||||
|
switch (currentEntity)
|
||||||
|
{
|
||||||
|
case VisitedLevelEntity visitedLevel:
|
||||||
|
{
|
||||||
|
if (origEntity is not VisitedLevelEntity) break;
|
||||||
|
|
||||||
|
activity = new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.PlayLevel,
|
||||||
|
SlotId = visitedLevel.SlotId,
|
||||||
|
UserId = visitedLevel.UserId,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SlotEntity slotEntity:
|
||||||
|
{
|
||||||
|
if (origEntity is not SlotEntity oldSlotEntity) break;
|
||||||
|
|
||||||
|
if (!oldSlotEntity.TeamPick && slotEntity.TeamPick)
|
||||||
|
{
|
||||||
|
activity = new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.MMPickLevel,
|
||||||
|
SlotId = slotEntity.SlotId,
|
||||||
|
UserId = SlotHelper.GetPlaceholderUserId(database).Result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (oldSlotEntity.SlotId == slotEntity.SlotId && slotEntity.Type == SlotType.User)
|
||||||
|
{
|
||||||
|
activity = new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.PublishLevel,
|
||||||
|
SlotId = slotEntity.SlotId,
|
||||||
|
UserId = slotEntity.CreatorId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertActivity(database, activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEntityDeleted<T>(DatabaseContext database, T entity) where T : class
|
||||||
|
{
|
||||||
|
Console.WriteLine($@"OnEntityDeleted: {entity.GetType().Name}");
|
||||||
|
ActivityEntity? activity = entity switch
|
||||||
|
{
|
||||||
|
//TODO move this to EntityModified and use CommentEntity.Deleted
|
||||||
|
CommentEntity comment => comment.Type switch
|
||||||
|
{
|
||||||
|
CommentType.Level => new CommentActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.DeleteLevelComment,
|
||||||
|
CommentId = comment.CommentId,
|
||||||
|
UserId = comment.PosterUserId,
|
||||||
|
},
|
||||||
|
_ => null,
|
||||||
|
},
|
||||||
|
HeartedLevelEntity heartedLevel => new LevelActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.UnheartLevel,
|
||||||
|
SlotId = heartedLevel.SlotId,
|
||||||
|
UserId = heartedLevel.UserId,
|
||||||
|
},
|
||||||
|
HeartedProfileEntity heartedProfile => new UserActivityEntity
|
||||||
|
{
|
||||||
|
Type = EventType.UnheartUser,
|
||||||
|
TargetUserId = heartedProfile.HeartedUserId,
|
||||||
|
UserId = heartedProfile.UserId,
|
||||||
|
},
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
InsertActivity(database, activity);
|
||||||
|
}
|
||||||
|
}
|
41
ProjectLighthouse/Types/Activity/ActivityGroup.cs
Normal file
41
ProjectLighthouse/Types/Activity/ActivityGroup.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
|
||||||
|
public class ActivityGroup
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public int UserId { get; set; }
|
||||||
|
public int? TargetSlotId { get; set; }
|
||||||
|
public int? TargetUserId { get; set; }
|
||||||
|
public int? TargetPlaylistId { get; set; }
|
||||||
|
|
||||||
|
public int TargetId =>
|
||||||
|
this.GroupType switch
|
||||||
|
{
|
||||||
|
ActivityGroupType.User => this.TargetUserId ?? 0,
|
||||||
|
ActivityGroupType.Level => this.TargetSlotId ?? 0,
|
||||||
|
ActivityGroupType.Playlist => this.TargetPlaylistId ?? 0,
|
||||||
|
_ => this.UserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
public ActivityGroupType GroupType =>
|
||||||
|
this.TargetSlotId != 0
|
||||||
|
? ActivityGroupType.Level
|
||||||
|
: this.TargetUserId != 0
|
||||||
|
? ActivityGroupType.User
|
||||||
|
: ActivityGroupType.Playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ActivityGroupType
|
||||||
|
{
|
||||||
|
[XmlEnum("user")]
|
||||||
|
User,
|
||||||
|
|
||||||
|
[XmlEnum("slot")]
|
||||||
|
Level,
|
||||||
|
|
||||||
|
[XmlEnum("playlist")]
|
||||||
|
Playlist,
|
||||||
|
}
|
|
@ -1,26 +1,69 @@
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Activity;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
|
||||||
public enum EventType
|
public enum EventType
|
||||||
{
|
{
|
||||||
|
[XmlEnum("heart_level")]
|
||||||
HeartLevel,
|
HeartLevel,
|
||||||
|
|
||||||
|
[XmlEnum("unheart_level")]
|
||||||
UnheartLevel,
|
UnheartLevel,
|
||||||
|
|
||||||
|
[XmlEnum("heart_user")]
|
||||||
HeartUser,
|
HeartUser,
|
||||||
|
|
||||||
|
[XmlEnum("unheart_user")]
|
||||||
UnheartUser,
|
UnheartUser,
|
||||||
|
|
||||||
|
[XmlEnum("play_level")]
|
||||||
PlayLevel,
|
PlayLevel,
|
||||||
|
|
||||||
|
[XmlEnum("rate_level")]
|
||||||
RateLevel,
|
RateLevel,
|
||||||
|
|
||||||
|
[XmlEnum("tag_level")]
|
||||||
TagLevel,
|
TagLevel,
|
||||||
|
|
||||||
|
[XmlEnum("comment_on_level")]
|
||||||
CommentOnLevel,
|
CommentOnLevel,
|
||||||
|
|
||||||
|
[XmlEnum("delete_level_comment")]
|
||||||
DeleteLevelComment,
|
DeleteLevelComment,
|
||||||
|
|
||||||
|
[XmlEnum("upload_photo")]
|
||||||
UploadPhoto,
|
UploadPhoto,
|
||||||
|
|
||||||
|
[XmlEnum("publish_level")]
|
||||||
PublishLevel,
|
PublishLevel,
|
||||||
|
|
||||||
|
[XmlEnum("unpublish_level")]
|
||||||
UnpublishLevel,
|
UnpublishLevel,
|
||||||
|
|
||||||
|
[XmlEnum("score")]
|
||||||
Score,
|
Score,
|
||||||
|
|
||||||
|
[XmlEnum("news_post")]
|
||||||
NewsPost,
|
NewsPost,
|
||||||
|
|
||||||
|
[XmlEnum("mm_pick_level")]
|
||||||
MMPickLevel,
|
MMPickLevel,
|
||||||
|
|
||||||
|
[XmlEnum("dpad_rate_level")]
|
||||||
DpadRateLevel,
|
DpadRateLevel,
|
||||||
|
|
||||||
|
[XmlEnum("review_level")]
|
||||||
ReviewLevel,
|
ReviewLevel,
|
||||||
|
|
||||||
|
[XmlEnum("comment_on_user")]
|
||||||
CommentOnUser,
|
CommentOnUser,
|
||||||
|
|
||||||
|
[XmlEnum("create_playlist")]
|
||||||
CreatePlaylist,
|
CreatePlaylist,
|
||||||
|
|
||||||
|
[XmlEnum("heart_playlist")]
|
||||||
HeartPlaylist,
|
HeartPlaylist,
|
||||||
|
|
||||||
|
[XmlEnum("add_level_to_playlist")]
|
||||||
AddLevelToPlaylist,
|
AddLevelToPlaylist,
|
||||||
}
|
}
|
10
ProjectLighthouse/Types/Activity/IEntityEventHandler.cs
Normal file
10
ProjectLighthouse/Types/Activity/IEntityEventHandler.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
|
||||||
|
public interface IEntityEventHandler
|
||||||
|
{
|
||||||
|
public void OnEntityInserted<T>(DatabaseContext database, T entity) where T : class;
|
||||||
|
public void OnEntityChanged<T>(DatabaseContext database, T origEntity, T currentEntity) where T : class;
|
||||||
|
public void OnEntityDeleted<T>(DatabaseContext database, T entity) where T : class;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Activity;
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
@ -10,7 +11,7 @@ public class ActivityEntity
|
||||||
[Key]
|
[Key]
|
||||||
public int ActivityId { get; set; }
|
public int ActivityId { get; set; }
|
||||||
|
|
||||||
public long Timestamp { get; set; }
|
public DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
public int UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supported event types: CommentOnUser, CommentOnLevel, DeleteLevelComment
|
||||||
|
/// </summary>
|
||||||
|
public class CommentActivityEntity : ActivityEntity
|
||||||
|
{
|
||||||
|
public int CommentId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(CommentId))]
|
||||||
|
public CommentEntity Comment { get; set; }
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Supported event types: CommentOnUser, CommentOnLevel, DeleteLevelComment
|
|
||||||
/// </summary>
|
|
||||||
public class CommentActivityEntry
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,6 +3,9 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supported event types: CreatePlaylist, HeartPlaylist, AddLevelToPlaylist
|
||||||
|
/// </summary>
|
||||||
public class PlaylistActivityEntity : ActivityEntity
|
public class PlaylistActivityEntity : ActivityEntity
|
||||||
{
|
{
|
||||||
public int PlaylistId { get; set; }
|
public int PlaylistId { get; set; }
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
|
||||||
|
public class ReviewActivityEntity : ActivityEntity
|
||||||
|
{
|
||||||
|
public int ReviewId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(ReviewId))]
|
||||||
|
public ReviewEntity Review { get; set; }
|
||||||
|
|
||||||
|
// TODO review_modified?
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Supported event types: HeartUser, UnheartUser
|
/// Supported event types: HeartUser, UnheartUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserActivityEntity : ActivityEntity
|
public class UserActivityEntity : ActivityEntity
|
||||||
{
|
{
|
||||||
|
public int TargetUserId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(TargetUserId))]
|
||||||
|
public UserEntity TargetUser { get; set; }
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@ using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
namespace LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Filter;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Levels;
|
namespace LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
[XmlInclude(typeof(GameUserCommentEvent))]
|
||||||
|
[XmlInclude(typeof(GameSlotCommentEvent))]
|
||||||
|
public class GameCommentEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("comment_id")]
|
||||||
|
public int CommentId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameUserCommentEvent : GameCommentEvent
|
||||||
|
{
|
||||||
|
[XmlElement("object_user")]
|
||||||
|
public string TargetUsername { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
CommentEntity comment = await database.Comments.FindAsync(this.CommentId);
|
||||||
|
if (comment == null) return;
|
||||||
|
|
||||||
|
UserEntity user = await database.Users.FindAsync(comment.TargetId);
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
this.TargetUsername = user.Username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameSlotCommentEvent : GameCommentEvent
|
||||||
|
{
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
public ReviewSlot TargetSlot { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
CommentEntity comment = await database.Comments.FindAsync(this.CommentId);
|
||||||
|
if (comment == null) return;
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(comment.TargetId);
|
||||||
|
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.TargetSlot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
[XmlInclude(typeof(GameCommentEvent))]
|
||||||
|
[XmlInclude(typeof(GamePhotoUploadEvent))]
|
||||||
|
[XmlInclude(typeof(GamePlayLevelEvent))]
|
||||||
|
[XmlInclude(typeof(GameReviewEvent))]
|
||||||
|
[XmlInclude(typeof(GameScoreEvent))]
|
||||||
|
[XmlInclude(typeof(GameHeartLevelEvent))]
|
||||||
|
[XmlInclude(typeof(GameHeartUserEvent))]
|
||||||
|
public class GameEvent : ILbpSerializable, INeedsPreparationForSerialization
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
private int UserId { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("type")]
|
||||||
|
public EventType Type { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("timestamp")]
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("actor")]
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
protected async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
Console.WriteLine($@"SERIALIZATION!! {this.UserId} - {this.GetHashCode()}");
|
||||||
|
UserEntity user = await database.Users.FindAsync(this.UserId);
|
||||||
|
if (user == null) return;
|
||||||
|
this.Username = user.Username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<GameEvent> CreateFromActivityGroups(IGrouping<EventType, ActivityEntity> group)
|
||||||
|
{
|
||||||
|
List<GameEvent> events = new();
|
||||||
|
|
||||||
|
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
|
||||||
|
// Events with Count need special treatment
|
||||||
|
switch (group.Key)
|
||||||
|
{
|
||||||
|
case EventType.PlayLevel:
|
||||||
|
{
|
||||||
|
if (group.First() is not LevelActivityEntity levelActivity) break;
|
||||||
|
|
||||||
|
events.Add(new GamePlayLevelEvent
|
||||||
|
{
|
||||||
|
Slot = new ReviewSlot
|
||||||
|
{
|
||||||
|
SlotId = levelActivity.SlotId,
|
||||||
|
},
|
||||||
|
Count = group.Count(),
|
||||||
|
UserId = levelActivity.UserId,
|
||||||
|
Timestamp = levelActivity.Timestamp.ToUnixTimeMilliseconds(),
|
||||||
|
Type = levelActivity.Type,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EventType.PublishLevel:
|
||||||
|
{
|
||||||
|
if (group.First() is not LevelActivityEntity levelActivity) break;
|
||||||
|
|
||||||
|
events.Add(new GamePublishLevelEvent
|
||||||
|
{
|
||||||
|
Slot = new ReviewSlot
|
||||||
|
{
|
||||||
|
SlotId = levelActivity.SlotId,
|
||||||
|
},
|
||||||
|
Count = group.Count(),
|
||||||
|
UserId = levelActivity.UserId,
|
||||||
|
Timestamp = levelActivity.Timestamp.ToUnixTimeMilliseconds(),
|
||||||
|
Type = levelActivity.Type,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Everything else can be handled as normal
|
||||||
|
default: events.AddRange(group.Select(CreateFromActivity));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return events.AsEnumerable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameEvent CreateFromActivity(ActivityEntity activity)
|
||||||
|
{
|
||||||
|
GameEvent gameEvent = activity.Type switch
|
||||||
|
{
|
||||||
|
EventType.PlayLevel => new GamePlayLevelEvent
|
||||||
|
{
|
||||||
|
Slot = new ReviewSlot
|
||||||
|
{
|
||||||
|
SlotId = ((LevelActivityEntity)activity).SlotId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EventType.CommentOnLevel => new GameSlotCommentEvent
|
||||||
|
{
|
||||||
|
CommentId = ((CommentActivityEntity)activity).CommentId,
|
||||||
|
},
|
||||||
|
EventType.CommentOnUser => new GameUserCommentEvent
|
||||||
|
{
|
||||||
|
CommentId = ((CommentActivityEntity)activity).CommentId,
|
||||||
|
},
|
||||||
|
EventType.HeartUser or EventType.UnheartUser => new GameHeartUserEvent
|
||||||
|
{
|
||||||
|
TargetUserId = ((UserActivityEntity)activity).TargetUserId,
|
||||||
|
},
|
||||||
|
EventType.HeartLevel or EventType.UnheartLevel => new GameHeartLevelEvent
|
||||||
|
{
|
||||||
|
TargetSlot = new ReviewSlot
|
||||||
|
{
|
||||||
|
SlotId = ((LevelActivityEntity)activity).SlotId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => new GameEvent(),
|
||||||
|
};
|
||||||
|
gameEvent.UserId = activity.UserId;
|
||||||
|
gameEvent.Type = activity.Type;
|
||||||
|
gameEvent.Timestamp = activity.Timestamp.ToUnixTimeMilliseconds();
|
||||||
|
return gameEvent;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GameHeartUserEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
public int TargetUserId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("object_user")]
|
||||||
|
public string TargetUsername { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
UserEntity targetUser = await database.Users.FindAsync(this.TargetUserId);
|
||||||
|
if (targetUser == null) return;
|
||||||
|
|
||||||
|
this.TargetUsername = targetUser.Username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameHeartLevelEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
public ReviewSlot TargetSlot { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(this.TargetSlot.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.TargetSlot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GamePhotoUploadEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("photo_id")]
|
||||||
|
public int PhotoId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
[DefaultValue(null)]
|
||||||
|
public ReviewSlot SlotId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("user_in_photo")]
|
||||||
|
public List<string> PhotoParticipants { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
PhotoEntity photo = await database.Photos.Where(p => p.PhotoId == this.PhotoId)
|
||||||
|
.Include(p => p.PhotoSubjects)
|
||||||
|
.ThenInclude(ps => ps.User)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (photo == null) return;
|
||||||
|
|
||||||
|
this.PhotoParticipants = photo.PhotoSubjects.Select(ps => ps.User.Username).ToList();
|
||||||
|
|
||||||
|
if (photo.SlotId == null) return;
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(photo.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.SlotId = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GamePlayLevelEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
public ReviewSlot Slot { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("count")]
|
||||||
|
public int Count { get; set; } = 1;
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(this.Slot.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.Slot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GamePublishLevelEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
public ReviewSlot Slot { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("republish")]
|
||||||
|
public bool IsRepublish { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("count")]
|
||||||
|
public int Count { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(this.Slot.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.Slot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
// TODO does this work?
|
||||||
|
this.IsRepublish = slot.LastUpdated == slot.FirstUploaded;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GameReviewEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlElement("slot_id")]
|
||||||
|
public ReviewSlot Slot { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("review_id")]
|
||||||
|
public int ReviewId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("review_modified")]
|
||||||
|
[DefaultValue(0)]
|
||||||
|
public long ReviewTimestamp { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
ReviewEntity review = await database.Reviews.FindAsync(this.ReviewId);
|
||||||
|
if (review == null) return;
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(review.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.Slot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
|
||||||
|
public class GameScoreEvent : GameEvent
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
public int ScoreId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("object_slot_id")]
|
||||||
|
public ReviewSlot Slot { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("score")]
|
||||||
|
public int Score { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("user_count")]
|
||||||
|
public int UserCount { get; set; }
|
||||||
|
|
||||||
|
public new async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
await base.PrepareSerialization(database);
|
||||||
|
|
||||||
|
ScoreEntity score = await database.Scores.FindAsync(this.ScoreId);
|
||||||
|
if (score == null) return;
|
||||||
|
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(score.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.Score = score.Points;
|
||||||
|
//TODO is this correct?
|
||||||
|
this.UserCount = score.Type;
|
||||||
|
|
||||||
|
this.Slot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity;
|
||||||
|
|
||||||
|
public class GameSlotStreamGroup : GameStreamGroup, INeedsPreparationForSerialization
|
||||||
|
{
|
||||||
|
[XmlElement("slot_id")]
|
||||||
|
public ReviewSlot Slot { get; set; }
|
||||||
|
|
||||||
|
public async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(this.Slot.SlotId);
|
||||||
|
if (slot == null) return;
|
||||||
|
|
||||||
|
this.Slot = ReviewSlot.CreateFromEntity(slot);
|
||||||
|
}
|
||||||
|
}
|
127
ProjectLighthouse/Types/Serialization/Activity/GameStream.cs
Normal file
127
ProjectLighthouse/Types/Serialization/Activity/GameStream.cs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The global stream object, contains all
|
||||||
|
/// </summary>
|
||||||
|
[XmlRoot("stream")]
|
||||||
|
public class GameStream : ILbpSerializable, INeedsPreparationForSerialization
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
private List<int> SlotIds { get; set; }
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
private List<int> UserIds { get; set; }
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
private int TargetUserId { get; set; }
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
private GameVersion TargetGame { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("start_timestamp")]
|
||||||
|
public long StartTimestamp { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("end_timestamp")]
|
||||||
|
public long EndTimestamp { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("groups")]
|
||||||
|
[XmlArrayItem("group")]
|
||||||
|
public List<GameStreamGroup> Groups { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("slots")]
|
||||||
|
[XmlArrayItem("slot")]
|
||||||
|
public List<SlotBase> Slots { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("users")]
|
||||||
|
[XmlArrayItem("user")]
|
||||||
|
public List<GameUser> Users { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("news")]
|
||||||
|
[XmlArrayItem("item")]
|
||||||
|
public List<object> News { get; set; }
|
||||||
|
//TODO implement lbp1 and lbp2 news objects
|
||||||
|
|
||||||
|
public async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
if (this.SlotIds.Count > 0)
|
||||||
|
{
|
||||||
|
this.Slots = new List<SlotBase>();
|
||||||
|
foreach (int slotId in this.SlotIds)
|
||||||
|
{
|
||||||
|
SlotEntity slot = await database.Slots.FindAsync(slotId);
|
||||||
|
if (slot == null) continue;
|
||||||
|
|
||||||
|
this.Slots.Add(SlotBase.CreateFromEntity(slot, this.TargetGame, this.TargetUserId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.UserIds.Count > 0)
|
||||||
|
{
|
||||||
|
this.Users = new List<GameUser>();
|
||||||
|
foreach (int userId in this.UserIds)
|
||||||
|
{
|
||||||
|
UserEntity user = await database.Users.FindAsync(userId);
|
||||||
|
if (user == null) continue;
|
||||||
|
|
||||||
|
this.Users.Add(GameUser.CreateFromEntity(user, this.TargetGame));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<GameStream> CreateFromEntityResult
|
||||||
|
(
|
||||||
|
DatabaseContext database,
|
||||||
|
GameTokenEntity token,
|
||||||
|
List<IGrouping<ActivityGroup, ActivityEntity>> results,
|
||||||
|
long startTimestamp,
|
||||||
|
long endTimestamp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<int> slotIds = results.Where(g => g.Key.TargetSlotId != null && g.Key.TargetSlotId.Value != 0)
|
||||||
|
.Select(g => g.Key.TargetSlotId.Value)
|
||||||
|
.ToList();
|
||||||
|
Console.WriteLine($@"slotIds: {string.Join(",", slotIds)}");
|
||||||
|
List<int> userIds = results.Where(g => g.Key.TargetUserId != null && g.Key.TargetUserId.Value != 0)
|
||||||
|
.Select(g => g.Key.TargetUserId.Value)
|
||||||
|
.Distinct()
|
||||||
|
.Union(results.Select(g => g.Key.UserId))
|
||||||
|
.ToList();
|
||||||
|
// Cache target levels and users within DbContext
|
||||||
|
await database.Slots.Where(s => slotIds.Contains(s.SlotId)).LoadAsync();
|
||||||
|
await database.Users.Where(u => userIds.Contains(u.UserId)).LoadAsync();
|
||||||
|
Console.WriteLine($@"userIds: {string.Join(",", userIds)}");
|
||||||
|
Console.WriteLine($@"Stream contains {slotIds.Count} slots and {userIds.Count} users");
|
||||||
|
GameStream gameStream = new()
|
||||||
|
{
|
||||||
|
TargetUserId = token.UserId,
|
||||||
|
TargetGame = token.GameVersion,
|
||||||
|
StartTimestamp = startTimestamp,
|
||||||
|
EndTimestamp = endTimestamp,
|
||||||
|
SlotIds = slotIds,
|
||||||
|
UserIds = userIds,
|
||||||
|
Groups = new List<GameStreamGroup>(),
|
||||||
|
};
|
||||||
|
foreach (IGrouping<ActivityGroup, ActivityEntity> group in results)
|
||||||
|
{
|
||||||
|
gameStream.Groups.Add(GameStreamGroup.CreateFromGrouping(group));
|
||||||
|
}
|
||||||
|
|
||||||
|
return gameStream;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Activity.Events;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Top level groups generally contain all events for a given level or user
|
||||||
|
/// <para>
|
||||||
|
/// The sub-groups are always <see cref="GameUserStreamGroup"/> and contain all activities from a single user
|
||||||
|
/// for the top level group entity
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
[XmlInclude(typeof(GameUserStreamGroup))]
|
||||||
|
[XmlInclude(typeof(GameSlotStreamGroup))]
|
||||||
|
public class GameStreamGroup : ILbpSerializable
|
||||||
|
{
|
||||||
|
[XmlAttribute("type")]
|
||||||
|
public ActivityGroupType Type { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("timestamp")]
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("subgroups")]
|
||||||
|
[XmlArrayItem("group")]
|
||||||
|
[DefaultValue(null)]
|
||||||
|
public List<GameStreamGroup> Groups { get; set; }
|
||||||
|
|
||||||
|
[XmlArray("events")]
|
||||||
|
[XmlArrayItem("event")]
|
||||||
|
[DefaultValue(null)]
|
||||||
|
public List<GameEvent> Events { get; set; }
|
||||||
|
|
||||||
|
public static GameStreamGroup CreateFromGrouping(IGrouping<ActivityGroup, ActivityEntity> group)
|
||||||
|
{
|
||||||
|
ActivityGroupType type = group.Key.GroupType;
|
||||||
|
GameStreamGroup gameGroup = type switch
|
||||||
|
{
|
||||||
|
ActivityGroupType.Level => new GameSlotStreamGroup
|
||||||
|
{
|
||||||
|
Slot = new ReviewSlot
|
||||||
|
{
|
||||||
|
SlotId = group.Key.TargetId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ActivityGroupType.User => new GameUserStreamGroup
|
||||||
|
{
|
||||||
|
UserId = group.Key.TargetId,
|
||||||
|
},
|
||||||
|
_ => new GameStreamGroup(),
|
||||||
|
};
|
||||||
|
gameGroup.Timestamp = new DateTimeOffset(group.Select(a => a.Timestamp).MaxBy(a => a)).ToUnixTimeMilliseconds();
|
||||||
|
gameGroup.Type = type;
|
||||||
|
|
||||||
|
List<IGrouping<EventType, ActivityEntity>> eventGroups = group.OrderByDescending(a => a.Timestamp).GroupBy(g => g.Type).ToList();
|
||||||
|
//TODO removeme debug
|
||||||
|
foreach (IGrouping<EventType, ActivityEntity> bruh in eventGroups)
|
||||||
|
{
|
||||||
|
Console.WriteLine($@"group key: {bruh.Key}, count={bruh.Count()}");
|
||||||
|
}
|
||||||
|
gameGroup.Groups = new List<GameStreamGroup>
|
||||||
|
{
|
||||||
|
new GameUserStreamGroup
|
||||||
|
{
|
||||||
|
UserId = group.Key.UserId,
|
||||||
|
Type = ActivityGroupType.User,
|
||||||
|
Timestamp = gameGroup.Timestamp,
|
||||||
|
Events = eventGroups.SelectMany(GameEvent.CreateFromActivityGroups).ToList(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return gameGroup;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Activity;
|
||||||
|
|
||||||
|
public class GameUserStreamGroup : GameStreamGroup, INeedsPreparationForSerialization
|
||||||
|
{
|
||||||
|
[XmlIgnore]
|
||||||
|
public int UserId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("user_id")]
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
public async Task PrepareSerialization(DatabaseContext database)
|
||||||
|
{
|
||||||
|
UserEntity user = await database.Users.FindAsync(this.UserId);
|
||||||
|
if (user == null) return;
|
||||||
|
|
||||||
|
this.Username = user.Username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameUserStreamGroup Create(int userId) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Comment;
|
||||||
|
|
||||||
[XmlRoot("comments")]
|
[XmlRoot("comments")]
|
||||||
public struct CommentListResponse : ILbpSerializable
|
public struct CommentListResponse : ILbpSerializable
|
|
@ -6,7 +6,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Comment;
|
||||||
|
|
||||||
[XmlRoot("comment")]
|
[XmlRoot("comment")]
|
||||||
[XmlType("comment")]
|
[XmlType("comment")]
|
|
@ -9,7 +9,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Photo;
|
||||||
|
|
||||||
[XmlRoot("photo")]
|
[XmlRoot("photo")]
|
||||||
[XmlType("photo")]
|
[XmlType("photo")]
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Photo;
|
||||||
|
|
||||||
[XmlType("subject")]
|
[XmlType("subject")]
|
||||||
[XmlRoot("subject")]
|
[XmlRoot("subject")]
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Photo;
|
||||||
|
|
||||||
[XmlRoot("photos")]
|
[XmlRoot("photos")]
|
||||||
public struct PhotoListResponse : ILbpSerializable
|
public struct PhotoListResponse : ILbpSerializable
|
|
@ -3,7 +3,7 @@ using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Photo;
|
||||||
|
|
||||||
[XmlRoot("slot")]
|
[XmlRoot("slot")]
|
||||||
public class PhotoSlot : ILbpSerializable
|
public class PhotoSlot : ILbpSerializable
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
|
||||||
[XmlRoot("author")]
|
[XmlRoot("author")]
|
||||||
public struct Author : ILbpSerializable
|
public struct Author : ILbpSerializable
|
|
@ -10,7 +10,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
|
||||||
[XmlRoot("playlist")]
|
[XmlRoot("playlist")]
|
||||||
public class GamePlaylist : ILbpSerializable, INeedsPreparationForSerialization
|
public class GamePlaylist : ILbpSerializable, INeedsPreparationForSerialization
|
|
@ -2,7 +2,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
|
||||||
public struct GenericPlaylistResponse<T> : ILbpSerializable, IHasCustomRoot where T : ILbpSerializable
|
public struct GenericPlaylistResponse<T> : ILbpSerializable, IHasCustomRoot where T : ILbpSerializable
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
|
||||||
public struct IconList : ILbpSerializable
|
public struct IconList : ILbpSerializable
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Playlist;
|
||||||
|
|
||||||
[XmlRoot("playlists")]
|
[XmlRoot("playlists")]
|
||||||
public struct PlaylistResponse : ILbpSerializable
|
public struct PlaylistResponse : ILbpSerializable
|
|
@ -8,7 +8,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
[XmlRoot("deleted_by")]
|
[XmlRoot("deleted_by")]
|
||||||
public enum DeletedBy
|
public enum DeletedBy
|
|
@ -2,7 +2,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
[XmlRoot("reviews")]
|
[XmlRoot("reviews")]
|
||||||
public struct ReviewResponse : ILbpSerializable
|
public struct ReviewResponse : ILbpSerializable
|
22
ProjectLighthouse/Types/Serialization/Review/ReviewSlot.cs
Normal file
22
ProjectLighthouse/Types/Serialization/Review/ReviewSlot.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
|
||||||
|
[XmlRoot("slot")]
|
||||||
|
public class ReviewSlot : ILbpSerializable
|
||||||
|
{
|
||||||
|
[XmlAttribute("type")]
|
||||||
|
public SlotType SlotType { get; set; }
|
||||||
|
|
||||||
|
[XmlText]
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
|
||||||
|
public static ReviewSlot CreateFromEntity(SlotEntity slot) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotType = slot.Type,
|
||||||
|
SlotId = slot.Type == SlotType.User ? slot.SlotId : slot.InternalSlotId,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Xml.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
|
||||||
|
|
||||||
[XmlRoot("slot")]
|
|
||||||
public class ReviewSlot : ILbpSerializable
|
|
||||||
{
|
|
||||||
[XmlAttribute("type")]
|
|
||||||
public SlotType SlotType { get; set; }
|
|
||||||
|
|
||||||
[XmlText]
|
|
||||||
public int SlotId { get; set; }
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Score;
|
||||||
|
|
||||||
[XmlRoot("playRecord")]
|
[XmlRoot("playRecord")]
|
||||||
[XmlType("playRecord")]
|
[XmlType("playRecord")]
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Score;
|
||||||
|
|
||||||
[XmlRoot("scoreboards")]
|
[XmlRoot("scoreboards")]
|
||||||
public class MultiScoreboardResponse : ILbpSerializable
|
public class MultiScoreboardResponse : ILbpSerializable
|
|
@ -2,7 +2,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Score;
|
||||||
|
|
||||||
public struct ScoreboardResponse: ILbpSerializable, IHasCustomRoot
|
public struct ScoreboardResponse: ILbpSerializable, IHasCustomRoot
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("categories")]
|
[XmlRoot("categories")]
|
||||||
public class CategoryListResponse : ILbpSerializable
|
public class CategoryListResponse : ILbpSerializable
|
|
@ -2,7 +2,7 @@
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("category")]
|
[XmlRoot("category")]
|
||||||
public class GameCategory : ILbpSerializable
|
public class GameCategory : ILbpSerializable
|
|
@ -7,7 +7,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("slot")]
|
[XmlRoot("slot")]
|
||||||
public class GameDeveloperSlot : SlotBase, INeedsPreparationForSerialization
|
public class GameDeveloperSlot : SlotBase, INeedsPreparationForSerialization
|
|
@ -13,10 +13,12 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.Review;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("slot")]
|
[XmlRoot("slot")]
|
||||||
public class GameUserSlot : SlotBase, INeedsPreparationForSerialization
|
public class GameUserSlot : SlotBase, INeedsPreparationForSerialization
|
|
@ -3,7 +3,7 @@ using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
public struct GenericSlotResponse : ILbpSerializable, IHasCustomRoot
|
public struct GenericSlotResponse : ILbpSerializable, IHasCustomRoot
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("planetStats")]
|
[XmlRoot("planetStats")]
|
||||||
public class PlanetStatsResponse : ILbpSerializable
|
public class PlanetStatsResponse : ILbpSerializable
|
|
@ -3,9 +3,10 @@ using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlInclude(typeof(GameUserSlot))]
|
[XmlInclude(typeof(GameUserSlot))]
|
||||||
[XmlInclude(typeof(GameDeveloperSlot))]
|
[XmlInclude(typeof(GameDeveloperSlot))]
|
||||||
|
@ -49,7 +50,7 @@ public abstract class SlotBase : ILbpSerializable
|
||||||
public static SlotBase CreateFromEntity(SlotEntity slot, GameTokenEntity token)
|
public static SlotBase CreateFromEntity(SlotEntity slot, GameTokenEntity token)
|
||||||
=> CreateFromEntity(slot, token.GameVersion, token.UserId);
|
=> CreateFromEntity(slot, token.GameVersion, token.UserId);
|
||||||
|
|
||||||
private static SlotBase CreateFromEntity(SlotEntity slot, GameVersion targetGame, int targetUserId)
|
public static SlotBase CreateFromEntity(SlotEntity slot, GameVersion targetGame, int targetUserId)
|
||||||
{
|
{
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.Slot;
|
||||||
|
|
||||||
[XmlRoot("slot")]
|
[XmlRoot("slot")]
|
||||||
public struct SlotResourceResponse : ILbpSerializable
|
public struct SlotResourceResponse : ILbpSerializable
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
[XmlRoot("npdata")]
|
[XmlRoot("npdata")]
|
||||||
public struct FriendResponse : ILbpSerializable
|
public struct FriendResponse : ILbpSerializable
|
|
@ -11,7 +11,7 @@ using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
[XmlRoot("user")]
|
[XmlRoot("user")]
|
||||||
public class GameUser : ILbpSerializable, INeedsPreparationForSerialization
|
public class GameUser : ILbpSerializable, INeedsPreparationForSerialization
|
|
@ -3,7 +3,7 @@ using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
public struct GenericUserResponse<T> : ILbpSerializable, IHasCustomRoot where T : ILbpSerializable
|
public struct GenericUserResponse<T> : ILbpSerializable, IHasCustomRoot where T : ILbpSerializable
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
[XmlRoot("users")]
|
[XmlRoot("users")]
|
||||||
public struct MinimalUserListResponse : ILbpSerializable
|
public struct MinimalUserListResponse : ILbpSerializable
|
|
@ -1,7 +1,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
public class NpHandle : ILbpSerializable
|
public class NpHandle : ILbpSerializable
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization.User;
|
||||||
|
|
||||||
public struct UserListResponse : ILbpSerializable, IHasCustomRoot
|
public struct UserListResponse : ILbpSerializable, IHasCustomRoot
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ public struct UserListResponse : ILbpSerializable, IHasCustomRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
public string RootTag { get; set; }
|
private string RootTag { get; set; }
|
||||||
|
|
||||||
[XmlElement("user")]
|
[XmlElement("user")]
|
||||||
public List<GameUser> Users { get; set; }
|
public List<GameUser> Users { get; set; }
|
Loading…
Add table
Add a link
Reference in a new issue