using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Serialization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.Moderator; [ApiController] [Route("moderation")] public class ModerationRemovalController : ControllerBase { private readonly DatabaseContext database; public ModerationRemovalController(DatabaseContext database) { this.database = database; } private async Task Delete(DbSet dbSet, int id, string? callbackUrl, Func> getHandler) where T: class { UserEntity? user = this.database.UserFromWebRequest(this.Request); if (user == null) return this.Redirect("~/login"); T? item = await getHandler(user, id); if (item == null) return this.Redirect("~/404"); dbSet.Remove(item); await this.database.SaveChangesAsync(); return this.Redirect(callbackUrl ?? "~/"); } [HttpGet("deleteScore/{scoreId:int}")] public async Task DeleteScore(int scoreId, [FromQuery] string? callbackUrl) { return await this.Delete(this.database.Scores, scoreId, callbackUrl, async (user, id) => { ScoreEntity? score = await this.database.Scores.Include(s => s.Slot).FirstOrDefaultAsync(s => s.ScoreId == id); if (score == null) return null; return user.IsModerator ? score : null; }); } [HttpGet("deleteComment/{commentId:int}")] public async Task DeleteComment(int commentId, [FromQuery] string? callbackUrl) { UserEntity? user = this.database.UserFromWebRequest(this.Request); if (user == null) return this.Redirect("~/login"); CommentEntity? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId); if (comment == null) return this.Redirect("~/404"); if (comment.Deleted) return this.Redirect(callbackUrl ?? "~/"); bool canDelete; switch (comment.Type) { case CommentType.Level: int slotCreatorId = await this.database.Slots.Where(s => s.SlotId == comment.TargetId) .Select(s => s.CreatorId) .FirstOrDefaultAsync(); canDelete = user.UserId == comment.PosterUserId || user.UserId == slotCreatorId; break; case CommentType.Profile: canDelete = user.UserId == comment.PosterUserId || user.UserId == comment.TargetId; break; default: throw new ArgumentOutOfRangeException(nameof(commentId)); } if (!canDelete && !user.IsModerator) return this.Redirect(callbackUrl ?? "~/"); comment.Deleted = true; comment.DeletedBy = user.Username; comment.DeletedType = !canDelete && user.IsModerator ? "moderator" : "user"; await this.database.SaveChangesAsync(); return this.Redirect(callbackUrl ?? "~/"); } [HttpGet("deleteReview/{reviewId:int}")] public async Task DeleteReview(int reviewId, [FromQuery] string? callbackUrl) { UserEntity? user = this.database.UserFromWebRequest(this.Request); if (user == null) return this.Redirect("~/login"); ReviewEntity? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(c => c.ReviewId == reviewId); if (review == null) return this.Redirect("~/404"); if (review.Deleted) return this.Redirect(callbackUrl ?? "~/"); bool canDelete = review.Slot?.CreatorId == user.UserId; if (!canDelete && !user.IsModerator) return this.Redirect(callbackUrl ?? "~/"); review.Deleted = true; review.DeletedBy = !canDelete && user.IsModerator ? DeletedBy.Moderator : DeletedBy.LevelAuthor; await this.database.SaveChangesAsync(); return this.Redirect(callbackUrl ?? "~/"); } [HttpGet("deletePhoto/{photoId:int}")] public async Task DeletePhoto(int photoId, [FromQuery] string? callbackUrl) { return await this.Delete(this.database.Photos, photoId, callbackUrl, async (user, id) => { PhotoEntity? photo = await this.database.Photos.Include(p => p.Slot).FirstOrDefaultAsync(p => p.PhotoId == id); if (photo == null) return null; if (!user.IsModerator && photo.CreatorId != user.UserId) return null; return photo; }); } }