Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Split GameComment into GameProfileComment and GameLevelComment #561

Merged
merged 8 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 30 additions & 22 deletions Refresh.GameServer/Database/GameDatabaseContext.Comments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,67 +7,75 @@ namespace Refresh.GameServer.Database;

public partial class GameDatabaseContext // Comments
{
public GameComment? GetCommentById(int id) =>
this.GameComments.FirstOrDefault(c => c.SequentialId == id);
public GameComment PostCommentToProfile(GameUser profile, GameUser author, string content)
public GameProfileComment? GetProfileCommentById(int id) =>
this.GameProfileComments.FirstOrDefault(c => c.SequentialId == id);

public GameProfileComment PostCommentToProfile(GameUser profile, GameUser author, string content)
{
GameComment comment = new()
GameProfileComment comment = new()
{
Author = author,
Profile = profile,
Content = content,
Timestamp = this._time.TimestampMilliseconds,
};

this.AddSequentialObject(comment, profile.ProfileComments);
this.AddSequentialObject(comment);
return comment;
}

public IEnumerable<GameComment> GetProfileComments(GameUser profile, int count, int skip) =>
profile.ProfileComments
public IEnumerable<GameProfileComment> GetProfileComments(GameUser profile, int count, int skip) =>
this.GameProfileComments
.Where(c => c.Profile == profile)
.OrderByDescending(c => c.Timestamp)
.AsEnumerable()
.Skip(skip)
.Take(count);

[Pure]
public int GetTotalCommentsForProfile(GameUser profile) => profile.ProfileComments.Count;
public int GetTotalCommentsForProfile(GameUser profile) => this.GameProfileComments.Count(c => c.Profile == profile);

public void DeleteProfileComment(GameComment comment, GameUser profile)
public void DeleteProfileComment(GameProfileComment comment, GameUser profile)
{
this.Write(() =>
{
profile.ProfileComments.Remove(comment);
this.GameProfileComments.Remove(comment);
});
}

public GameLevelComment? GetLevelCommentById(int id) =>
this.GameLevelComments.FirstOrDefault(c => c.SequentialId == id);

public GameComment PostCommentToLevel(GameLevel level, GameUser author, string content)
public GameLevelComment PostCommentToLevel(GameLevel level, GameUser author, string content)
{
GameComment comment = new()
GameLevelComment comment = new()
{
Author = author,
Level = level,
Content = content,
Timestamp = this._time.TimestampMilliseconds,
};

this.AddSequentialObject(comment, level.LevelComments);
this.AddSequentialObject(comment);
return comment;
}

public IEnumerable<GameComment> GetLevelComments(GameLevel level, int count, int skip) =>
level.LevelComments
.OrderByDescending(c => c.Timestamp)
.AsEnumerable()
.Skip(skip)
.Take(count);
public IEnumerable<GameLevelComment> GetLevelComments(GameLevel level, int count, int skip) =>
this.GameLevelComments
.Where(c => c.Level == level)
.OrderByDescending(c => c.Timestamp)
.AsEnumerable()
.Skip(skip)
.Take(count);

[Pure]
public int GetTotalCommentsForLevel(GameLevel level) => level.LevelComments.Count;
public int GetTotalCommentsForLevel(GameLevel level) => this.GameLevelComments.Count(c => c.Level == level);

public void DeleteLevelComment(GameComment comment, GameLevel level)
public void DeleteLevelComment(GameLevelComment comment, GameLevel level)
{
this.Write(() =>
{
level.LevelComments.Remove(comment);
this.GameLevelComments.Remove(comment);
});
}
}
49 changes: 38 additions & 11 deletions Refresh.GameServer/Database/GameDatabaseContext.Relations.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Diagnostics.Contracts;
using Realms;
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Endpoints.Game.Levels.FilterSettings;
using Refresh.GameServer.Extensions;
using Refresh.GameServer.Types.Comments;
using Refresh.GameServer.Types.Comments.Relations;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Relations;
using Refresh.GameServer.Types.Reviews;
Expand Down Expand Up @@ -350,33 +352,52 @@ public int GetUniquePlaysForLevel(GameLevel level) =>

#region Comments

private CommentRelation? GetCommentRelationByUser(GameComment comment, GameUser user) => this.CommentRelations
private ProfileCommentRelation? GetProfileCommentRelationByUser(GameProfileComment comment, GameUser user) => this.ProfileCommentRelations
.FirstOrDefault(r => r.Comment == comment && r.User == user);

private LevelCommentRelation? GetLevelCommentRelationByUser(GameLevelComment comment, GameUser user) => this.LevelCommentRelations
.FirstOrDefault(r => r.Comment == comment && r.User == user);

/// <summary>
/// Get a user's rating on a particular comment.
/// Get a user's rating on a particular profile comment.
/// A null return value means a user has not set a rating.
/// </summary>
/// <param name="comment">The comment to check</param>
/// <param name="user">The user to check</param>
/// <returns>The rating if found</returns>
[Pure]
public RatingType? GetRatingByUser(GameComment comment, GameUser user)
=> this.GetCommentRelationByUser(comment, user)?.RatingType;
public RatingType? GetProfileCommentRatingByUser(GameProfileComment comment, GameUser user)
=> this.GetProfileCommentRelationByUser(comment, user)?.RatingType;

public int GetTotalRatingsForComment(GameComment comment, RatingType type) =>
this.CommentRelations.Count(r => r.Comment == comment && r._RatingType == (int)type);
/// <summary>
/// Get a user's rating on a particular level comment.
/// A null return value means a user has not set a rating.
/// </summary>
/// <param name="comment">The comment to check</param>
/// <param name="user">The user to check</param>
/// <returns>The rating if found</returns>
[Pure]
public RatingType? GetLevelCommentRatingByUser(GameLevelComment comment, GameUser user)
=> this.GetLevelCommentRelationByUser(comment, user)?.RatingType;

public int GetTotalRatingsForProfileComment(GameProfileComment comment, RatingType type) =>
this.ProfileCommentRelations.Count(r => r.Comment == comment && r._RatingType == (int)type);

public bool RateComment(GameUser user, GameComment comment, RatingType ratingType)
public int GetTotalRatingsForLevelComment(GameLevelComment comment, RatingType type) =>
this.LevelCommentRelations.Count(r => r.Comment == comment && r._RatingType == (int)type);

private bool RateComment<TComment, TCommentRelation>(GameUser user, TComment comment, RatingType ratingType, RealmDbSet<TCommentRelation> list)
where TComment : class, IGameComment
where TCommentRelation : class, ICommentRelation<TComment>, new()
{
if (ratingType == RatingType.Neutral)
return false;

CommentRelation? relation = GetCommentRelationByUser(comment, user);

TCommentRelation? relation = list.FirstOrDefault(r => r.Comment == comment && r.User == user);
if (relation == null)
{
relation = new CommentRelation
relation = new TCommentRelation
{
User = user,
Comment = comment,
Expand All @@ -386,7 +407,7 @@ public bool RateComment(GameUser user, GameComment comment, RatingType ratingTyp

this.Write(() =>
{
this.CommentRelations.Add(relation);
list.Add(relation);
});
}
else
Expand All @@ -400,6 +421,12 @@ public bool RateComment(GameUser user, GameComment comment, RatingType ratingTyp

return true;
}

public bool RateProfileComment(GameUser user, GameProfileComment comment, RatingType ratingType)
=> this.RateComment(user, comment, ratingType, this.ProfileCommentRelations);

public bool RateLevelComment(GameUser user, GameLevelComment comment, RatingType ratingType)
=> this.RateComment(user, comment, ratingType, this.LevelCommentRelations);

#endregion
}
8 changes: 5 additions & 3 deletions Refresh.GameServer/Database/GameDatabaseContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
using Refresh.GameServer.Types.Activity;
using Refresh.GameServer.Types.Assets;
using Refresh.GameServer.Types.Comments;
using Refresh.GameServer.Types.Comments.Relations;
using Refresh.GameServer.Types.Contests;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Levels.SkillRewards;
using Refresh.GameServer.Types.Notifications;
using Refresh.GameServer.Types.Photos;
using Refresh.GameServer.Types.Relations;
Expand All @@ -30,8 +30,10 @@ public partial class GameDatabaseContext : RealmDatabaseContext
private RealmDbSet<GameUser> GameUsers => new(this._realm);
private RealmDbSet<Token> Tokens => new(this._realm);
private RealmDbSet<GameLevel> GameLevels => new(this._realm);
private RealmDbSet<GameComment> GameComments => new(this._realm);
private RealmDbSet<CommentRelation> CommentRelations => new(this._realm);
private RealmDbSet<GameProfileComment> GameProfileComments => new(this._realm);
private RealmDbSet<GameLevelComment> GameLevelComments => new(this._realm);
private RealmDbSet<ProfileCommentRelation> ProfileCommentRelations => new(this._realm);
private RealmDbSet<LevelCommentRelation> LevelCommentRelations => new(this._realm);
private RealmDbSet<FavouriteLevelRelation> FavouriteLevelRelations => new(this._realm);
private RealmDbSet<QueueLevelRelation> QueueLevelRelations => new(this._realm);
private RealmDbSet<FavouriteUserRelation> FavouriteUserRelations => new(this._realm);
Expand Down
13 changes: 8 additions & 5 deletions Refresh.GameServer/Database/GameDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Refresh.GameServer.Time;
using Refresh.GameServer.Types.Activity;
using Refresh.GameServer.Types.Assets;
using Refresh.GameServer.Types.Comments.Relations;
using Refresh.GameServer.Types.Contests;
using Refresh.GameServer.Types.Levels.SkillRewards;
using Refresh.GameServer.Types.Notifications;
Expand Down Expand Up @@ -43,8 +44,10 @@ protected GameDatabaseProvider(IDateTimeProvider time)
typeof(Token),
typeof(GameLevel),
typeof(GameSkillReward),
typeof(GameComment),
typeof(CommentRelation),
typeof(GameProfileComment),
typeof(GameLevelComment),
typeof(ProfileCommentRelation),
typeof(LevelCommentRelation),
typeof(FavouriteLevelRelation),
typeof(QueueLevelRelation),
typeof(FavouriteUserRelation),
Expand Down Expand Up @@ -309,14 +312,14 @@ protected override void Migrate(Migration migration, ulong oldVersion)
}

IQueryable<dynamic>? oldComments = migration.OldRealm.DynamicApi.All("GameComment");
IQueryable<GameComment>? newComments = migration.NewRealm.All<GameComment>();
IQueryable<dynamic>? newComments = migration.NewRealm.DynamicApi.All("GameComment");

for (int i = 0; i < newComments.Count(); i++)
{
dynamic oldComment = oldComments.ElementAt(i);
GameComment newComment = newComments.ElementAt(i);
dynamic newComment = newComments.ElementAt(i);

// In version 40, we switched to Realm source generators which requires some values to be reset
// In version 40, we switched to Realm source generators, which requires some values to be reset
if (oldVersion < 40)
{
newComment.Content = oldComment.Content;
Expand Down
43 changes: 26 additions & 17 deletions Refresh.GameServer/Endpoints/Game/CommentEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Refresh.GameServer.Endpoints.Game;
public class CommentEndpoints : EndpointGroup
{
[GameEndpoint("postUserComment/{username}", ContentType.Xml, HttpMethods.Post)]
public Response PostProfileComment(RequestContext context, GameDatabaseContext database, string username, GameComment body, GameUser user, IDateTimeProvider timeProvider)
public Response PostProfileComment(RequestContext context, GameDatabaseContext database, string username, SerializedComment body, GameUser user, IDateTimeProvider timeProvider)
{
if (body.Content.Length > 4096)
{
Expand All @@ -43,10 +43,7 @@ public Response PostProfileComment(RequestContext context, GameDatabaseContext d

(int skip, int count) = context.GetPageData();

List<GameComment> comments = database.GetProfileComments(profile, count, skip).ToList();
foreach (GameComment comment in comments) comment.PrepareForSerialization(user, dataContext);

return new SerializedCommentList(comments);
return new SerializedCommentList(SerializedComment.FromOldList(database.GetProfileComments(profile, count, skip), dataContext));
}

[GameEndpoint("deleteUserComment/{username}", HttpMethods.Post)]
Expand All @@ -57,7 +54,7 @@ public Response DeleteProfileComment(RequestContext context, GameDatabaseContext
GameUser? profile = database.GetUserByUsername(username);
if (profile == null) return NotFound;

GameComment? comment = profile.ProfileComments.FirstOrDefault(comment => comment.SequentialId == commentId);
GameProfileComment? comment = database.GetProfileCommentById(commentId);
if (comment == null) return BadRequest;

//Validate someone doesnt try to delete someone elses comment
Expand All @@ -73,7 +70,7 @@ public Response DeleteProfileComment(RequestContext context, GameDatabaseContext
}

[GameEndpoint("postComment/{slotType}/{id}", ContentType.Xml, HttpMethods.Post)]
public Response PostLevelComment(RequestContext context, GameDatabaseContext database, string slotType, int id, GameComment body, GameUser user)
public Response PostLevelComment(RequestContext context, GameDatabaseContext database, string slotType, int id, SerializedComment body, GameUser user)
{
if (body.Content.Length > 4096)
{
Expand All @@ -98,10 +95,7 @@ public Response PostLevelComment(RequestContext context, GameDatabaseContext dat

(int skip, int count) = context.GetPageData();

List<GameComment> comments = database.GetLevelComments(level, count, skip).ToList();
foreach(GameComment comment in comments) comment.PrepareForSerialization(user, dataContext);

return new SerializedCommentList(comments);
return new SerializedCommentList(SerializedComment.FromOldList(database.GetLevelComments(level, count, skip), dataContext));
}

[GameEndpoint("deleteComment/{slotType}/{id}", HttpMethods.Post)]
Expand All @@ -111,8 +105,8 @@ public Response DeleteLevelComment(RequestContext context, GameDatabaseContext d

GameLevel? level = database.GetLevelByIdAndType(slotType, id);
if (level == null) return NotFound;
GameComment? comment = level.LevelComments.FirstOrDefault(comment => comment.SequentialId == commentId);

GameLevelComment? comment = database.GetLevelCommentById(commentId);
if (comment == null) return BadRequest;

//Validate someone doesnt try to delete someone else's comment
Expand All @@ -126,20 +120,35 @@ public Response DeleteLevelComment(RequestContext context, GameDatabaseContext d

return OK;
}

[GameEndpoint("rateUserComment/{content}", HttpMethods.Post)] // profile comments
public Response RateProfileComment(RequestContext context, GameDatabaseContext database, GameUser user, string content)
{
if (!int.TryParse(context.QueryString["commentId"], out int commentId)) return BadRequest;
if (!Enum.TryParse(context.QueryString["rating"], out RatingType ratingType)) return BadRequest;

GameProfileComment? comment = database.GetProfileCommentById(commentId);
if (comment == null)
return NotFound;

if (!database.RateProfileComment(user, comment, ratingType))
return BadRequest;

return OK;
}

[GameEndpoint("rateComment/user/{content}", HttpMethods.Post)] // `user` level comments
[GameEndpoint("rateComment/developer/{content}", HttpMethods.Post)] // `developer` level comments
[GameEndpoint("rateUserComment/{content}", HttpMethods.Post)] // profile comments
public Response RateComment(RequestContext context, GameDatabaseContext database, GameUser user, string content)
public Response RateLevelComment(RequestContext context, GameDatabaseContext database, GameUser user, string content)
{
if (!int.TryParse(context.QueryString["commentId"], out int commentId)) return BadRequest;
if (!Enum.TryParse(context.QueryString["rating"], out RatingType ratingType)) return BadRequest;

GameComment? comment = database.GetCommentById(commentId);
GameLevelComment? comment = database.GetLevelCommentById(commentId);
if (comment == null)
return NotFound;

if (!database.RateComment(user, comment, ratingType))
if (!database.RateLevelComment(user, comment, ratingType))
return BadRequest;

return OK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public static GameLevelResponse FromHash(string hash, DataContext dataContext)
Links = "",
AverageStarRating = old.CalculateAverageStarRating(dataContext.Database),
ReviewCount = old.Reviews.Count,
CommentCount = old.LevelComments.Count,
CommentCount = dataContext.Database.GetTotalCommentsForLevel(old),
};

response.Type = "user";
Expand Down Expand Up @@ -221,7 +221,7 @@ public static GameLevelResponse FromHash(string hash, DataContext dataContext)

response.IconHash = dataContext.Database.GetAssetFromHash(old.IconHash)?.GetAsIcon(dataContext.Game, dataContext) ?? response.IconHash;

response.CommentCount = old.LevelComments.Count;
response.CommentCount = dataContext.Database.GetTotalCommentsForLevel(old);

return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class GameUserResponse : IDataConvertableFrom<GameUserResponse, GameUser>
PlanetsHash = "0",

Handle = SerializedUserHandle.FromUser(old, dataContext),
CommentCount = old.ProfileComments.Count,
CommentCount = dataContext.Database.GetTotalCommentsForProfile(old),
CommentsEnabled = true,
FavouriteLevelCount = old.IsManaged ? dataContext.Database.GetTotalLevelsFavouritedByUser(old) : 0,
FavouriteUserCount = old.IsManaged ? dataContext.Database.GetTotalUsersFavouritedByUser(old) : 0,
Expand Down
Loading
Loading