mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-16 14:42:28 +00:00
Improvements to website comments and good grief reports along with numerous bug fixes
This commit is contained in:
parent
e4b4984505
commit
aacc2d5eaf
30 changed files with 882 additions and 148 deletions
|
@ -33,49 +33,9 @@ public class CommentController : ControllerBase
|
||||||
User? user = await this.database.UserFromGameRequest(this.Request);
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
Comment? comment = await this.database.Comments.Include(c => c.Poster).FirstOrDefaultAsync(c => commentId == c.CommentId);
|
bool success = await this.database.RateComment(user, commentId, rating);
|
||||||
|
if (!success) return this.BadRequest();
|
||||||
|
|
||||||
if (comment == null) return this.BadRequest();
|
|
||||||
|
|
||||||
Reaction? reaction = await this.database.Reactions.FirstOrDefaultAsync(r => r.UserId == user.UserId && r.TargetId == commentId);
|
|
||||||
if (reaction == null)
|
|
||||||
{
|
|
||||||
Reaction newReaction = new Reaction()
|
|
||||||
{
|
|
||||||
UserId = user.UserId,
|
|
||||||
TargetId = commentId,
|
|
||||||
Rating = 0,
|
|
||||||
};
|
|
||||||
this.database.Reactions.Add(newReaction);
|
|
||||||
await this.database.SaveChangesAsync();
|
|
||||||
reaction = newReaction;
|
|
||||||
}
|
|
||||||
int oldRating = reaction.Rating;
|
|
||||||
if (oldRating == rating) return this.Ok();
|
|
||||||
|
|
||||||
reaction.Rating = rating;
|
|
||||||
// if rating changed then we count the number of reactions to ensure accuracy
|
|
||||||
List<Reaction> reactions = await this.database.Reactions
|
|
||||||
.Where(c => c.TargetId == commentId)
|
|
||||||
.ToListAsync();
|
|
||||||
int yay = 0;
|
|
||||||
int boo = 0;
|
|
||||||
foreach (Reaction r in reactions)
|
|
||||||
{
|
|
||||||
switch (r.Rating)
|
|
||||||
{
|
|
||||||
case -1:
|
|
||||||
boo++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
yay++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
comment.ThumbsDown = boo;
|
|
||||||
comment.ThumbsUp = yay;
|
|
||||||
await this.database.SaveChangesAsync();
|
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,27 +95,12 @@ public class CommentController : ControllerBase
|
||||||
|
|
||||||
int targetId = slotId.GetValueOrDefault();
|
int targetId = slotId.GetValueOrDefault();
|
||||||
|
|
||||||
if (type == CommentType.Profile)
|
if (type == CommentType.Profile) targetId = this.database.Users.First(u => u.Username == username).UserId;
|
||||||
{
|
|
||||||
User? target = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
|
||||||
if (target == null) return this.BadRequest();
|
|
||||||
targetId = target.UserId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Slot? target = await this.database.Slots.FirstOrDefaultAsync(u => u.SlotId == slotId);
|
|
||||||
if (target == null) return this.BadRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
comment.PosterUserId = poster.UserId;
|
bool success = await this.database.PostComment(poster, targetId, type, comment.Message);
|
||||||
comment.TargetId = targetId;
|
if (success) return this.Ok();
|
||||||
comment.Type = type;
|
|
||||||
|
|
||||||
comment.Timestamp = TimeHelper.UnixTimeMilliseconds();
|
return this.BadRequest();
|
||||||
|
|
||||||
this.database.Comments.Add(comment);
|
|
||||||
await this.database.SaveChangesAsync();
|
|
||||||
return this.Ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("deleteUserComment/{username}")]
|
[HttpPost("deleteUserComment/{username}")]
|
||||||
|
|
56
ProjectLighthouse/Controllers/GameApi/ReportController.cs
Normal file
56
ProjectLighthouse/Controllers/GameApi/ReportController.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Kettu;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||||
|
[Produces("text/xml")]
|
||||||
|
public class ReportController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly Database database;
|
||||||
|
|
||||||
|
public ReportController(Database database)
|
||||||
|
{
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("grief")]
|
||||||
|
public async Task<IActionResult> Report()
|
||||||
|
{
|
||||||
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
|
this.Request.Body.Position = 0;
|
||||||
|
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||||
|
|
||||||
|
Console.WriteLine(bodyString);
|
||||||
|
XmlSerializer serializer = new(typeof(GriefReport));
|
||||||
|
GriefReport? report = (GriefReport?) serializer.Deserialize(new StringReader(bodyString));
|
||||||
|
|
||||||
|
if (report == null) return this.BadRequest();
|
||||||
|
|
||||||
|
report.Bounds = JsonSerializer.Serialize(report.XmlBounds.Rect, typeof(Rectangle));
|
||||||
|
report.Players = JsonSerializer.Serialize(report.XmlPlayers, typeof(ReportPlayer[]));
|
||||||
|
report.VisiblePlayers = JsonSerializer.Serialize(report.XmlVisiblePlayers, typeof(VisiblePlayer[]));
|
||||||
|
report.Timestamp = TimeHelper.UnixTimeMilliseconds();
|
||||||
|
report.ReportingPlayerId = user.UserId;
|
||||||
|
|
||||||
|
this.database.Reports.Add(report);
|
||||||
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return this.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ public class ResourcesController : ControllerBase
|
||||||
[HttpGet("/gameAssets/{hash}")]
|
[HttpGet("/gameAssets/{hash}")]
|
||||||
public IActionResult GetGameImage(string hash)
|
public IActionResult GetGameImage(string hash)
|
||||||
{
|
{
|
||||||
string path = $"png/{hash}.png";
|
string path = $"png{Path.DirectorySeparatorChar}{hash}.png";
|
||||||
|
|
||||||
if (IOFile.Exists(path))
|
if (IOFile.Exists(path))
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,32 @@ public class SlotPageController : ControllerBase
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("rateComment")]
|
||||||
|
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int commentId, [FromQuery] int rating)
|
||||||
|
{
|
||||||
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
|
await this.database.RateComment(user,
|
||||||
|
commentId,
|
||||||
|
rating);
|
||||||
|
|
||||||
|
return this.Redirect("~/slot/" + id + "#" + commentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("postComment")]
|
||||||
|
public async Task<IActionResult> PostComment([FromRoute] int id, [FromQuery] string msg)
|
||||||
|
{
|
||||||
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
|
bool success = await this.database.PostComment(user, id, CommentType.Level, msg);
|
||||||
|
|
||||||
|
if (!success) return this.NotFound();
|
||||||
|
|
||||||
|
return this.Redirect("~/slot/" + id);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("heart")]
|
[HttpGet("heart")]
|
||||||
public async Task<IActionResult> HeartLevel([FromRoute] int id, [FromQuery] string? callbackUrl)
|
public async Task<IActionResult> HeartLevel([FromRoute] int id, [FromQuery] string? callbackUrl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Controllers.Website;
|
namespace LBPUnion.ProjectLighthouse.Controllers.Website;
|
||||||
|
@ -31,6 +34,30 @@ public class UserPageController : ControllerBase
|
||||||
return this.Redirect("~/user/" + id);
|
return this.Redirect("~/user/" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("rateComment")]
|
||||||
|
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int commentId, [FromQuery] int rating)
|
||||||
|
{
|
||||||
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
|
await this.database.RateComment(user, commentId, rating);
|
||||||
|
|
||||||
|
return this.Redirect("~/user/" + id + "#" + commentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("postComment")]
|
||||||
|
public async Task<IActionResult> PostComment([FromRoute] int id, [FromQuery] string msg)
|
||||||
|
{
|
||||||
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
|
bool success = await this.database.PostComment(user, id, CommentType.Profile, msg);
|
||||||
|
|
||||||
|
if (!success) return this.NotFound();
|
||||||
|
|
||||||
|
return this.Redirect("~/user/" + id);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("unheart")]
|
[HttpGet("unheart")]
|
||||||
public async Task<IActionResult> UnheartUser([FromRoute] int id)
|
public async Task<IActionResult> UnheartUser([FromRoute] int id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
@ -6,6 +7,7 @@ using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Categories;
|
using LBPUnion.ProjectLighthouse.Types.Categories;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Reviews;
|
using LBPUnion.ProjectLighthouse.Types.Reviews;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Tickets;
|
using LBPUnion.ProjectLighthouse.Types.Tickets;
|
||||||
|
@ -37,6 +39,7 @@ public class Database : DbContext
|
||||||
public DbSet<UserApprovedIpAddress> UserApprovedIpAddresses { get; set; }
|
public DbSet<UserApprovedIpAddress> UserApprovedIpAddresses { get; set; }
|
||||||
public DbSet<DatabaseCategory> CustomCategories { get; set; }
|
public DbSet<DatabaseCategory> CustomCategories { get; set; }
|
||||||
public DbSet<Reaction> Reactions { get; set; }
|
public DbSet<Reaction> Reactions { get; set; }
|
||||||
|
public DbSet<GriefReport> Reports { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
=> options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
=> options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
||||||
|
@ -89,6 +92,83 @@ public class Database : DbContext
|
||||||
|
|
||||||
#region Hearts & Queues
|
#region Hearts & Queues
|
||||||
|
|
||||||
|
public async Task<bool> RateComment(User user, int commentId, int rating)
|
||||||
|
{
|
||||||
|
Comment? comment = await this.Comments.FirstOrDefaultAsync(c => commentId == c.CommentId);
|
||||||
|
|
||||||
|
if (comment == null) return false;
|
||||||
|
|
||||||
|
if (comment.PosterUserId == user.UserId) return false;
|
||||||
|
|
||||||
|
Reaction? reaction = await this.Reactions.FirstOrDefaultAsync(r => r.UserId == user.UserId && r.TargetId == commentId);
|
||||||
|
if (reaction == null)
|
||||||
|
{
|
||||||
|
Reaction newReaction = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
TargetId = commentId,
|
||||||
|
Rating = 0,
|
||||||
|
};
|
||||||
|
this.Reactions.Add(newReaction);
|
||||||
|
await this.SaveChangesAsync();
|
||||||
|
reaction = newReaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oldRating = reaction.Rating;
|
||||||
|
if (oldRating == rating) return true;
|
||||||
|
|
||||||
|
reaction.Rating = rating;
|
||||||
|
// if rating changed then we count the number of reactions to ensure accuracy
|
||||||
|
List<Reaction> reactions = await this.Reactions.Where(c => c.TargetId == commentId).ToListAsync();
|
||||||
|
int yay = 0;
|
||||||
|
int boo = 0;
|
||||||
|
foreach (Reaction r in reactions)
|
||||||
|
{
|
||||||
|
switch (r.Rating)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
boo++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
yay++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.ThumbsDown = boo;
|
||||||
|
comment.ThumbsUp = yay;
|
||||||
|
await this.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> PostComment(User user, int targetId, CommentType type, string message)
|
||||||
|
{
|
||||||
|
if (type == CommentType.Profile)
|
||||||
|
{
|
||||||
|
User? targetUser = await this.Users.FirstOrDefaultAsync(u => u.UserId == targetId);
|
||||||
|
if (targetUser == null) return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Slot? targetSlot = await this.Slots.FirstOrDefaultAsync(u => u.SlotId == targetId);
|
||||||
|
if(targetSlot == null) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Comments.Add
|
||||||
|
(
|
||||||
|
new Comment
|
||||||
|
{
|
||||||
|
PosterUserId = user.UserId,
|
||||||
|
TargetId = targetId,
|
||||||
|
Type = type,
|
||||||
|
Message = message,
|
||||||
|
Timestamp = TimeHelper.UnixTimeMilliseconds(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await this.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task HeartUser(User user, User heartedUser)
|
public async Task HeartUser(User user, User heartedUser)
|
||||||
{
|
{
|
||||||
HeartedProfile? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
HeartedProfile? heartedProfile = await this.HeartedProfiles.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.Intrinsics.Arm;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -11,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
public static class HashHelper
|
public static class HashHelper
|
||||||
{
|
{
|
||||||
private static readonly SHA1 sha1 = SHA1.Create();
|
// private static readonly SHA1 sha1 = SHA1.Create();
|
||||||
private static readonly SHA256 sha256 = SHA256.Create();
|
private static readonly SHA256 sha256 = SHA256.Create();
|
||||||
private static readonly Random random = new();
|
private static readonly Random random = new();
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ public static class HashHelper
|
||||||
|
|
||||||
public static string Sha1Hash(string str) => Sha1Hash(Encoding.UTF8.GetBytes(str));
|
public static string Sha1Hash(string str) => Sha1Hash(Encoding.UTF8.GetBytes(str));
|
||||||
|
|
||||||
public static string Sha1Hash(byte[] bytes) => BitConverter.ToString(sha1.ComputeHash(bytes)).Replace("-", "");
|
public static string Sha1Hash(byte[] bytes) => BitConverter.ToString(SHA1.Create().ComputeHash(bytes)).Replace("-","");
|
||||||
|
|
||||||
public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str);
|
public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ public static class ImageHelper
|
||||||
{
|
{
|
||||||
if (type != LbpFileType.Jpeg && type != LbpFileType.Png && type != LbpFileType.Texture) return false;
|
if (type != LbpFileType.Jpeg && type != LbpFileType.Png && type != LbpFileType.Texture) return false;
|
||||||
|
|
||||||
if (File.Exists($"png/{hash}.png")) return true;
|
if (File.Exists($"png{Path.DirectorySeparatorChar}{hash}.png")) return true;
|
||||||
|
|
||||||
using MemoryStream ms = new(data);
|
using MemoryStream ms = new(data);
|
||||||
using BinaryReader reader = new(ms);
|
using BinaryReader reader = new(ms);
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(Database))]
|
||||||
|
[Migration("20220212041106_AddGriefReports")]
|
||||||
|
public partial class AddGriefReports : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Reports",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ReportId = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Type = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Timestamp = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
VisiblePlayers = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
ReportingPlayerId = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Players = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
GriefStateHash = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
LevelOwner = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
InitialStateHash = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
JpegHash = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
LevelId = table.Column<int>(type: "int", nullable: false),
|
||||||
|
LevelType = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Bounds = table.Column<string>(type: "longtext", nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Reports", x => x.ReportId);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Reports_Users_ReportingPlayerId",
|
||||||
|
column: x => x.ReportingPlayerId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "UserId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Reports_ReportingPlayerId",
|
||||||
|
table: "Reports",
|
||||||
|
column: "ReportingPlayerId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Reports");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ namespace ProjectLighthouse.Migrations
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "6.0.0")
|
.HasAnnotation("ProductVersion", "6.0.2")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b =>
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b =>
|
||||||
|
@ -503,6 +503,55 @@ namespace ProjectLighthouse.Migrations
|
||||||
b.ToTable("Reactions");
|
b.ToTable("Reactions");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reports.GriefReport", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ReportId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Bounds")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("GriefStateHash")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("InitialStateHash")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("JpegHash")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("LevelId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("LevelOwner")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("LevelType")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Players")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("ReportingPlayerId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Timestamp")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("VisiblePlayers")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("ReportId");
|
||||||
|
|
||||||
|
b.HasIndex("ReportingPlayerId");
|
||||||
|
|
||||||
|
b.ToTable("Reports");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b =>
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("RatedReviewId")
|
b.Property<int>("RatedReviewId")
|
||||||
|
@ -862,6 +911,17 @@ namespace ProjectLighthouse.Migrations
|
||||||
b.Navigation("Poster");
|
b.Navigation("Poster");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reports.GriefReport", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "ReportingPlayer")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ReportingPlayerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("ReportingPlayer");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b =>
|
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Reviews.Review", "Review")
|
b.HasOne("LBPUnion.ProjectLighthouse.Types.Reviews.Review", "Review")
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
@if (Model.User.IsAdmin)
|
@if (Model.User.IsAdmin)
|
||||||
{
|
{
|
||||||
|
Model.NavigationItems.Add(new PageNavigationItem("Reports", "/reports/0", "exclamation circle"));
|
||||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Admin Panel", "/admin", "cogs"));
|
Model.NavigationItemsRight.Add(new PageNavigationItem("Admin Panel", "/admin", "cogs"));
|
||||||
}
|
}
|
||||||
Model.NavigationItemsRight.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last
|
Model.NavigationItemsRight.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last
|
||||||
|
|
74
ProjectLighthouse/Pages/Partials/CommentsPartial.cshtml
Normal file
74
ProjectLighthouse/Pages/Partials/CommentsPartial.cshtml
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
@using System.IO
|
||||||
|
@using System.Web
|
||||||
|
@using LBPUnion.ProjectLighthouse.Types.Profiles
|
||||||
|
|
||||||
|
<div class="ui yellow segment" id="comments">
|
||||||
|
<style>
|
||||||
|
.comment {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.voting {
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1>Comments</h1>
|
||||||
|
@if (Model.Comments.Count == 0)
|
||||||
|
{
|
||||||
|
<p>There are no comments.</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
@for (int i = 0; i < Model.Comments.Count; i++)
|
||||||
|
{
|
||||||
|
Comment comment = Model.Comments[i];
|
||||||
|
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000);
|
||||||
|
StringWriter messageWriter = new();
|
||||||
|
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
||||||
|
string decodedMessage = messageWriter.ToString();
|
||||||
|
string url = Url.RouteUrl(ViewContext.RouteData.Values);
|
||||||
|
int rating = comment.ThumbsUp - comment.ThumbsDown;
|
||||||
|
<div style="display: flex" id="@comment.CommentId">
|
||||||
|
<div class="voting">
|
||||||
|
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == 1 ? 0 : 1)">
|
||||||
|
<i class="fitted @(comment.YourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
|
||||||
|
</a>
|
||||||
|
<span style="text-align: center; margin: auto; @(rating < 0 ? "margin-left: -5px" : "")">@(rating)</span>
|
||||||
|
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == -1 ? 0 : -1)">
|
||||||
|
<i class="fitted @(comment.YourThumb == -1 ? "red" : "grey") arrow down link icon" style="display: block"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment">
|
||||||
|
<b><a href="/user/@comment.PosterUserId">@comment.Poster.Username</a>: </b>
|
||||||
|
@if (comment.Deleted)
|
||||||
|
{
|
||||||
|
<i><span>@decodedMessage</span></i>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>@decodedMessage</span>
|
||||||
|
}
|
||||||
|
<p>
|
||||||
|
<i>@timestamp.ToString("MM/dd/yyyy @ h:mm tt") UTC</i>
|
||||||
|
</p>
|
||||||
|
@if (i != Model.Comments.Count - 1)
|
||||||
|
{
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if(Model.CommentsEnabled){
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<form class="ui reply form" action="@Url.RouteUrl(ViewContext.RouteData.Values)/postComment">
|
||||||
|
<div class="field">
|
||||||
|
<textarea style="min-height: 70px; height: 70px; max-height:120px" name="msg"></textarea>
|
||||||
|
</div>
|
||||||
|
<input type="submit" class="ui blue button">
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</div>
|
|
@ -31,16 +31,17 @@ public class PhotosPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name)) name = "";
|
if (string.IsNullOrWhiteSpace(name)) name = "";
|
||||||
|
|
||||||
this.PhotoCount = await this.Database.Photos.CountAsync(p => p.Creator.Username.Contains(name) || p.PhotoSubjectCollection.Contains(name));
|
this.SearchValue = name.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
this.PhotoCount = await this.Database.Photos.CountAsync(p => p.Creator.Username.Contains(this.SearchValue) || p.PhotoSubjectCollection.Contains(this.SearchValue));
|
||||||
|
|
||||||
this.SearchValue = name;
|
|
||||||
this.PageNumber = pageNumber;
|
this.PageNumber = pageNumber;
|
||||||
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.PhotoCount / ServerStatics.PageSize));
|
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.PhotoCount / ServerStatics.PageSize));
|
||||||
|
|
||||||
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/photos/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/photos/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
||||||
|
|
||||||
this.Photos = await this.Database.Photos.Include(p => p.Creator)
|
this.Photos = await this.Database.Photos.Include(p => p.Creator)
|
||||||
.Where(p => p.Creator.Username.Contains(name) || p.PhotoSubjectCollection.Contains(name))
|
.Where(p => p.Creator.Username.Contains(this.SearchValue) || p.PhotoSubjectCollection.Contains(this.SearchValue))
|
||||||
.OrderByDescending(p => p.Timestamp)
|
.OrderByDescending(p => p.Timestamp)
|
||||||
.Skip(pageNumber * ServerStatics.PageSize)
|
.Skip(pageNumber * ServerStatics.PageSize)
|
||||||
.Take(ServerStatics.PageSize)
|
.Take(ServerStatics.PageSize)
|
||||||
|
|
206
ProjectLighthouse/Pages/ReportsPage.cshtml
Normal file
206
ProjectLighthouse/Pages/ReportsPage.cshtml
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
@page "/reports/{pageNumber:int}"
|
||||||
|
@using LBPUnion.ProjectLighthouse.Types.Reports
|
||||||
|
@model LBPUnion.ProjectLighthouse.Pages.ReportsPage
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "Layouts/BaseLayout";
|
||||||
|
Model.Title = "Reports";
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>There are @Model.ReportCount total reports!</p>
|
||||||
|
|
||||||
|
<form action="/reports/0">
|
||||||
|
<div class="ui icon input">
|
||||||
|
<input type="text" name="name" placeholder="Search reports..." value="@Model.SearchValue">
|
||||||
|
<i class="search icon"></i>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<script>
|
||||||
|
let subjects = [];
|
||||||
|
let bounds = [];
|
||||||
|
let canvases = [];
|
||||||
|
let ctx = [];
|
||||||
|
let images = [];
|
||||||
|
</script>
|
||||||
|
@foreach (GriefReport report in Model.Reports)
|
||||||
|
{
|
||||||
|
<div class="ui segment">
|
||||||
|
<div>
|
||||||
|
<canvas class="hide-subjects" id="canvas-subjects-@report.ReportId" width="1920" height="1080"
|
||||||
|
style="position: absolute; transform: rotate(180deg)">
|
||||||
|
</canvas>
|
||||||
|
<img id="game-image-@report.ReportId" src="/gameAssets/@report.JpegHash" alt="Grief report picture" style="width: 100%; height: auto; border-radius: .28571429rem;">
|
||||||
|
</div>
|
||||||
|
<p><i>Report submitted by <b><a href="/user/@report.ReportingPlayerId">@report.ReportingPlayer.Username</a></b></i></p>
|
||||||
|
<b class="hover-players" id="hover-subjects-2-@report.ReportId">Report contains @report.XmlPlayers.Length @(report.XmlPlayers.Length == 1 ? "player" : "players")</b>
|
||||||
|
@foreach (ReportPlayer player in report.XmlPlayers)
|
||||||
|
{
|
||||||
|
<div id="hover-subjects-@report.ReportId" class="hover-players">
|
||||||
|
<a href="/">@player.Name</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div><b>Report time: </b>@(DateTimeOffset.FromUnixTimeMilliseconds(report.Timestamp).ToString("R"))</div>
|
||||||
|
<div><b>Report reason: </b>@report.Type</div>
|
||||||
|
<div><b>Level ID:</b> @report.LevelId</div>
|
||||||
|
<div><b>Level type:</b> @report.LevelType</div>
|
||||||
|
<div><b>Level owner:</b> @report.LevelOwner</div>
|
||||||
|
<div id="hover-bounds-@report.ReportId" class="hover-region"><b>Hover to see reported region</b></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
subjects[@report.ReportId] = @Html.Raw(report.Players)
|
||||||
|
bounds[@report.ReportId] = @Html.Raw(report.Bounds)
|
||||||
|
images[@report.ReportId] = document.getElementById("game-image-@report.ReportId")
|
||||||
|
canvases[@report.ReportId] = document.getElementById("canvas-subjects-@report.ReportId")
|
||||||
|
canvases[@report.ReportId].width = images[@report.ReportId].offsetWidth;
|
||||||
|
canvases[@report.ReportId].height = images[@report.ReportId].clientHeight;
|
||||||
|
ctx[@report.ReportId] = canvases[@report.ReportId].getContext('2d');
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
<script>
|
||||||
|
function getReportId(name){
|
||||||
|
let split = name.split("-");
|
||||||
|
return split[split.length-1];
|
||||||
|
}
|
||||||
|
const colours = ["#96dd3c", "#ceb424", "#cc0a1d", "#c800cc"];
|
||||||
|
let displayType;
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
document.querySelectorAll(".hover-players").forEach(item => {
|
||||||
|
item.addEventListener('mouseenter', function () {
|
||||||
|
let reportId = getReportId(item.id);
|
||||||
|
displayType = 1;
|
||||||
|
canvases[reportId].className = "photo-subjects";
|
||||||
|
redraw(reportId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".hover-region").forEach(item => {
|
||||||
|
item.addEventListener('mouseenter', function () {
|
||||||
|
let reportId = getReportId(item.id);
|
||||||
|
displayType = 0;
|
||||||
|
canvases[reportId].className = "photo-subjects";
|
||||||
|
redraw(reportId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
document.querySelectorAll(".hover-region, .hover-players").forEach(item => {
|
||||||
|
item.addEventListener('mouseleave', function () {
|
||||||
|
canvases[getReportId(item.id)].className = "photo-subjects hide-subjects";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
function redraw(reportId){
|
||||||
|
let context = ctx[reportId];
|
||||||
|
let canvas = canvases[reportId];
|
||||||
|
let image = images[reportId];
|
||||||
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
let w = canvas.width;
|
||||||
|
let h = canvas.height;
|
||||||
|
|
||||||
|
// halfwidth, halfheight
|
||||||
|
const hw = w / 2;
|
||||||
|
const hh = h / 2;
|
||||||
|
switch (displayType){
|
||||||
|
case 0: {
|
||||||
|
let imageBounds = bounds[reportId];
|
||||||
|
const x1 = imageBounds.Left;
|
||||||
|
const x2 = imageBounds.Right;
|
||||||
|
const y1 = imageBounds.Top;
|
||||||
|
const y2 = imageBounds.Bottom;
|
||||||
|
const scaleX = image.naturalWidth / canvas.width;
|
||||||
|
const scaleY = image.naturalHeight / canvas.height;
|
||||||
|
const bx = canvas.width-(x2/scaleX);
|
||||||
|
const by = canvas.height-(y2/scaleY);
|
||||||
|
const bw = (x2 - x1) / scaleX;
|
||||||
|
const bh = (y2 - y1) / scaleY;
|
||||||
|
context.beginPath();
|
||||||
|
context.lineWidth = 3;
|
||||||
|
context.globalAlpha = 0.6;
|
||||||
|
context.fillStyle = "black";
|
||||||
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
context.clearRect(bx, by, bw, bh);
|
||||||
|
context.globalAlpha = 1.0;
|
||||||
|
context.beginPath();
|
||||||
|
context.lineWidth = 3;
|
||||||
|
context.strokeStyle = "#cc0a1d";
|
||||||
|
context.rect(bx, by, bw, bh);
|
||||||
|
context.stroke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
let subject = subjects[reportId];
|
||||||
|
subject.forEach((s, si) => {
|
||||||
|
const colour = colours[si % 4];
|
||||||
|
|
||||||
|
// Bounding box
|
||||||
|
const x1 = s.Location.Left;
|
||||||
|
const x2 = s.Location.Right;
|
||||||
|
const y1 = s.Location.Top;
|
||||||
|
const y2 = s.Location.Bottom;
|
||||||
|
|
||||||
|
const scaleX = image.naturalWidth / canvas.width;
|
||||||
|
const scaleY = image.naturalHeight / canvas.height;
|
||||||
|
|
||||||
|
|
||||||
|
const bx = canvas.width-(x2/scaleX);
|
||||||
|
const by = canvas.height-(y2/scaleY);
|
||||||
|
const bw = (x2 - x1) / scaleX;
|
||||||
|
const bh = (y2 - y1) / scaleY;
|
||||||
|
|
||||||
|
context.beginPath();
|
||||||
|
context.lineWidth = 3;
|
||||||
|
context.strokeStyle = colour;
|
||||||
|
context.rect(bx, by, bw, bh);
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
// Move into relative coordinates from bounding box
|
||||||
|
context.translate(bx, by);
|
||||||
|
|
||||||
|
// Username label
|
||||||
|
context.font = "16px Lato";
|
||||||
|
context.fillStyle = colour;
|
||||||
|
|
||||||
|
// Text width/height for the label background
|
||||||
|
const tw = context.measureText(s.Name).width;
|
||||||
|
const th = 24;
|
||||||
|
|
||||||
|
// Check if the label will flow off the bottom of the frame
|
||||||
|
const overflowBottom = (y2+tw - 24) > (canvas.width);
|
||||||
|
// Check if the label will flow off the left of the frame
|
||||||
|
const overflowLeft = (x2) < (24);
|
||||||
|
|
||||||
|
// Set alignment
|
||||||
|
context.textAlign = overflowLeft ? "start" : "end";
|
||||||
|
|
||||||
|
// Text x / y
|
||||||
|
const lx = overflowLeft ? -bw + 6 : -6;
|
||||||
|
const ly = overflowBottom ? -bh - 6 : 16;
|
||||||
|
|
||||||
|
// Label background x / y
|
||||||
|
const lbx = overflowLeft ? bw - tw - 12 : 0;
|
||||||
|
const lby = overflowBottom ? bh : -24;
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
context.fillRect(lbx, lby, tw+8, th);
|
||||||
|
|
||||||
|
// Draw text, rotated back upright (canvas draws rotated 180deg)
|
||||||
|
context.fillStyle = "white";
|
||||||
|
context.rotate(Math.PI);
|
||||||
|
context.fillText(s.Name, lx, ly);
|
||||||
|
|
||||||
|
// reset transform
|
||||||
|
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@if (Model.PageNumber != 0)
|
||||||
|
{
|
||||||
|
<a href="/reports/@(Model.PageNumber - 1)@(Model.SearchValue.Length == 0 ? "" : "?name=" + Model.SearchValue)">Previous Page</a>
|
||||||
|
}
|
||||||
|
@(Model.PageNumber + 1) / @(Model.PageAmount)
|
||||||
|
@if (Model.PageNumber < Model.PageAmount - 1)
|
||||||
|
{
|
||||||
|
<a href="/reports/@(Model.PageNumber + 1)@(Model.SearchValue.Length == 0 ? "" : "?name=" + Model.SearchValue)">Next Page</a>
|
||||||
|
}
|
65
ProjectLighthouse/Pages/ReportsPage.cshtml.cs
Normal file
65
ProjectLighthouse/Pages/ReportsPage.cshtml.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Pages;
|
||||||
|
|
||||||
|
public class ReportsPage : BaseLayout
|
||||||
|
{
|
||||||
|
|
||||||
|
public int PageAmount;
|
||||||
|
|
||||||
|
public int PageNumber;
|
||||||
|
|
||||||
|
public int ReportCount;
|
||||||
|
|
||||||
|
public List<GriefReport> Reports;
|
||||||
|
|
||||||
|
public string SearchValue;
|
||||||
|
|
||||||
|
public ReportsPage([NotNull] Database database) : base(database)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name)) name = "";
|
||||||
|
|
||||||
|
this.SearchValue = name.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
this.ReportCount = await this.Database.Reports.Include(r => r.ReportingPlayer).CountAsync(r => r.ReportingPlayer.Username.Contains(this.SearchValue));
|
||||||
|
|
||||||
|
this.PageNumber = pageNumber;
|
||||||
|
this.PageAmount = Math.Max(1, (int) Math.Ceiling((double) this.ReportCount / ServerStatics.PageSize));
|
||||||
|
|
||||||
|
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount)
|
||||||
|
return this.Redirect($"/reports/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
||||||
|
|
||||||
|
this.Reports = await this.Database.Reports.Include(r => r.ReportingPlayer)
|
||||||
|
.Where(r => r.ReportingPlayer.Username.Contains(this.SearchValue))
|
||||||
|
.OrderByDescending(r => r.Timestamp)
|
||||||
|
.Skip(pageNumber * ServerStatics.PageSize)
|
||||||
|
.Take(ServerStatics.PageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (GriefReport r in this.Reports)
|
||||||
|
{
|
||||||
|
r.XmlPlayers = (ReportPlayer[]) JsonSerializer.Deserialize(r.Players, typeof(ReportPlayer[]))!;
|
||||||
|
|
||||||
|
r.XmlBounds = new Marqee()
|
||||||
|
{
|
||||||
|
Rect = (Rectangle) JsonSerializer.Deserialize(r.Bounds, typeof(Rectangle))!,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
@page "/slot/{id:int}"
|
@page "/slot/{id:int}"
|
||||||
@using System.IO
|
|
||||||
@using System.Web
|
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Profiles
|
|
||||||
@model LBPUnion.ProjectLighthouse.Pages.SlotPage
|
@model LBPUnion.ProjectLighthouse.Pages.SlotPage
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
@ -57,36 +54,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui yellow segment">
|
|
||||||
<h1>Comments</h1>
|
|
||||||
@if (Model.Comments.Count == 0)
|
|
||||||
{
|
|
||||||
<p>There are no comments.</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
@foreach (Comment comment in Model.Comments!)
|
@await Html.PartialAsync("Partials/CommentsPartial")
|
||||||
{
|
|
||||||
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000);
|
|
||||||
StringWriter messageWriter = new();
|
|
||||||
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
|
||||||
string decodedMessage = messageWriter.ToString();
|
|
||||||
<div>
|
|
||||||
<b><a href="/user/@comment.PosterUserId">@comment.Poster.Username</a>: </b>
|
|
||||||
@if (comment.Deleted)
|
|
||||||
{
|
|
||||||
<i><span>@decodedMessage</span></i>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span>@decodedMessage</span>
|
|
||||||
}
|
|
||||||
<p>
|
|
||||||
<i>@timestamp.ToString("MM/dd/yyyy @ h:mm tt") UTC</i>
|
|
||||||
</p>
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@if (Model.User != null && Model.User.IsAdmin)
|
@if (Model.User != null && Model.User.IsAdmin)
|
||||||
{
|
{
|
||||||
<div class="ui yellow segment">
|
<div class="ui yellow segment">
|
||||||
|
|
|
@ -7,6 +7,7 @@ using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ public class SlotPage : BaseLayout
|
||||||
{
|
{
|
||||||
public List<Comment> Comments;
|
public List<Comment> Comments;
|
||||||
|
|
||||||
|
public bool CommentsEnabled = ServerSettings.Instance.LevelCommentsEnabled;
|
||||||
|
|
||||||
public Slot Slot;
|
public Slot Slot;
|
||||||
public SlotPage([NotNull] Database database) : base(database)
|
public SlotPage([NotNull] Database database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
@ -33,6 +36,15 @@ public class SlotPage : BaseLayout
|
||||||
|
|
||||||
this.Slot = slot;
|
this.Slot = slot;
|
||||||
|
|
||||||
|
if (this.User == null) return this.Page();
|
||||||
|
|
||||||
|
foreach (Comment c in this.Comments)
|
||||||
|
{
|
||||||
|
Reaction? reaction = await this.Database.Reactions.FirstOrDefaultAsync(r =>
|
||||||
|
r.UserId == this.User.UserId && r.TargetId == c.CommentId);
|
||||||
|
if (reaction != null) c.YourThumb = reaction.Rating;
|
||||||
|
}
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,16 +32,17 @@ public class SlotsPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name)) name = "";
|
if (string.IsNullOrWhiteSpace(name)) name = "";
|
||||||
|
|
||||||
this.SlotCount = await this.Database.Slots.CountAsync(p => p.Name.Contains(name));
|
this.SearchValue = name.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
this.SlotCount = await this.Database.Slots.CountAsync(p => p.Name.Contains(this.SearchValue));
|
||||||
|
|
||||||
this.SearchValue = name;
|
|
||||||
this.PageNumber = pageNumber;
|
this.PageNumber = pageNumber;
|
||||||
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.SlotCount / ServerStatics.PageSize));
|
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.SlotCount / ServerStatics.PageSize));
|
||||||
|
|
||||||
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/slots/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/slots/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
||||||
|
|
||||||
this.Slots = await this.Database.Slots.Include(p => p.Creator)
|
this.Slots = await this.Database.Slots.Include(p => p.Creator)
|
||||||
.Where(p => p.Name.Contains(name))
|
.Where(p => p.Name.Contains(this.SearchValue))
|
||||||
.OrderByDescending(p => p.FirstUploaded)
|
.OrderByDescending(p => p.FirstUploaded)
|
||||||
.Skip(pageNumber * ServerStatics.PageSize)
|
.Skip(pageNumber * ServerStatics.PageSize)
|
||||||
.Take(ServerStatics.PageSize)
|
.Take(ServerStatics.PageSize)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
@page "/user/{userId:int}"
|
@page "/user/{userId:int}"
|
||||||
@using System.IO
|
|
||||||
@using System.Web
|
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
||||||
@using LBPUnion.ProjectLighthouse.Types
|
@using LBPUnion.ProjectLighthouse.Types
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Profiles
|
|
||||||
@model LBPUnion.ProjectLighthouse.Pages.UserPage
|
@model LBPUnion.ProjectLighthouse.Pages.UserPage
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
@ -114,35 +111,4 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@await Html.PartialAsync("Partials/CommentsPartial")
|
||||||
<div class="ui yellow segment">
|
|
||||||
<h1>Comments</h1>
|
|
||||||
@if (Model.ProfileUser.Comments == 0)
|
|
||||||
{
|
|
||||||
<p>There are no comments.</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
@foreach (Comment comment in Model.Comments!)
|
|
||||||
{
|
|
||||||
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000);
|
|
||||||
StringWriter messageWriter = new();
|
|
||||||
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
|
||||||
string decodedMessage = messageWriter.ToString();
|
|
||||||
<div>
|
|
||||||
<b><a href="/user/@comment.PosterUserId">@comment.Poster.Username</a>: </b>
|
|
||||||
@if (comment.Deleted)
|
|
||||||
{
|
|
||||||
<i><span>@decodedMessage</span></i>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span>@decodedMessage</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<i>@timestamp.ToString("MM/dd/yyyy @ h:mm tt") UTC</i>
|
|
||||||
</p>
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -14,6 +15,8 @@ public class UserPage : BaseLayout
|
||||||
{
|
{
|
||||||
public List<Comment>? Comments;
|
public List<Comment>? Comments;
|
||||||
|
|
||||||
|
public bool CommentsEnabled = ServerSettings.Instance.ProfileCommentsEnabled;
|
||||||
|
|
||||||
public bool IsProfileUserHearted;
|
public bool IsProfileUserHearted;
|
||||||
|
|
||||||
public List<Photo>? Photos;
|
public List<Photo>? Photos;
|
||||||
|
@ -34,11 +37,19 @@ public class UserPage : BaseLayout
|
||||||
.Where(p => p.TargetId == userId && p.Type == CommentType.Profile)
|
.Where(p => p.TargetId == userId && p.Type == CommentType.Profile)
|
||||||
.Take(50)
|
.Take(50)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (this.User != null)
|
if (this.User != null)
|
||||||
this.IsProfileUserHearted = await this.Database.HeartedProfiles.FirstOrDefaultAsync
|
{
|
||||||
(u => u.UserId == this.User.UserId && u.HeartedUserId == this.ProfileUser.UserId) !=
|
foreach (Comment c in this.Comments)
|
||||||
|
{
|
||||||
|
Reaction? reaction = await this.Database.Reactions.FirstOrDefaultAsync(r =>
|
||||||
|
r.UserId == this.User.UserId && r.TargetId == c.CommentId);
|
||||||
|
if (reaction != null) c.YourThumb = reaction.Rating;
|
||||||
|
}
|
||||||
|
this.IsProfileUserHearted = await this.Database.HeartedProfiles.FirstOrDefaultAsync(u =>
|
||||||
|
u.UserId == this.User.UserId &&
|
||||||
|
u.HeartedUserId == this.ProfileUser.UserId) !=
|
||||||
null;
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,16 @@ public class UsersPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name)) name = "";
|
if (string.IsNullOrWhiteSpace(name)) name = "";
|
||||||
|
|
||||||
this.UserCount = await this.Database.Users.CountAsync(u => !u.Banned && u.Username.Contains(name));
|
this.SearchValue = name.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
this.UserCount = await this.Database.Users.CountAsync(u => !u.Banned && u.Username.Contains(this.SearchValue));
|
||||||
|
|
||||||
this.SearchValue = name;
|
|
||||||
this.PageNumber = pageNumber;
|
this.PageNumber = pageNumber;
|
||||||
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.UserCount / ServerStatics.PageSize));
|
this.PageAmount = Math.Max(1, (int)Math.Ceiling((double)this.UserCount / ServerStatics.PageSize));
|
||||||
|
|
||||||
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/users/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
if (this.PageNumber < 0 || this.PageNumber >= this.PageAmount) return this.Redirect($"/users/{Math.Clamp(this.PageNumber, 0, this.PageAmount - 1)}");
|
||||||
|
|
||||||
this.Users = await this.Database.Users.Where(u => !u.Banned && u.Username.Contains(name))
|
this.Users = await this.Database.Users.Where(u => !u.Banned && u.Username.Contains(this.SearchValue))
|
||||||
.OrderByDescending(b => b.UserId)
|
.OrderByDescending(b => b.UserId)
|
||||||
.Skip(pageNumber * ServerStatics.PageSize)
|
.Skip(pageNumber * ServerStatics.PageSize)
|
||||||
.Take(ServerStatics.PageSize)
|
.Take(ServerStatics.PageSize)
|
||||||
|
|
|
@ -100,7 +100,7 @@ public static class Program
|
||||||
{
|
{
|
||||||
while (fileQueue.TryDequeue(out string? filename))
|
while (fileQueue.TryDequeue(out string? filename))
|
||||||
{
|
{
|
||||||
LbpFile? file = LbpFile.FromHash(filename.Replace("r/", ""));
|
LbpFile? file = LbpFile.FromHash(filename.Replace("r" + Path.DirectorySeparatorChar, ""));
|
||||||
if (file == null) continue;
|
if (file == null) continue;
|
||||||
|
|
||||||
if (file.FileType == LbpFileType.Jpeg || file.FileType == LbpFileType.Png || file.FileType == LbpFileType.Texture)
|
if (file.FileType == LbpFileType.Jpeg || file.FileType == LbpFileType.Png || file.FileType == LbpFileType.Texture)
|
||||||
|
|
|
@ -37,6 +37,10 @@ public class Comment
|
||||||
public int ThumbsUp { get; set; }
|
public int ThumbsUp { get; set; }
|
||||||
public int ThumbsDown { get; set; }
|
public int ThumbsDown { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
[XmlIgnore]
|
||||||
|
public int YourThumb;
|
||||||
|
|
||||||
public string getComment()
|
public string getComment()
|
||||||
{
|
{
|
||||||
if (!this.Deleted)
|
if (!this.Deleted)
|
||||||
|
|
59
ProjectLighthouse/Types/Reports/GriefReport.cs
Normal file
59
ProjectLighthouse/Types/Reports/GriefReport.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
[XmlRoot("griefReport")]
|
||||||
|
public class GriefReport
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int ReportId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("griefTypeId")]
|
||||||
|
public GriefType Type { get; set; }
|
||||||
|
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
[XmlElement("visibleBadge")]
|
||||||
|
public VisiblePlayer[] XmlVisiblePlayers { get; set; }
|
||||||
|
|
||||||
|
public string VisiblePlayers { get; set; }
|
||||||
|
|
||||||
|
public int ReportingPlayerId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(ReportingPlayerId))]
|
||||||
|
public User ReportingPlayer { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
[XmlElement("player")]
|
||||||
|
public ReportPlayer[] XmlPlayers { get; set; }
|
||||||
|
|
||||||
|
public string Players { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("griefStateHash")]
|
||||||
|
public string GriefStateHash { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("levelOwner")]
|
||||||
|
public string LevelOwner { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("initialStateHash")]
|
||||||
|
public string InitialStateHash { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("jpegHash")]
|
||||||
|
public string JpegHash { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("levelId")]
|
||||||
|
public int LevelId { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("levelType")]
|
||||||
|
public string LevelType { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
[XmlElement("marqee")]
|
||||||
|
public Marqee XmlBounds { get; set; }
|
||||||
|
|
||||||
|
public string Bounds { get; set; }
|
||||||
|
|
||||||
|
}
|
23
ProjectLighthouse/Types/Reports/GriefType.cs
Normal file
23
ProjectLighthouse/Types/Reports/GriefType.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
public enum GriefType
|
||||||
|
{
|
||||||
|
[XmlEnum("1")]
|
||||||
|
Obscene = 1,
|
||||||
|
[XmlEnum("2")]
|
||||||
|
Mature = 2,
|
||||||
|
[XmlEnum("3")]
|
||||||
|
Offensive = 3,
|
||||||
|
[XmlEnum("4")]
|
||||||
|
Violence = 4,
|
||||||
|
[XmlEnum("5")]
|
||||||
|
Illegal = 5,
|
||||||
|
[XmlEnum("6")]
|
||||||
|
Unknown = 6,
|
||||||
|
[XmlEnum("7")]
|
||||||
|
Tos = 7,
|
||||||
|
[XmlEnum("8")]
|
||||||
|
Other = 8,
|
||||||
|
}
|
10
ProjectLighthouse/Types/Reports/Marqee.cs
Normal file
10
ProjectLighthouse/Types/Reports/Marqee.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
[XmlRoot("marqee")]
|
||||||
|
public class Marqee
|
||||||
|
{
|
||||||
|
[XmlElement("rect")]
|
||||||
|
public Rectangle Rect { get; set; }
|
||||||
|
}
|
23
ProjectLighthouse/Types/Reports/Rectangle.cs
Normal file
23
ProjectLighthouse/Types/Reports/Rectangle.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
public class Rectangle
|
||||||
|
{
|
||||||
|
[XmlAttribute("t")]
|
||||||
|
public int Top { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("l")]
|
||||||
|
public int Left { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("b")]
|
||||||
|
public int Bottom { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("r")]
|
||||||
|
public int Right { get; set; }
|
||||||
|
|
||||||
|
}
|
23
ProjectLighthouse/Types/Reports/ReportPlayer.cs
Normal file
23
ProjectLighthouse/Types/Reports/ReportPlayer.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
[XmlRoot("player")]
|
||||||
|
public class ReportPlayer
|
||||||
|
{
|
||||||
|
[XmlElement("id")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("rect")]
|
||||||
|
public Rectangle Location { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("reporter")]
|
||||||
|
public bool Reporter { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("ingamenow")]
|
||||||
|
public bool InGame { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("playerNumber")]
|
||||||
|
public int PlayerNum { get; set; }
|
||||||
|
|
||||||
|
}
|
22
ProjectLighthouse/Types/Reports/VisiblePlayer.cs
Normal file
22
ProjectLighthouse/Types/Reports/VisiblePlayer.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Reports;
|
||||||
|
|
||||||
|
[XmlRoot("visibleBadge")]
|
||||||
|
[Serializable]
|
||||||
|
public class VisiblePlayer
|
||||||
|
{
|
||||||
|
[XmlElement("id")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("hash")]
|
||||||
|
public string Hash { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("rect")]
|
||||||
|
public Rectangle Bounds { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
}
|
|
@ -190,8 +190,8 @@ public class User
|
||||||
LbpSerializer.BlankElement("photos") +
|
LbpSerializer.BlankElement("photos") +
|
||||||
LbpSerializer.StringElement("heartCount", this.Hearts) +
|
LbpSerializer.StringElement("heartCount", this.Hearts) +
|
||||||
LbpSerializer.StringElement("yay2", this.YayHash) +
|
LbpSerializer.StringElement("yay2", this.YayHash) +
|
||||||
LbpSerializer.StringElement("boo2", this.YayHash) +
|
LbpSerializer.StringElement("boo2", this.BooHash) +
|
||||||
LbpSerializer.StringElement("meh2", this.YayHash);
|
LbpSerializer.StringElement("meh2", this.MehHash);
|
||||||
this.ClientsConnected.Serialize();
|
this.ClientsConnected.Serialize();
|
||||||
|
|
||||||
return LbpSerializer.TaggedStringElement("user", user, "type", "user");
|
return LbpSerializer.TaggedStringElement("user", user, "type", "user");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue