Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions SetupProject.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F16", "Src\Core\F16\F16.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F17", "Src\Core\F17\F17.csproj", "{A4CC6A27-4EDE-4383-9956-B41A622D34D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F18", "Src\Core\F18\F18.csproj", "{53684635-F86C-4635-ABFA-B889CAF9308B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -167,6 +169,10 @@ Global
{A4CC6A27-4EDE-4383-9956-B41A622D34D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4CC6A27-4EDE-4383-9956-B41A622D34D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4CC6A27-4EDE-4383-9956-B41A622D34D3}.Release|Any CPU.Build.0 = Release|Any CPU
{53684635-F86C-4635-ABFA-B889CAF9308B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53684635-F86C-4635-ABFA-B889CAF9308B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53684635-F86C-4635-ABFA-B889CAF9308B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53684635-F86C-4635-ABFA-B889CAF9308B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -200,5 +206,6 @@ Global
{5F6FC9E6-C713-471B-99E8-AACC3994C583} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{7373234F-7D82-49D3-BBCB-B8CFD84F6389} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{A4CC6A27-4EDE-4383-9956-B41A622D34D3} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{53684635-F86C-4635-ABFA-B889CAF9308B} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
EndGlobalSection
EndGlobal
43 changes: 43 additions & 0 deletions Src/Core/F18/BusinessLogic/F18Service.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using F18.Common;
using F18.DataAccess;
using F18.Models;
using FCommon.FeatureService;

namespace F18.BusinessLogic;

public sealed class F18Service : IServiceHandler<F18AppRequestModel, F18AppResponseModel>
{
private readonly Lazy<IF18Repository> _repository;

public F18Service(Lazy<IF18Repository> repository)
{
_repository = repository;
}

public async Task<F18AppResponseModel> ExecuteAsync(
F18AppRequestModel request,
CancellationToken ct
)
{
var doesTaskExist = await _repository.Value.DoesTodoTaskExistAsync(request.TodoTaskId, ct);
if (!doesTaskExist)
{
return F18Constant.DefaultResponse.App.TASK_NOT_FOUND;
}

var isSuccess = await _repository.Value.ModifyIsImportantStatusAsync(
request.TodoTaskId,
request.IsImportant,
ct
);
if (!isSuccess)
{
return F18Constant.DefaultResponse.App.SERVER_ERROR;
}

return new() { AppCode = F18Constant.AppCode.SUCCESS };
}
}
60 changes: 60 additions & 0 deletions Src/Core/F18/Common/F18Constant.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using F18.Models;
using F18.Presentation;
using Microsoft.AspNetCore.Http;

namespace F18.Common;

public static class F18Constant
{
public const string ENDPOINT_PATH = "f18";

public const string REQUEST_ARGUMENT_NAME = "request";

public static class DefaultResponse
{
public static class App
{
public static readonly F18AppResponseModel TASK_NOT_FOUND = new()
{
AppCode = AppCode.TASK_NOT_FOUND,
};

public static readonly F18AppResponseModel SERVER_ERROR = new()
{
AppCode = AppCode.SERVER_ERROR,
};
}

public static class Http
{
public static readonly F18Response VALIDATION_FAILED = new()
{
AppCode = (int)AppCode.VALIDATION_FAILED,
HttpCode = StatusCodes.Status400BadRequest,
};

public static readonly F18Response TASK_NOT_FOUND = new()
{
AppCode = (int)AppCode.TASK_NOT_FOUND,
HttpCode = StatusCodes.Status404NotFound,
};

public static readonly F18Response SERVER_ERROR = new()
{
AppCode = (int)AppCode.SERVER_ERROR,
HttpCode = StatusCodes.Status500InternalServerError,
};
}
}

public enum AppCode
{
SUCCESS = 1,

VALIDATION_FAILED,

TASK_NOT_FOUND,

SERVER_ERROR,
}
}
65 changes: 65 additions & 0 deletions Src/Core/F18/DataAccess/F18Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FA1.DbContext;
using FA1.Entities;
using Microsoft.EntityFrameworkCore;

namespace F18.DataAccess;

public sealed class F18Repository : IF18Repository
{
private readonly AppDbContext _appContext;

public F18Repository(AppDbContext context)
{
_appContext = context;
}

public async Task<bool> ModifyIsImportantStatusAsync(
long taskId,
bool isImportant,
CancellationToken ct
)
{
var dbResult = true;

await _appContext
.Database.CreateExecutionStrategy()
.ExecuteAsync(async () =>
{
await using var dbTransaction = await _appContext.Database.BeginTransactionAsync(
IsolationLevel.ReadCommitted,
ct
);

try
{
await _appContext
.Set<TodoTaskEntity>()
.Where(task => task.Id == taskId)
.ExecuteUpdateAsync(
setProp =>
setProp.SetProperty(entity => entity.IsImportant, isImportant),
ct
);

await dbTransaction.CommitAsync(ct);
}
catch (DbUpdateException)
{
await dbTransaction.RollbackAsync(ct);

dbResult = false;
}
});

return dbResult;
}

public Task<bool> DoesTodoTaskExistAsync(long taskId, CancellationToken ct)
{
return _appContext.Set<TodoTaskEntity>().AnyAsync(entity => entity.Id == taskId, ct);
}
}
11 changes: 11 additions & 0 deletions Src/Core/F18/DataAccess/IF18Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading;
using System.Threading.Tasks;

namespace F18.DataAccess;

public interface IF18Repository
{
Task<bool> DoesTodoTaskExistAsync(long taskId, CancellationToken ct);

Task<bool> ModifyIsImportantStatusAsync(long taskId, bool isImportant, CancellationToken ct);
}
2 changes: 2 additions & 0 deletions Src/Core/F18/F18.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project Sdk="Microsoft.NET.Sdk">
</Project>
33 changes: 33 additions & 0 deletions Src/Core/F18/F18Register.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using F18.BusinessLogic;
using F18.DataAccess;
using FACommon.DependencyInjection;
using FluentValidation;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace F18;

public sealed class F18Register : IServiceRegister
{
public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
{
var currentAssembly = typeof(F18Register).Assembly;

#region Filters
services.RegisterFiltersFromAssembly(currentAssembly);
#endregion

#region Validation
services.AddValidatorsFromAssembly(currentAssembly, ServiceLifetime.Singleton);
#endregion

#region Core
services
.AddScoped<IF18Repository, F18Repository>()
.MakeScopedLazy<IF18Repository>()
.AddScoped<F18Service>();
#endregion

return services;
}
}
51 changes: 51 additions & 0 deletions Src/Core/F18/Mapper/F17HttpResponseMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Concurrent;
using F18.Common;
using F18.Models;
using F18.Presentation;
using Microsoft.AspNetCore.Http;

namespace F17.Mapper;

public static class F17HttpResponseMapper
{
private static ConcurrentDictionary<
F18Constant.AppCode,
Func<F18AppRequestModel, F18AppResponseModel, F18Response>
> _httpResponseMapper;

private static void Init()
{
if (Equals(_httpResponseMapper, null))
{
_httpResponseMapper = new();
}

_httpResponseMapper.TryAdd(
F18Constant.AppCode.SUCCESS,
(appRequest, appResponse) =>
new()
{
AppCode = (int)F18Constant.AppCode.SUCCESS,
HttpCode = StatusCodes.Status200OK,
}
);

_httpResponseMapper.TryAdd(
F18Constant.AppCode.TASK_NOT_FOUND,
(appRequest, appResponse) => F18Constant.DefaultResponse.Http.TASK_NOT_FOUND
);

_httpResponseMapper.TryAdd(
F18Constant.AppCode.SERVER_ERROR,
(appRequest, appResponse) => F18Constant.DefaultResponse.Http.SERVER_ERROR
);
}

public static F18Response Get(F18AppRequestModel appRequest, F18AppResponseModel appResponse)
{
Init();

return _httpResponseMapper[appResponse.AppCode](appRequest, appResponse);
}
}
10 changes: 10 additions & 0 deletions Src/Core/F18/Models/F18AppRequestModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using FCommon.FeatureService;

namespace F18.Models;

public sealed class F18AppRequestModel : IServiceRequest<F18AppResponseModel>
{
public long TodoTaskId { get; set; }

public bool IsImportant { get; set; }
}
13 changes: 13 additions & 0 deletions Src/Core/F18/Models/F18AppResponseModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using F18.Common;
using FCommon.FeatureService;

namespace F18.Models;

public sealed class F18AppResponseModel : IServiceResponse
{
public F18Constant.AppCode AppCode { get; set; }

public BodyModel Body { get; set; }

public sealed class BodyModel { }
}
42 changes: 42 additions & 0 deletions Src/Core/F18/Presentation/F18Endpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Threading;
using System.Threading.Tasks;
using F17.Mapper;
using F18.BusinessLogic;
using F18.Common;
using F18.Models;
using F18.Presentation.Filters.Validation;
using FCommon.Authorization.Default;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace F18.Presentation;

public sealed class F18Endpoint : ControllerBase
{
private readonly F18Service _service;

public F18Endpoint(F18Service service)
{
_service = service;
}

[HttpPost(F18Constant.ENDPOINT_PATH)]
[Authorize(Policy = nameof(DefaultAuthorizationRequirement))]
[ServiceFilter<F18ValidationFilter>(Order = 1)]
public async Task<IActionResult> ExecuteAsync(
[FromBody] F18Request request,
CancellationToken ct
)
{
var appRequest = new F18AppRequestModel
{
TodoTaskId = request.TodoTaskId,
IsImportant = request.IsImportant,
};
var appResponse = await _service.ExecuteAsync(appRequest, ct);

var httpResponse = F17HttpResponseMapper.Get(appRequest, appResponse);

return StatusCode(httpResponse.HttpCode, httpResponse);
}
}
8 changes: 8 additions & 0 deletions Src/Core/F18/Presentation/F18Request.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace F18.Presentation;

public sealed class F18Request
{
public long TodoTaskId { get; set; }

public bool IsImportant { get; set; }
}
15 changes: 15 additions & 0 deletions Src/Core/F18/Presentation/F18Response.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;

namespace F18.Presentation;

public sealed class F18Response
{
[JsonIgnore]
public int HttpCode { get; set; }

public int AppCode { get; set; }

public BodyDto Body { get; set; }

public sealed class BodyDto { }
}
Loading
Loading