Skip to content

Commit

Permalink
Migrate frontend to Blazor (#992)
Browse files Browse the repository at this point in the history
* Initial blazor implementation

* Remove template files

* Add developmentSettings to gitignore and allow wwwroot in blazor project

* Add MudBlazor to _Host.cshtml

* Initial landing page implementation

* Migrate Modix startup to Modix.Web
Add Authorization policies based on AuthorizationClaim enum
Add crude implementation of DiscordUserService

* Implement navbar with separate views depending on authorization state

* Initial implementation of UserLookup page

* Initial implementation of Commands page

* Initial implementation of Stats page

* Initial implementation of Tags page

* Initial implementation of Promotions page

* Run AuthorizationService.OnAuthenticatedAsync in MainLayout instead
ClaimsTransformation uses a different service scope from the blazor circuit - which leads to AuthorizationService properties not being set properly for the authenticated user
Also remove redundant authorization setup in startup

* Initial implementation of Logs/Infractions page

* Use dropdown for 'Type' in infractions grid

* Remove unnecessary comments

* Move navbar from MainLayout to separate component

* Change page titles

* Get SocketGuild from SocketGuildUser instead

* Use OnAfterRenderAsync instead to avoid duplicate DB calls

* Implement guild selection
Remove ClaimsTransformationService
Overall improvements to navbar
Move logic for adding claims to App.razor
Read selected guild from cookie and pass it down the chain

* Remove <AuthorizeView> etc in favor of Authorize attribute

* Use OnAfterRenderAsync to avoid unnecessary execution of db calls etc

* Use [Authorize] attribute to avoid rendering of the page whatsoever

* Fix icon colors of navbar in the logged out state

* Use middleware to assign claims rather than have it in App.razor
The call to AuthorizationService.OnAuthenticatedAsync is still needed in App.razor to be able to set the values in the correct scope.

* Move logout button to dropdown menu
Small tidy up

* Rename LocalStorageService -> CookieService

* Show current user when first visiting UserLookup
Slight improvements with nullability
Remove commented code

* Move models to Models folder

* Propagate CurrentUserId down to components via SessionState to avoid reading from user claims constantly

* Fix issue with filters not resetting properly

* Initially select nothing in the dropdown for InfractionType (nothing was actually initially selected, it just appeared to be)

* Force cookie to be created on root path

* Continue with first found guild if no guild cookie was found

* Case-insensitive filtering on Tags page

* Improve feedback when Tag creation fails (or succeeds)

* Allow null/empty comments for promotions
Use MudSpacer instead of manual flex-grow

* Disable editing comments for closed campaigns
Update UI after editing comment
Better feedback after editing comment

* Initial implementation of Configuration (Claims)

* Small touchup

* Remove unnecessary stuff in MainLayout

* Modify DesignatedRoleService API slightly to return the id of the created entity

* Initial implementation of Configuration (Roles)

* Slight improvement to styling of menu for Configuration and Logs

* Modify DesignatedChannelService API slightly to return the id of the created entity

* Make IndividualDesignation component generic

* Initial implementation of Configuration (Channels)

* Slight improvements to Channels/Roles configuration pages

* Make Autocomplete component generic

* Move ModixUser and RoleInformation into Common

* Modify interface of PromotionsService to return the PromotionActionSummary after updating a comment
Fix bug in Promotions UI where you could edit a comment and inadvertently have two active ones as a result

* Implement possibility of passing query parameters to infractions page, such as ?id=<infraction_id> and ?subject=<username>
Also redirect from /infractions to /logs/infractions

* Add possibility of accepting/rejecting/forcing a campaign as well as link to the infractions page for the campaign subject

* Simplify styling on Infractions page

* Use iconbuttons instead for accept/reject

* Re-use existing extension method for getting full username

* Initial implementation of Logs/DeletedMessages page

* Fix bug with filtering DeletedMessageEntity
- When Batch is set, use that to filter on CreatedBy(Id)
- Move AsExpandable() to sourceQuery

* Set _currentContext before potential early bail
Close dialog on error

* Show role color if relevant in Tags grid

* Enable query parameter for Tags page

* Use generic version of DialogParameters when instantiating Dialogs

* Persist infraction table settings to local storage
Move cookie constants into separate class

* Slight styling improvements to stats page

* Fix/consolidate date string formatting

* Responsive navmenu

* Responsive commands page

* Better styling for DeletedMessages

* Better styling for Infractions page

* Responsive styling for Configuration (Claims)

* Responsive styling for UserLookup

* Slightly improve styling for landing and promotions pages

* Remove unnecessary elements from landing page

* Change Primary color to match the vue website

* Fix weird flickering issue when navigating via anchors

* Use MudGrid instead of MudDrawer
Improve styling on Commands page
Fix element Ids not being navigable to because of having spaces in them

* Rename DiscordUserService to DiscordHelper

* Make it possible to switch between Vue and Blazor via config flag 'UseBlazor'
Convert Startup based startup to minimal hosting model in Modix
Make Modix.Web into a class library

* Remove appsettings from Modix.Web

* Add NoDefaultLaunchSettingsFile to avoid re-creating launchSettings.json

* Remove LocalStorageService in favor of reading cookies upon first HTTP request to the site and propagating settings through SessionState instead

* Remove unused package/project references

* Add favicon

* Use Roles instead of Policy authorization

* Improve grid size for bigger screens

* Implement comment creation box to show when the user has yet to vote on a campaign

* Fit content to screen width on Tags page

* Minor touchups

* Remove unused css

* Fix more nullability stuff
Some of it might technically be impossible scenarios, but "meh" :)

* Fixed AutoComplete after breaking it by not invoking the RenderFragment after fixing nullability

* Disable button/comment box on promotion creation page if no "next rank" is available

* Fix compilation issue

* Upgrade packages to stable version to fix startup issue

* Fix ItemTemplate issue causing preview to be empty

* Remove TODO comments, add error message when fetching of campaign details fails

* Make Title an optional parameter on the AutoComplete component and remove the usage of it on the UserLookup page

* Remove background color from UserLookup

* Apply small gap rule on small screen sizes (that aren't quite xs yet) to avoid overlapping between elements

* Improved styling for toolbar on Infractions page

* Improved styling for toolbar on Tags page

* Fix css not being served from the correct folder

* Improve styling for Promotions page on small resolutions

* Update NuGet packages and change from deprecated APIs/properties

* Remove UseStaticFiles call in favor of linking to static files correctly in the _Host file

* Update Dockerfile to use .net8 instead of .net8-preview image

* Update more NuGet packages to .NET pinned versions and cleanup some of the version references in projects

* Use maxcpucount:1 in Dockerfile to avoid files being used by other processes error

* Slight mobile styling tweaks to Infractions and Tags page

* Reduce reliance on inline styling

* Update default value for UseBlazor setting in deployment configuration files

* Format code

* Improved styling on CreatePromotion page on small resolutions

* Improved styling for Configuration/Logs pages

* Add margin to make it look a bit nicer when scrolling to the bottom of the page

* Tweak styling for large resolutions on Stats and Logs pages
  • Loading branch information
calledude authored Mar 26, 2024
1 parent 6c35da2 commit 045decc
Show file tree
Hide file tree
Showing 78 changed files with 4,217 additions and 272 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bld/
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
wwwroot/
!Modix.Web/wwwroot/
dataprotection/

# VS Code
Expand Down Expand Up @@ -261,5 +262,5 @@ Modix/config
/Modix/Properties/launchSettings.json

*.DotSettings
Modix/developmentSettings\.json
Modix/logs/*
**/developmentSettings\.json
**/logs/*
47 changes: 23 additions & 24 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,28 @@
<ItemGroup>
<PackageReference Update="Discord.Net" Version="3.11.0" />

<PackageReference Update="Microsoft.EntityFrameworkCore" Version="8.0.0-preview.4.*" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Design" Version="8.0.0-preview.4.*"/>
<PackageReference Update="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0-preview.4.*" />
<PackageReference Update="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0-preview.4" />
<PackageReference Update="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Design" Version="8.0.0"/>
<PackageReference Update="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
<PackageReference Update="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />

<PackageReference Update="Nito.AsyncEx.Coordination" Version="5.1.2" />

<PackageReference Update="AspNet.Security.OAuth.Discord" Version="7.0.2" />
<PackageReference Update="AspNet.Security.OAuth.Discord" Version="8.0.0" />

<PackageReference Update="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Caching.Memory" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.DependencyInjection" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Hosting" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Http" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Http.Polly" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Logging.Console" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Options" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0-preview.6.*" />
<PackageReference Update="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0" />
<PackageReference Update="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Http.Polly" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Update="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.*" />

<PackageReference Update="Newtonsoft.Json" Version="13.0.3" />
Expand All @@ -44,13 +44,12 @@

<PackageReference Update="LinqKit.Microsoft.EntityFrameworkCore" Version="7.1.4" />

<PackageReference Update="Serilog" Version="3.0.1" />
<PackageReference Update="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Update="Serilog.Expressions" Version="3.4.1" />
<PackageReference Update="Serilog.Extensions.Logging" Version="7.0.0" />
<PackageReference Update="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Update="Serilog" Version="3.1.1" />
<PackageReference Update="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Update="Serilog.Expressions" Version="4.0.0" />
<PackageReference Update="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Update="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Update="Serilog.Sinks.Seq" Version="5.2.2" />
<PackageReference Update="Serilog.Sinks.Seq" Version="6.0.0" />

<PackageReference Update="Humanizer.Core" Version="2.14.1" />

Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0-preview AS base
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0-preview AS dotnet-build-base
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS dotnet-build-base
WORKDIR /src
RUN printf 'Package: nodejs\nPin: origin deb.nodesource.com\nPin-Priority: 600\n' > /etc/apt/preferences.d/nodesource
RUN apt-get update && apt-get install curl -y \
Expand All @@ -15,13 +15,13 @@ RUN dotnet restore Modix.sln
COPY . .

FROM dotnet-build-base AS dotnet-build
RUN dotnet build -c Release --no-restore Modix.sln
RUN dotnet build -maxcpucount:1 -c Release --no-restore Modix.sln

FROM dotnet-build as dotnet-test
RUN dotnet test -c Release --no-build --no-restore Modix.sln

FROM dotnet-build AS publish
RUN dotnet publish -c Release --no-build --no-restore -o /app Modix/Modix.csproj
RUN dotnet publish -maxcpucount:1 -c Release --no-build --no-restore -o /app Modix/Modix.csproj

FROM base AS final
COPY --from=publish /app .
Expand Down
2 changes: 1 addition & 1 deletion Modix.Bot.Test/Modix.Bot.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Discord.Net" Version="2.4.0" />
<PackageReference Include="Discord.Net" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="NUnit"/>
Expand Down
4 changes: 2 additions & 2 deletions Modix.Data.Test/Assertions/DbContextSequenceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ private static ResettableSequenceValueGenerator<TProperty> GetGetResettableSeque
.GetOrAdd(property, entity, valueGeneratorConstructor);
}

private static readonly Dictionary<Type, Func<IProperty, IEntityType, ValueGenerator>> _valueGeneratorConstructorsByValueType
= new Dictionary<Type, Func<IProperty, IEntityType, ValueGenerator>>()
private static readonly Dictionary<Type, Func<IProperty, ITypeBase, ValueGenerator>> _valueGeneratorConstructorsByValueType
= new Dictionary<Type, Func<IProperty, ITypeBase, ValueGenerator>>()
{
[typeof(long)] = (p, e) => new ResettableInt64SequenceValueGenerator()
};
Expand Down
5 changes: 2 additions & 3 deletions Modix.Data/Models/Core/ModixConfig.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;

namespace Modix.Data.Models.Core
namespace Modix.Data.Models.Core
{
public class ModixConfig
{
Expand Down Expand Up @@ -31,5 +29,6 @@ public class ModixConfig
public string WebsiteBaseUrl { get; set; } = "https://mod.gg";

public bool EnableStatsd { get; set; }
public bool UseBlazor { get; set; }
}
}
10 changes: 8 additions & 2 deletions Modix.Data/Models/Moderation/DeletedMessageSearchCriteria.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,16 @@ public static IQueryable<DeletedMessageEntity> FilterBy(this IQueryable<DeletedM
x => ReusableQueries.StringContainsUser.Invoke(x.Author, criteria!.Author!),
!string.IsNullOrWhiteSpace(criteria?.Author))
.FilterBy(
x => x.CreateAction.CreatedById == criteria!.CreatedById,
x => x.Batch == null
? x.CreateAction.CreatedById == criteria!.CreatedById
: x.Batch.CreateAction.CreatedById == criteria!.CreatedById,
criteria?.CreatedById != null)
.FilterBy(
x => ReusableQueries.StringContainsUser.Invoke(x.CreateAction.CreatedBy!, criteria!.CreatedBy!),
x => ReusableQueries.StringContainsUser.Invoke(
x.Batch == null
? x.CreateAction.CreatedBy!
: x.Batch.CreateAction.CreatedBy,
criteria!.CreatedBy!),
!string.IsNullOrWhiteSpace(criteria?.CreatedBy))
.FilterBy(
x => ReusableQueries.DbCaseInsensitiveContains.Invoke(x.Content, criteria!.Content!),
Expand Down
3 changes: 1 addition & 2 deletions Modix.Data/Repositories/DeletedMessageRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,12 @@ public async Task CreateAsync(
public async Task<RecordsPage<DeletedMessageSummary>> SearchSummariesPagedAsync(
DeletedMessageSearchCriteria searchCriteria, IEnumerable<SortingCriteria> sortingCriteria, PagingCriteria pagingCriteria)
{
var sourceQuery = ModixContext.Set<DeletedMessageEntity>().AsNoTracking();
var sourceQuery = ModixContext.Set<DeletedMessageEntity>().AsNoTracking().AsExpandable();

var filteredQuery = sourceQuery
.FilterBy(searchCriteria);

var pagedQuery = filteredQuery
.AsExpandable()
.Select(DeletedMessageSummary.FromEntityProjection)
.SortBy(sortingCriteria, DeletedMessageSummary.SortablePropertyMap)
.OrderThenBy(x => x.MessageId, SortDirection.Ascending)
Expand Down
2 changes: 1 addition & 1 deletion Modix.Services.Test/Modix.Services.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
Expand Down
25 changes: 12 additions & 13 deletions Modix.Services/Core/DesignatedChannelService.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Discord;

using Serilog;

using Modix.Data.Models.Core;
using Modix.Data.Repositories;
using System.Threading;
using Serilog;

namespace Modix.Services.Core
{
Expand All @@ -25,7 +22,7 @@ public interface IDesignatedChannelService
/// <param name="channel">The channel to be assigned.</param>
/// <param name="type">The type of designation to be assigned.</param>
/// <returns>A <see cref="Task"/> that will complete when the operation has completed.</returns>
Task AddDesignatedChannelAsync(IGuild guild, IMessageChannel channel, DesignatedChannelType type);
Task<long> AddDesignatedChannelAsync(IGuild guild, IMessageChannel channel, DesignatedChannelType type);

/// <summary>
/// Unassigns a channel's previously given designation, for a given guild.
Expand Down Expand Up @@ -117,7 +114,7 @@ public DesignatedChannelService(IDesignatedChannelMappingRepository designatedCh
}

/// <inheritdoc />
public async Task AddDesignatedChannelAsync(IGuild guild, IMessageChannel logChannel, DesignatedChannelType type)
public async Task<long> AddDesignatedChannelAsync(IGuild guild, IMessageChannel logChannel, DesignatedChannelType type)
{
AuthorizationService.RequireAuthenticatedUser();
AuthorizationService.RequireClaims(AuthorizationClaim.DesignatedChannelMappingCreate);
Expand All @@ -135,7 +132,7 @@ public async Task AddDesignatedChannelAsync(IGuild guild, IMessageChannel logCha
throw new InvalidOperationException($"{logChannel.Name} in {guild.Name} is already assigned to {type}");
}

await DesignatedChannelMappingRepository.CreateAsync(new DesignatedChannelMappingCreationData()
var id = await DesignatedChannelMappingRepository.CreateAsync(new DesignatedChannelMappingCreationData()
{
GuildId = guild.Id,
ChannelId = logChannel.Id,
Expand All @@ -144,6 +141,8 @@ await DesignatedChannelMappingRepository.CreateAsync(new DesignatedChannelMappin
});

transaction.Commit();

return id;
}
}

Expand Down Expand Up @@ -205,11 +204,11 @@ public Task<bool> AnyDesignatedChannelAsync(ulong guildId, DesignatedChannelType
/// <inheritdoc />
public Task<IReadOnlyCollection<ulong>> GetDesignatedChannelIdsAsync(ulong guildId, DesignatedChannelType type)
=> DesignatedChannelMappingRepository.SearchChannelIdsAsync(new DesignatedChannelMappingSearchCriteria()
{
GuildId = guildId,
Type = type,
IsDeleted = false
});
{
GuildId = guildId,
Type = type,
IsDeleted = false
});

/// <inheritdoc />
public async Task<IReadOnlyCollection<IMessageChannel>> GetDesignatedChannelsAsync(IGuild guild, DesignatedChannelType type)
Expand Down
8 changes: 5 additions & 3 deletions Modix.Services/Core/DesignatedRoleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IDesignatedRoleService
/// <param name="roleId">The Discord snowflake ID of the role being designated</param>
/// <param name="type">The type of designation to be made</param>
/// <returns>A <see cref="Task"/> that will complete when the operation has completed.</returns>
Task AddDesignatedRoleAsync(ulong guildId, ulong roleId, DesignatedRoleType type);
Task<long> AddDesignatedRoleAsync(ulong guildId, ulong roleId, DesignatedRoleType type);

/// <summary>
/// Unassigns a role's previously given designation.
Expand Down Expand Up @@ -95,7 +95,7 @@ public DesignatedRoleService(IAuthorizationService authorizationService, IDesign
}

/// <inheritdoc />
public async Task AddDesignatedRoleAsync(ulong guildId, ulong roleId, DesignatedRoleType type)
public async Task<long> AddDesignatedRoleAsync(ulong guildId, ulong roleId, DesignatedRoleType type)
{
AuthorizationService.RequireAuthenticatedUser();
AuthorizationService.RequireClaims(AuthorizationClaim.DesignatedRoleMappingCreate);
Expand All @@ -111,7 +111,7 @@ public async Task AddDesignatedRoleAsync(ulong guildId, ulong roleId, Designated
}, default))
throw new InvalidOperationException($"Role {roleId} already has a {type} designation");

await DesignatedRoleMappingRepository.CreateAsync(new DesignatedRoleMappingCreationData()
var entityId = await DesignatedRoleMappingRepository.CreateAsync(new DesignatedRoleMappingCreationData()
{
GuildId = guildId,
RoleId = roleId,
Expand All @@ -120,6 +120,8 @@ await DesignatedRoleMappingRepository.CreateAsync(new DesignatedRoleMappingCreat
});

transaction.Commit();

return entityId;
}
}

Expand Down
12 changes: 8 additions & 4 deletions Modix.Services/Promotions/PromotionsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public interface IPromotionsService
/// <param name="sentiment">The <see cref="PromotionCommentEntity.Sentiment"/> value to use for the new comment.</param>
/// <param name="content">The <see cref="PromotionCommentEntity.Content"/> value to use for the new comment.</param>
/// <returns>A <see cref="Task"/> that will complete when the operation has completed.</returns>
Task AddCommentAsync(long campaignId, PromotionSentiment sentiment, string? content);
Task<PromotionActionSummary> AddCommentAsync(long campaignId, PromotionSentiment sentiment, string? content);

/// <summary>
/// Updates an existing comment on a promotion campaign by deleting the comment and adding a new one.
Expand All @@ -59,7 +59,7 @@ public interface IPromotionsService
/// <param name="newSentiment">The <see cref="PromotionCommentEntity.Sentiment"/> value of the updated comment.</param>
/// <param name="newContent">The <see cref="PromotionCommentEntity.Content"/> value of the updated comment.</param>
/// <returns>A <see cref="Task"/> that will complete when the operation has completed.</returns>
Task UpdateCommentAsync(long commentId, PromotionSentiment newSentiment, string? newContent);
Task<PromotionActionSummary> UpdateCommentAsync(long commentId, PromotionSentiment newSentiment, string? newContent);

Task AddOrUpdateCommentAsync(long campaignId, Optional<PromotionSentiment> sentiment, Optional<string?> comment = default);

Expand Down Expand Up @@ -187,7 +187,7 @@ public async Task CreateCampaignAsync(ulong subjectId, string? comment = null)
}

/// <inheritdoc />
public async Task AddCommentAsync(long campaignId, PromotionSentiment sentiment, string? content)
public async Task<PromotionActionSummary> AddCommentAsync(long campaignId, PromotionSentiment sentiment, string? content)
{
AuthorizationService.RequireAuthenticatedGuild();
AuthorizationService.RequireAuthenticatedUser();
Expand Down Expand Up @@ -234,10 +234,12 @@ public async Task AddCommentAsync(long campaignId, PromotionSentiment sentiment,
}

PublishActionNotificationAsync(resultAction);

return resultAction;
}

/// <inheritdoc />
public async Task UpdateCommentAsync(long commentId, PromotionSentiment newSentiment, string? newContent)
public async Task<PromotionActionSummary> UpdateCommentAsync(long commentId, PromotionSentiment newSentiment, string? newContent)
{
AuthorizationService.RequireAuthenticatedUser();
AuthorizationService.RequireClaims(AuthorizationClaim.PromotionsComment);
Expand All @@ -263,6 +265,8 @@ public async Task UpdateCommentAsync(long commentId, PromotionSentiment newSenti
}

PublishActionNotificationAsync(resultAction);

return resultAction;
}

public async Task AddOrUpdateCommentAsync(long campaignId, Optional<PromotionSentiment> sentiment, Optional<string?> content = default)
Expand Down
Loading

0 comments on commit 045decc

Please sign in to comment.