Skip to content

Commit

Permalink
Controller refactoring (#86)
Browse files Browse the repository at this point in the history
* Emote suggestions, image extension validation.

* Api V2 Refactoring

* AuditLogController refactoring

* AuthController refactoring

* DashboardController refactoring

* InviteController refactoring

* AutoReplyController refactoring

* ChannelController refactoring

* EmotesController and EmoteSuggestionController refactoring

* GuildController refactoring

* PointsController refactoring

* PublicApiClientsController refactoring

* ReminderController refactoring

* ScheduledJobsController refactoring

* SearchingController refactoring

* ServiceController refactoring

* StatisticsController refactoring

* SystemController refactoring

* UnverifyController refactoring

* UserController refactoring

* Last changes

* Bugfixes after testing
  • Loading branch information
Misha12 authored Oct 31, 2023
1 parent f4b6c99 commit ed15927
Show file tree
Hide file tree
Showing 125 changed files with 2,514 additions and 2,123 deletions.
24 changes: 17 additions & 7 deletions src/GrillBot.App/Actions/ActionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using GrillBot.Core.Services.AuditLog;
using GrillBot.Core.Services.PointsService;
using GrillBot.Core.Services.RubbergodService;
using GrillBot.Database.Migrations;
using Microsoft.Extensions.DependencyInjection;

namespace GrillBot.App.Actions;

Expand All @@ -7,16 +11,21 @@ public static class ActionsExtensions
public static IServiceCollection AddActions(this IServiceCollection services)
{
return services
.AddServiceBridge()
.AddApiActions()
.AddCommandsActions();
}

private static IServiceCollection AddApiActions(this IServiceCollection services)
private static IServiceCollection AddServiceBridge(this IServiceCollection services)
{
// Common
services
.AddScoped<Api.ApiBridgeAction>();
return services
.AddScoped<Api.ServiceBridgeAction<IRubbergodServiceClient>>()
.AddScoped<Api.ServiceBridgeAction<IAuditLogServiceClient>>()
.AddScoped<Api.ServiceBridgeAction<IPointsServiceClient>>();
}

private static IServiceCollection AddApiActions(this IServiceCollection services)
{
// V1
// AuditLog
services
Expand Down Expand Up @@ -52,7 +61,7 @@ private static IServiceCollection AddApiActions(this IServiceCollection services
.AddScoped<Api.V1.Channel.SimpleList.GetChannelSimpleListWithPins>()
.AddScoped<Api.V1.Channel.GetPins>()
.AddScoped<Api.V1.Channel.GetPinsWithAttachments>();

// Dashboard
services
.AddScoped<Api.V1.Dashboard.GetActiveOperations>()
Expand Down Expand Up @@ -154,7 +163,8 @@ private static IServiceCollection AddApiActions(this IServiceCollection services
.AddScoped<Api.V1.User.GetAvailableUsers>()
.AddScoped<Api.V1.User.GetUserDetail>()
.AddScoped<Api.V1.User.GetUserList>()
.AddScoped<Api.V1.User.UpdateUser>();
.AddScoped<Api.V1.User.UpdateUser>()
.AddScoped<Api.V1.User.Hearthbeat>();

// V2
services
Expand Down
21 changes: 0 additions & 21 deletions src/GrillBot.App/Actions/Api/ApiBridgeAction.cs

This file was deleted.

32 changes: 32 additions & 0 deletions src/GrillBot.App/Actions/Api/ServiceBridgeAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using GrillBot.Common.Models;
using GrillBot.Core.Infrastructure.Actions;
using GrillBot.Core.Services.Common;

namespace GrillBot.App.Actions.Api;

public class ServiceBridgeAction<TServiceClient> : ApiAction where TServiceClient : IClient
{
private TServiceClient Client { get; }

public ServiceBridgeAction(ApiRequestContext apiContext, TServiceClient client) : base(apiContext)
{
Client = client;
}

public override async Task<ApiResult> ProcessAsync()
{
var funcExecutor = Parameters.OfType<Func<TServiceClient, Task<object>>>().FirstOrDefault();
var actionExecutor = Parameters.OfType<Func<TServiceClient, Task>>().FirstOrDefault();

if (funcExecutor is not null)
return ApiResult.Ok(await funcExecutor(Client));

if (actionExecutor is not null)
{
await actionExecutor(Client);
return ApiResult.Ok();
}

return ApiResult.BadRequest();
}
}
18 changes: 11 additions & 7 deletions src/GrillBot.App/Actions/Api/V1/AuditLog/CreateLogItem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using GrillBot.Common.Managers.Localization;
using GrillBot.Common.Extensions;
using GrillBot.Common.Managers.Localization;
using GrillBot.Common.Models;
using GrillBot.Core.Infrastructure.Actions;
using GrillBot.Core.Services.AuditLog;
using GrillBot.Core.Services.AuditLog.Enums;
using GrillBot.Core.Services.AuditLog.Models.Request.CreateItems;
Expand All @@ -18,8 +20,9 @@ public CreateLogItem(ApiRequestContext apiContext, ITextsManager texts, IAuditLo
AuditLogServiceClient = auditLogServiceClient;
}

public async Task ProcessAsync(ClientLogItemRequest request)
public override async Task<ApiResult> ProcessAsync()
{
var request = (ClientLogItemRequest)Parameters[0]!;
ValidateParameters(request);

var logRequest = new LogRequest
Expand Down Expand Up @@ -50,20 +53,21 @@ public async Task ProcessAsync(ClientLogItemRequest request)
}

await AuditLogServiceClient.CreateItemsAsync(new List<LogRequest> { logRequest });
return ApiResult.Ok();
}

private void ValidateParameters(ClientLogItemRequest request)
{
var flags = new[] { request.IsInfo, request.IsWarning, request.IsError };
var names = new[] { nameof(request.IsInfo), nameof(request.IsWarning), nameof(request.IsError) };

ValidationResult? result = null;
string? errorMessage = null;
if (!Array.Exists(flags, o => o))
result = new ValidationResult(Texts["AuditLog/CreateLogItem/Required", ApiContext.Language], names);
errorMessage = Texts["AuditLog/CreateLogItem/Required", ApiContext.Language];
else if (flags.Count(o => o) > 1)
result = new ValidationResult(Texts["AuditLog/CreateLogItem/MultipleTypes", ApiContext.Language], names);
errorMessage = Texts["AuditLog/CreateLogItem/MultipleTypes", ApiContext.Language];

if (result is not null)
throw new ValidationException(result, null, request);
if (!string.IsNullOrEmpty(errorMessage))
throw new ValidationException(errorMessage).ToBadRequestValidation(request, names);
}
}
114 changes: 58 additions & 56 deletions src/GrillBot.App/Actions/Api/V1/AuditLog/GetAuditLogDetail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using GrillBot.Common.Extensions.Discord;
using GrillBot.Common.Models;
using GrillBot.Core.Extensions;
using GrillBot.Core.Infrastructure.Actions;
using GrillBot.Core.Services.AuditLog;
using GrillBot.Core.Services.AuditLog.Enums;
using GrillBot.Core.Services.AuditLog.Models.Response.Detail;
Expand All @@ -25,11 +26,12 @@ public GetAuditLogDetail(ApiRequestContext apiContext, IAuditLogServiceClient au
Mapper = mapper;
}

public async Task<Detail?> ProcessAsync(Guid id)
public override async Task<ApiResult> ProcessAsync()
{
var id = (Guid)Parameters[0]!;
var detail = await AuditLogServiceClient.DetailAsync(id);
if (detail?.Data is not JsonElement jsonElement)
return null;
return ApiResult.NotFound();

var options = new JsonSerializerOptions
{
Expand All @@ -48,75 +50,75 @@ public GetAuditLogDetail(ApiRequestContext apiContext, IAuditLogServiceClient au
detail.Data = jsonElement.Deserialize<ChannelUpdatedDetail>(options);
break;
case LogType.OverwriteUpdated:
{
var overwriteUpdated = jsonElement.Deserialize<OverwriteUpdatedDetail>(options)!;
var role = overwriteUpdated.TargetType == PermissionTarget.Role ? await DiscordClient.FindRoleAsync(overwriteUpdated.TargetId.ToUlong()) : null;
var user = overwriteUpdated.TargetType == PermissionTarget.User ? await repository.User.FindUserByIdAsync(overwriteUpdated.TargetId.ToUlong()) : null;

detail.Data = new Data.Models.API.AuditLog.Detail.OverwriteUpdatedDetail
{
User = Mapper.Map<Data.Models.API.Users.User>(user),
Role = Mapper.Map<Data.Models.API.Role>(role),
Allow = overwriteUpdated.Allow,
Deny = overwriteUpdated.Deny
};
break;
}
case LogType.MemberUpdated:
{
var memberUpdated = jsonElement.Deserialize<MemberUpdatedDetail>(options)!;
var user = await repository.User.FindUserByIdAsync(memberUpdated.UserId.ToUlong());
var overwriteUpdated = jsonElement.Deserialize<OverwriteUpdatedDetail>(options)!;
var role = overwriteUpdated.TargetType == PermissionTarget.Role ? await DiscordClient.FindRoleAsync(overwriteUpdated.TargetId.ToUlong()) : null;
var user = overwriteUpdated.TargetType == PermissionTarget.User ? await repository.User.FindUserByIdAsync(overwriteUpdated.TargetId.ToUlong()) : null;

detail.Data = new Data.Models.API.AuditLog.Detail.MemberUpdatedDetail
detail.Data = new Data.Models.API.AuditLog.Detail.OverwriteUpdatedDetail
{
User = Mapper.Map<Data.Models.API.Users.User>(user),
Role = Mapper.Map<Data.Models.API.Role>(role),
Allow = overwriteUpdated.Allow,
Deny = overwriteUpdated.Deny
};
break;
}
case LogType.MemberUpdated:
{
User = Mapper.Map<Data.Models.API.Users.User>(user),
Flags = memberUpdated.Flags,
Nickname = memberUpdated.Nickname,
IsDeaf = memberUpdated.IsDeaf,
IsMuted = memberUpdated.IsMuted,
SelfUnverifyMinimalTime = memberUpdated.SelfUnverifyMinimalTime
};
break;
}
var memberUpdated = jsonElement.Deserialize<MemberUpdatedDetail>(options)!;
var user = await repository.User.FindUserByIdAsync(memberUpdated.UserId.ToUlong());

detail.Data = new Data.Models.API.AuditLog.Detail.MemberUpdatedDetail
{
User = Mapper.Map<Data.Models.API.Users.User>(user),
Flags = memberUpdated.Flags,
Nickname = memberUpdated.Nickname,
IsDeaf = memberUpdated.IsDeaf,
IsMuted = memberUpdated.IsMuted,
SelfUnverifyMinimalTime = memberUpdated.SelfUnverifyMinimalTime
};
break;
}
case LogType.GuildUpdated:
detail.Data = jsonElement.Deserialize<GuildUpdatedDetail>(options);
break;
case LogType.MessageDeleted:
{
var messageDeleted = jsonElement.Deserialize<MessageDeletedDetail>(options)!;
var author = await repository.User.FindUserByIdAsync(messageDeleted.AuthorId.ToUlong());

detail.Data = new Data.Models.API.AuditLog.Detail.MessageDeletedDetail
{
Author = Mapper.Map<Data.Models.API.Users.User>(author),
Content = messageDeleted.Content,
Embeds = messageDeleted.Embeds,
MessageCreatedAt = messageDeleted.MessageCreatedAt.ToLocalTime()
};
break;
}
var messageDeleted = jsonElement.Deserialize<MessageDeletedDetail>(options)!;
var author = await repository.User.FindUserByIdAsync(messageDeleted.AuthorId.ToUlong());

detail.Data = new Data.Models.API.AuditLog.Detail.MessageDeletedDetail
{
Author = Mapper.Map<Data.Models.API.Users.User>(author),
Content = messageDeleted.Content,
Embeds = messageDeleted.Embeds,
MessageCreatedAt = messageDeleted.MessageCreatedAt.ToLocalTime()
};
break;
}
case LogType.InteractionCommand:
detail.Data = jsonElement.Deserialize<InteractionCommandDetail>(options);
break;
case LogType.ThreadDeleted:
detail.Data = jsonElement.Deserialize<ThreadDeletedDetail>(options);
break;
case LogType.JobCompleted:
{
var jobCompleted = jsonElement.Deserialize<JobExecutionDetail>(options)!;
var startUser = string.IsNullOrEmpty(jobCompleted.StartUserId) ? null : await repository.User.FindUserByIdAsync(jobCompleted.StartUserId.ToUlong());

detail.Data = new Data.Models.API.AuditLog.Detail.JobExecutionDetail
{
Result = jobCompleted.Result,
EndAt = jobCompleted.EndAt.ToLocalTime(),
JobName = jobCompleted.JobName,
StartAt = jobCompleted.StartAt.ToLocalTime(),
StartUser = startUser is null ? null : Mapper.Map<Data.Models.API.Users.User>(startUser),
WasError = jobCompleted.WasError
};
break;
}
var jobCompleted = jsonElement.Deserialize<JobExecutionDetail>(options)!;
var startUser = string.IsNullOrEmpty(jobCompleted.StartUserId) ? null : await repository.User.FindUserByIdAsync(jobCompleted.StartUserId.ToUlong());

detail.Data = new Data.Models.API.AuditLog.Detail.JobExecutionDetail
{
Result = jobCompleted.Result,
EndAt = jobCompleted.EndAt.ToLocalTime(),
JobName = jobCompleted.JobName,
StartAt = jobCompleted.StartAt.ToLocalTime(),
StartUser = startUser is null ? null : Mapper.Map<Data.Models.API.Users.User>(startUser),
WasError = jobCompleted.WasError
};
break;
}
case LogType.Api:
detail.Data = jsonElement.Deserialize<ApiRequestDetail>(options);
break;
Expand All @@ -128,6 +130,6 @@ public GetAuditLogDetail(ApiRequestContext apiContext, IAuditLogServiceClient au
break;
}

return detail;
return ApiResult.Ok(detail);
}
}
19 changes: 11 additions & 8 deletions src/GrillBot.App/Actions/Api/V1/AuditLog/GetAuditLogList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using GrillBot.Common.FileStorage;
using GrillBot.Common.Models;
using GrillBot.Core.Extensions;
using GrillBot.Core.Infrastructure.Actions;
using GrillBot.Core.Models.Pagination;
using GrillBot.Core.Services.AuditLog;
using GrillBot.Core.Services.AuditLog.Enums;
Expand Down Expand Up @@ -43,9 +44,12 @@ public GetAuditLogList(ApiRequestContext apiContext, GrillBotDatabaseBuilder dat
BlobManagerFactoryHelper = blobManagerFactoryHelper;
}

public async Task<PaginatedResponse<LogListItem>> ProcessAsync(SearchRequest request)
public override async Task<ApiResult> ProcessAsync()
{
FixDateTimes(request);
var request = (SearchRequest)Parameters[0]!;

request.CreatedFrom = FixDateTime(request.CreatedFrom);
request.CreatedTo = FixDateTime(request.CreatedTo);

var response = await AuditLogServiceClient.SearchItemsAsync(request);
if (response.ValidationErrors is not null)
Expand All @@ -58,13 +62,12 @@ public async Task<PaginatedResponse<LogListItem>> ProcessAsync(SearchRequest req
}

await using var repository = DatabaseBuilder.CreateRepository();
return await PaginatedResponse<LogListItem>.CopyAndMapAsync(response.Response!, async entity => await MapListItemAsync(repository, entity));
}
var result = await PaginatedResponse<LogListItem>.CopyAndMapAsync(
response.Response!,
async entity => await MapListItemAsync(repository, entity)
);

private static void FixDateTimes(SearchRequest request)
{
request.CreatedFrom = FixDateTime(request.CreatedFrom);
request.CreatedTo = FixDateTime(request.CreatedTo);
return ApiResult.Ok(result);
}

private static DateTime? FixDateTime(DateTime? dateTime)
Expand Down
8 changes: 6 additions & 2 deletions src/GrillBot.App/Actions/Api/V1/AuditLog/RemoveItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using GrillBot.Common.Managers.Localization;
using GrillBot.Common.Models;
using GrillBot.Core.Exceptions;
using GrillBot.Core.Infrastructure.Actions;
using GrillBot.Core.Services.AuditLog;

namespace GrillBot.App.Actions.Api.V1.AuditLog;
Expand All @@ -20,14 +21,15 @@ public RemoveItem(ApiRequestContext apiContext, ITextsManager texts, IAuditLogSe
BlobManagerFactoryHelper = blobManagerFactoryHelper;
}

public async Task ProcessAsync(Guid id)
public override async Task<ApiResult> ProcessAsync()
{
var id = (Guid)Parameters[0]!;
var response = await AuditLogServiceClient.DeleteItemAsync(id);
if (!response.Exists)
throw new NotFoundException(Texts["AuditLog/RemoveItem/NotFound", ApiContext.Language]);

if (response.FilesToDelete.Count == 0)
return;
return ApiResult.Ok();

var manager = await BlobManagerFactoryHelper.CreateAsync(BlobConstants.AuditLogDeletedAttachments);
var legacyManager = await BlobManagerFactoryHelper.CreateLegacyAsync();
Expand All @@ -37,5 +39,7 @@ public async Task ProcessAsync(Guid id)
await manager.DeleteAsync(filename);
await legacyManager.DeleteAsync(filename);
}

return ApiResult.Ok();
}
}
Loading

0 comments on commit ed15927

Please sign in to comment.