Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
SakuraIsayeki committed Jun 15, 2024
2 parents 450ed37 + b7ccef9 commit b207534
Show file tree
Hide file tree
Showing 17 changed files with 218 additions and 86 deletions.
14 changes: 9 additions & 5 deletions WowsKarma.Api/Controllers/Admin/ModActionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ public ModActionController(ModService service)
/// </summary>
/// <param name="id">ID of ModAction to fetch.</param>
[HttpGet("{id:guid}"), AllowAnonymous]
public async Task<PostModActionDTO> Fetch(Guid id) => (await _service.GetModActionAsync(id)).Adapt<PostModActionDTO>();
public async Task<PostModActionDTO> Fetch(Guid id)
{
using PostModAction? pma = await _service.GetModActionAsync(id);
return pma.Adapt<PostModActionDTO>();
}

/// <summary>
/// Lists ModActions by Post or User IDs.
Expand All @@ -39,7 +43,7 @@ public ModActionController(ModService service)
[HttpGet("list"), AllowAnonymous, ProducesResponseType(typeof(IEnumerable<PostModActionDTO>), 200), ProducesResponseType(204)]
public IActionResult List([FromQuery] Guid postId = default, [FromQuery] uint userId = default)
{
PostModAction[] modActions = [];
PostModAction[] modActions;

if (postId != default)
{
Expand All @@ -55,8 +59,8 @@ public IActionResult List([FromQuery] Guid postId = default, [FromQuery] uint us
}

return modActions is []
? base.StatusCode(204)
: base.StatusCode(200, modActions.Adapt<IEnumerable<PostModActionDTO>>());
? NoContent()
: Ok(modActions.Adapt<IEnumerable<PostModActionDTO>>());
}

/// <summary>
Expand All @@ -72,7 +76,7 @@ public IActionResult List([FromQuery] Guid postId = default, [FromQuery] uint us
public async Task<IActionResult> Submit([FromBody] PostModActionDTO modAction,
[FromServices] PostService postService)
{
Post post = postService.GetPost(modAction.PostId) ?? throw new InvalidOperationException("Post ID is invalid.");
using Post post = postService.GetPost(modAction.PostId) ?? throw new InvalidOperationException("Post ID is invalid.");
uint modId = uint.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? throw new BadHttpRequestException("Missing NameIdentifier claim."));

if ((post.AuthorId == modId || post.PlayerId == modId) && !User.IsInRole(ApiRoles.Administrator))
Expand Down
4 changes: 2 additions & 2 deletions WowsKarma.Api/Controllers/PostController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public async Task<IActionResult> CreatePost(

try
{
Post created = await _postService.CreatePostAsync(post, replay, ignoreChecks);
using Post created = await _postService.CreatePostAsync(post, replay, ignoreChecks);
return StatusCode(201, created.Id);
}
catch (ArgumentException)
Expand Down Expand Up @@ -320,7 +320,7 @@ public async Task<IActionResult> EditPost([FromBody] PlayerPostDTO post, [FromQu
}
catch (ArgumentException e)
{
return StatusCode(400, e.ToString());
return BadRequest(e);
}
}

Expand Down
17 changes: 16 additions & 1 deletion WowsKarma.Api/Data/Models/Notifications/NotificationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,34 @@

namespace WowsKarma.Api.Data.Models.Notifications;

/// <inheritdoc />
public abstract record NotificationBase : INotification
{
/// <inheritdoc />
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; }

/// <inheritdoc />
public uint AccountId { get; init; }
public virtual Player Account { get; init; }

/// <summary>
/// The player account associated with the notification.
/// </summary>
public virtual Player Account { get; init; } = null!;

/// <inheritdoc />
public abstract NotificationType Type { get; private protected init; }

/// <inheritdoc />
public DateTimeOffset EmittedAt { get; private protected init; } = DateTimeOffset.UtcNow;

/// <inheritdoc />
public DateTimeOffset? AcknowledgedAt { get; set; }

/// <summary>
/// Converts the notification to a DTO.
/// </summary>
/// <returns>The DTO representation of the notification.</returns>
public virtual NotificationBaseDTO ToDTO() => new()
{
Id = Id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public record PlatformBanNotification : NotificationBase

[Required]
public Guid BanId { get; set; }
public PlatformBan Ban { get; set; }
public PlatformBan Ban { get; set; } = null!;


public override PlatformBanNotificationDTO ToDTO() => new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@

namespace WowsKarma.Api.Data.Models.Notifications;

public record PostModDeletedNotification : NotificationBase
/// <summary>
/// Represents a notification that a post was deleted by a moderator.
/// </summary>
public sealed record PostModDeletedNotification : NotificationBase, IDisposable
{
/// <inheritdoc />
public override NotificationType Type { get; private protected init; } = NotificationType.PostModDeleted;

public virtual Guid ModActionId { get; set; }
public virtual PostModAction ModAction { get; set; }

/// <summary>
/// The unique identifier of the moderation action that deleted the post.
/// </summary>
public Guid ModActionId { get; set; }

/// <summary>
/// The moderation action that deleted the post.
/// </summary>
public PostModAction ModAction { get; set; } = null!;


public static PostModDeletedNotification FromModAction(PostModAction modAction) => modAction?.ActionType is not ModActionType.Deletion
? throw new ArgumentException(null, nameof(modAction))
: new()
Expand All @@ -21,6 +32,7 @@ public static PostModDeletedNotification FromModAction(PostModAction modAction)
ModAction = modAction
};

/// <inheritdoc />
public override PostModDeletedNotificationDTO ToDTO() => new()
{
Id = Id,
Expand All @@ -31,4 +43,10 @@ public static PostModDeletedNotification FromModAction(PostModAction modAction)
ModActionId = ModActionId,
Type = Type
};

/// <inheritdoc />
public void Dispose()
{
ModAction.Dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

namespace WowsKarma.Api.Data.Models.Notifications;

public record PostModEditedNotification : NotificationBase
public sealed record PostModEditedNotification : NotificationBase, IDisposable
{
public override NotificationType Type { get; private protected init; } = NotificationType.PostModEdited;

public virtual Guid ModActionId { get; set; }
public virtual PostModAction ModAction { get; set; }
public Guid ModActionId { get; set; }
public PostModAction ModAction { get; set; } = null!;


public static PostModDeletedNotification FromModAction(PostModAction modAction) => modAction?.ActionType is not ModActionType.Deletion
Expand All @@ -31,4 +31,9 @@ public static PostModDeletedNotification FromModAction(PostModAction modAction)
ModActionId = ModActionId,
Type = Type
};

public void Dispose()
{
ModAction.Dispose();
}
}
88 changes: 74 additions & 14 deletions WowsKarma.Api/Data/Models/Post.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,98 @@

namespace WowsKarma.Api.Data.Models;

public sealed record Post : ITimestamped
/// <summary>
/// Represents a player post, sent by one player to another.
/// </summary>
public sealed record Post : ITimestamped, IDisposable
{
/// <summary>
/// The unique identifier of the post.
/// </summary>
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; }

[Required]
public uint PlayerId { get; init; }
[Required]
public Player Player { get; init; } = null!;
[Required]
public uint AuthorId { get; init; }
[Required]
public Player Author { get; init; } = null!;
/// <summary>
/// The unique identifier of the player who received the post.
/// </summary>
[Required] public uint PlayerId { get; init; }

/// <summary>
/// The player who received the post.
/// </summary>
[Required] public Player Player { get; init; } = null!;

/// <summary>
/// The unique identifier of the player who sent the post.
/// </summary>
[Required] public uint AuthorId { get; init; }

/// <summary>
/// The player who sent the post.
/// </summary>
[Required] public Player Author { get; init; } = null!;

/// <summary>
/// The unique identifier of the post's parent post.
/// </summary>
public PostFlairs Flairs { get; set; }

/// <summary>
/// The parsed flairs of the post.
/// </summary>
public PostFlairsParsed? ParsedFlairs => Flairs.ParseFlairsEnum();

[Required]
public string Title { get; set; } = "";
[Required]
public string Content { get; set; } = "";
/// <summary>
/// The title of the post.
/// </summary>
[Required] public string Title { get; set; } = "";

/// <summary>
/// The content of the post.
/// </summary>
[Required] public string Content { get; set; } = "";

/// <summary>
/// The unique identifier of the replay associated with the post.
/// </summary>
public Guid? ReplayId { get; set; }

/// <summary>
/// The replay associated with the post.
/// </summary>
public Replay? Replay { get; set; }

// Computed by DB Engine (hopefully)

/// <summary>
/// The date and time the post was created.
/// </summary>
public DateTimeOffset CreatedAt { get; init; }

/// <summary>
/// The date and time the post was last updated.
/// </summary>
public DateTimeOffset UpdatedAt { get; set; }

/// <summary>
/// Whether this post is able to negatively affect the receiving player's karma.
/// </summary>
public bool NegativeKarmaAble { get; internal set; }

/// <summary>
/// Whether this post is locked for edits.
/// </summary>
public bool ReadOnly { get; set; }


/// <summary>
/// Whether this post was locked by mods, and inaccessible on the platform.
/// </summary>
public bool ModLocked { get; set; }


/// <inheritdoc />
public void Dispose()
{
Replay?.Dispose();
}
}
7 changes: 6 additions & 1 deletion WowsKarma.Api/Data/Models/PostModAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace WowsKarma.Api.Data.Models;
/**
* Conversion Mapping done in <see cref="Utilities.Conversions"/>.
**/
public sealed record PostModAction
public sealed record PostModAction : IDisposable
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; }
Expand All @@ -20,4 +20,9 @@ public sealed record PostModAction
public uint ModId { get; init; }

public string Reason { get; set; } = "";

public void Dispose()
{
Post.Dispose();
}
}
13 changes: 9 additions & 4 deletions WowsKarma.Api/Data/Models/Replays/Replay.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json;
using Nodsoft.WowsReplaysUnpack.Core.Models;

namespace WowsKarma.Api.Data.Models.Replays;


public sealed record Replay
public sealed record Replay : IDisposable
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; init; }
Expand All @@ -22,13 +23,17 @@ public sealed record Replay
/*
* Replay content (stored JSON)
*/

[Column(TypeName = "jsonb")]
public ArenaInfo ArenaInfo { get; set; } = null!;
public JsonDocument ArenaInfo { get; set; } = null!;

[Column(TypeName = "jsonb")]
public IEnumerable<ReplayPlayer> Players { get; set; } = [];

[Column(TypeName = "jsonb")]
public IEnumerable<ReplayChatMessage> ChatMessages { get; set; } = [];

/// <inheritdoc />
public void Dispose()
{
ArenaInfo.Dispose();
}
}
6 changes: 3 additions & 3 deletions WowsKarma.Api/Services/MinimapRenderingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public async Task RenderPostReplayMinimapAsync(Guid postId, bool force = false,
{
_logger.LogDebug("Rendering minimap for post {postId}.", postId);

Post post = await _context.Posts.Include(static r => r.Replay).FirstOrDefaultAsync(p => p.Id == postId, cancellationToken: ct)
using Post post = await _context.Posts.Include(static r => r.Replay).FirstOrDefaultAsync(p => p.Id == postId, cancellationToken: ct)
?? throw new ArgumentException($"Post with ID {postId} does not exist.", nameof(postId));

if (!force && post.Replay is null or { MinimapRendered: true })
Expand Down Expand Up @@ -92,7 +92,7 @@ private async ValueTask UploadReplayMinimapAsync(Guid replayId, byte[] content,
{
_logger.LogDebug("Uploading minimap for replay {replayId} to Azure storage.", replayId);

Post post = await _context.Posts.Include(static r => r.Replay).FirstOrDefaultAsync(p => p.Replay.Id == replayId, ct)
using Post post = await _context.Posts.Include(static r => r.Replay).FirstOrDefaultAsync(p => p.Replay.Id == replayId, ct)

Check warning on line 95 in WowsKarma.Api/Services/MinimapRenderingService.cs

View workflow job for this annotation

GitHub Actions / Build & Package API (preview) / Build & Package .NET Project

Dereference of a possibly null reference.
?? throw new ArgumentException($"Post with replay ID {replayId} does not exist.", nameof(replayId));

if (!force && post.Replay is null or { MinimapRendered: true })
Expand Down Expand Up @@ -146,7 +146,7 @@ public async Task ReprocessAllMinimapsAsync(DateTime? start, DateTime? end, bool

public async ValueTask<Uri> GenerateMinimapUriAsync(Guid replayId)
{
Replay replay = await _context.Replays.FindAsync(replayId) ?? throw new ArgumentException("No replay was found for specified GUID.", nameof(replayId));
using Replay replay = await _context.Replays.FindAsync(replayId) ?? throw new ArgumentException("No replay was found for specified GUID.", nameof(replayId));
return _containerClient.GetBlobClient(replay.BlobName).Uri;
}
}
Loading

0 comments on commit b207534

Please sign in to comment.