Prevent heart activity spam and fix photo grouping

This commit is contained in:
Slendy 2023-09-07 01:25:01 -05:00
commit 41d2b5be7d
No known key found for this signature in database
GPG key ID: 7288D68361B91428
3 changed files with 274 additions and 2 deletions

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Database;
@ -205,6 +206,55 @@ public class ActivityEventHandlerTests
.FirstOrDefault(a => a.Type == EventType.HeartLevel && a.SlotId == 1));
}
[Fact]
public async Task HeartedLevel_InsertDuplicate_ShouldRemoveOldActivity()
{
ActivityEntityEventHandler eventHandler = new();
DatabaseContext database = await MockHelper.GetTestDatabase(new List<UserEntity>
{
new()
{
Username = "test",
UserId = 1,
},
});
SlotEntity slot = new()
{
SlotId = 1,
CreatorId = 1,
};
database.Slots.Add(slot);
LevelActivityEntity levelActivity = new()
{
UserId = 1,
SlotId = 1,
Type = EventType.HeartLevel,
Timestamp = DateTime.MinValue,
};
database.Activities.Add(levelActivity);
await database.SaveChangesAsync();
HeartedLevelEntity heartedLevel = new()
{
HeartedLevelId = 1,
UserId = 1,
SlotId = 1,
Slot = slot,
};
Assert.NotNull(database.Activities.OfType<LevelActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.HeartLevel && a.SlotId == 1 && a.Timestamp == DateTime.MinValue));
eventHandler.OnEntityInserted(database, heartedLevel);
Assert.NotNull(database.Activities.OfType<LevelActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.HeartLevel && a.SlotId == 1 && a.Timestamp != DateTime.MinValue));
}
[Fact]
public async Task HeartedProfile_Insert_ShouldCreateUserActivity()
{
@ -231,6 +281,46 @@ public class ActivityEventHandlerTests
.FirstOrDefault(a => a.Type == EventType.HeartUser && a.TargetUserId == 1));
}
[Fact]
public async Task HeartedProfile_InsertDuplicate_ShouldRemoveOldActivity()
{
ActivityEntityEventHandler eventHandler = new();
DatabaseContext database = await MockHelper.GetTestDatabase(new List<UserEntity>
{
new()
{
Username = "test",
UserId = 1,
},
});
UserActivityEntity userActivity = new()
{
UserId = 1,
TargetUserId = 1,
Type = EventType.HeartUser,
Timestamp = DateTime.MinValue,
};
database.Activities.Add(userActivity);
await database.SaveChangesAsync();
Assert.NotNull(database.Activities.OfType<UserActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.HeartUser && a.TargetUserId == 1 && a.Timestamp == DateTime.MinValue));
HeartedProfileEntity heartedProfile = new()
{
HeartedProfileId = 1,
UserId = 1,
HeartedUserId = 1,
};
eventHandler.OnEntityInserted(database, heartedProfile);
Assert.NotNull(database.Activities.OfType<UserActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.HeartUser && a.TargetUserId == 1 && a.Timestamp != DateTime.MinValue));
}
[Fact]
public async Task HeartedPlaylist_Insert_ShouldCreatePlaylistActivity()
{
@ -265,6 +355,54 @@ public class ActivityEventHandlerTests
.FirstOrDefault(a => a.Type == EventType.HeartPlaylist && a.PlaylistId == 1));
}
[Fact]
public async Task HeartedPlaylist_InsertDuplicate_ShouldCreatePlaylistActivity()
{
ActivityEntityEventHandler eventHandler = new();
DatabaseContext database = await MockHelper.GetTestDatabase(new List<UserEntity>
{
new()
{
Username = "test",
UserId = 1,
},
});
PlaylistEntity playlist = new()
{
PlaylistId = 1,
CreatorId = 1,
};
database.Playlists.Add(playlist);
PlaylistActivityEntity playlistActivity = new()
{
UserId = 1,
PlaylistId = 1,
Type = EventType.HeartPlaylist,
Timestamp = DateTime.MinValue,
};
database.Activities.Add(playlistActivity);
await database.SaveChangesAsync();
HeartedPlaylistEntity heartedPlaylist = new()
{
HeartedPlaylistId = 1,
UserId = 1,
PlaylistId = 1,
};
Assert.NotNull(database.Activities.OfType<PlaylistActivityEntity>()
.FirstOrDefault(a =>
a.Type == EventType.HeartPlaylist && a.PlaylistId == 1 && a.Timestamp == DateTime.MinValue));
eventHandler.OnEntityInserted(database, heartedPlaylist);
Assert.NotNull(database.Activities.OfType<PlaylistActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.HeartPlaylist && a.PlaylistId == 1 && a.Timestamp != DateTime.MinValue));
}
[Fact]
public async Task VisitedLevel_Insert_ShouldCreateLevelActivity()
{
@ -696,6 +834,52 @@ public class ActivityEventHandlerTests
.FirstOrDefault(a => a.Type == EventType.UnheartLevel && a.SlotId == 1));
}
[Fact]
public async Task HeartedLevel_DeleteDuplicate_ShouldRemoveOldActivity()
{
ActivityEntityEventHandler eventHandler = new();
DatabaseContext database = await MockHelper.GetTestDatabase(new List<UserEntity>
{
new()
{
Username = "test",
UserId = 1,
},
});
SlotEntity slot = new()
{
SlotId = 1,
CreatorId = 1,
};
database.Slots.Add(slot);
LevelActivityEntity levelActivity = new()
{
UserId = 1,
SlotId = 1,
Type = EventType.UnheartLevel,
Timestamp = DateTime.MinValue,
};
database.Activities.Add(levelActivity);
HeartedLevelEntity heartedLevel = new()
{
HeartedLevelId = 1,
UserId = 1,
SlotId = 1,
};
database.HeartedLevels.Add(heartedLevel);
await database.SaveChangesAsync();
eventHandler.OnEntityDeleted(database, heartedLevel);
Assert.NotNull(database.Activities.OfType<LevelActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.UnheartLevel && a.SlotId == 1 && a.Timestamp != DateTime.MinValue));
}
[Fact]
public async Task HeartedProfile_Delete_ShouldCreateLevelActivity()
{
@ -731,5 +915,46 @@ public class ActivityEventHandlerTests
Assert.NotNull(database.Activities.OfType<UserActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.UnheartUser && a.UserId == 1));
}
[Fact]
public async Task HeartedProfile_DeleteDuplicate_ShouldCreateLevelActivity()
{
ActivityEntityEventHandler eventHandler = new();
DatabaseContext database = await MockHelper.GetTestDatabase(new List<UserEntity>
{
new()
{
Username = "test",
UserId = 1,
},
});
UserActivityEntity userActivity = new()
{
UserId = 1,
TargetUserId = 1,
Type = EventType.UnheartUser,
Timestamp = DateTime.MinValue,
};
database.Activities.Add(userActivity);
HeartedProfileEntity heartedProfile = new()
{
HeartedProfileId = 1,
UserId = 1,
HeartedUserId = 1,
};
database.HeartedProfiles.Add(heartedProfile);
await database.SaveChangesAsync();
Assert.NotNull(database.Activities.OfType<UserActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.UnheartUser && a.UserId == 1 && a.Timestamp == DateTime.MinValue));
eventHandler.OnEntityDeleted(database, heartedProfile);
Assert.NotNull(database.Activities.OfType<UserActivityEntity>()
.FirstOrDefault(a => a.Type == EventType.UnheartUser && a.UserId == 1 && a.Timestamp != DateTime.MinValue));
}
#endregion
}

View file

@ -118,7 +118,7 @@ public static class ActivityQueryExtensions
? ((UserActivityEntity)a).TargetUserId
: a is CommentActivityEntity && ((CommentActivityEntity)a).Comment.Type == CommentType.Profile
? ((CommentActivityEntity)a).Comment.TargetUserId
: a is PhotoActivityEntity && ((PhotoActivityEntity)a).Photo.SlotId != 0
: a is PhotoActivityEntity && ((PhotoActivityEntity)a).Photo.SlotId == 0
? ((PhotoActivityEntity)a).Photo.CreatorId
: 0,
TargetPlaylistId = a is PlaylistActivityEntity || a is PlaylistWithSlotActivityEntity

View file

@ -1,7 +1,9 @@
#nullable enable
using System;
using System.Linq;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types.Entities.Activity;
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
@ -144,12 +146,57 @@ public class ActivityEntityEventHandler : IEntityEventHandler
InsertActivity(database, activity);
}
private static void RemoveDuplicateEvents(DatabaseContext database, ActivityEntity activity)
{
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (activity.Type)
{
case EventType.HeartLevel:
case EventType.UnheartLevel:
{
if (activity is not LevelActivityEntity levelActivity) break;
DeleteActivity(a => a.TargetSlotId == levelActivity.SlotId);
break;
}
case EventType.HeartUser:
case EventType.UnheartUser:
{
if (activity is not UserActivityEntity userActivity) break;
DeleteActivity(a => a.TargetUserId == userActivity.TargetUserId);
break;
}
case EventType.HeartPlaylist:
{
if (activity is not PlaylistActivityEntity playlistActivity) break;
DeleteActivity(a => a.TargetPlaylistId == playlistActivity.PlaylistId);
break;
}
}
return;
void DeleteActivity(Expression<Func<ActivityDto, bool>> predicate)
{
database.Activities.ToActivityDto()
.Where(a => a.Activity.UserId == activity.UserId)
.Where(a => a.Activity.Type == activity.Type)
.Where(predicate)
.Select(a => a.Activity)
.ExecuteDelete();
}
}
private static void InsertActivity(DatabaseContext database, ActivityEntity? activity)
{
if (activity == null) return;
Logger.Debug("Inserting activity: " + activity.GetType().Name, LogArea.Activity);
RemoveDuplicateEvents(database, activity);
activity.Timestamp = DateTime.UtcNow;
database.Activities.Add(activity);
database.SaveChanges();