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 @@ -57,6 +57,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F14", "Src\Core\F14\F14.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F15", "Src\Core\F15\F15.csproj", "{5F6FC9E6-C713-471B-99E8-AACC3994C583}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F16", "Src\Core\F16\F16.csproj", "{7373234F-7D82-49D3-BBCB-B8CFD84F6389}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -155,6 +157,10 @@ Global
{5F6FC9E6-C713-471B-99E8-AACC3994C583}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F6FC9E6-C713-471B-99E8-AACC3994C583}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F6FC9E6-C713-471B-99E8-AACC3994C583}.Release|Any CPU.Build.0 = Release|Any CPU
{7373234F-7D82-49D3-BBCB-B8CFD84F6389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7373234F-7D82-49D3-BBCB-B8CFD84F6389}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7373234F-7D82-49D3-BBCB-B8CFD84F6389}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7373234F-7D82-49D3-BBCB-B8CFD84F6389}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -186,5 +192,6 @@ Global
{95E410E2-9C9C-4ED3-B927-3E2951197829} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{C044FCB9-18E7-4EE2-AA37-19E658387971} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{5F6FC9E6-C713-471B-99E8-AACC3994C583} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
{7373234F-7D82-49D3-BBCB-B8CFD84F6389} = {F7C07F6C-C2ED-4E06-9025-AD33B4BBBB51}
EndGlobalSection
EndGlobal
43 changes: 43 additions & 0 deletions Src/Core/F16/BusinessLogic/F16Service.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 F16.Common;
using F16.DataAccess;
using F16.Models;
using FCommon.FeatureService;

namespace F16.BusinessLogic;

public sealed class F16Service : IServiceHandler<F16AppRequestModel, F16AppResponseModel>
{
private readonly Lazy<IF16Repository> _repository;

public F16Service(Lazy<IF16Repository> repository)
{
_repository = repository;
}

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

var isSuccess = await _repository.Value.ModifyIsInMyDayStatusAsync(
request.TodoTaskId,
request.IsInMyDay,
ct
);
if (!isSuccess)
{
return F16Constant.DefaultResponse.App.SERVER_ERROR;
}

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

namespace F16.Common;

public static class F16Constant
{
public const string ENDPOINT_PATH = "f16";

public const string REQUEST_ARGUMENT_NAME = "request";

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

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

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

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

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

public enum AppCode
{
SUCCESS = 1,

VALIDATION_FAILED,

TASK_NOT_FOUND,

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

namespace F16.DataAccess;

public sealed class F16Repository : IF16Repository
{
private readonly AppDbContext _appContext;

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

public async Task<bool> ModifyIsInMyDayStatusAsync(
long taskId,
bool isInMyDay,
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.IsInMyDay, isInMyDay),
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/F16/DataAccess/IF16Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading;
using System.Threading.Tasks;

namespace F16.DataAccess;

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

Task<bool> ModifyIsInMyDayStatusAsync(long taskId, bool isInMyDay, CancellationToken ct);
}
2 changes: 2 additions & 0 deletions Src/Core/F16/F16.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/F16/F16Register.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using F16.BusinessLogic;
using F16.DataAccess;
using FACommon.DependencyInjection;
using FluentValidation;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace F16;

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

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

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

#region Core
services
.AddScoped<IF16Repository, F16Repository>()
.MakeScopedLazy<IF16Repository>()
.AddScoped<F16Service>();
#endregion

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

namespace F16.Mapper;

public static class F16HttpResponseMapper
{
private static ConcurrentDictionary<
F16Constant.AppCode,
Func<F16AppRequestModel, F16AppResponseModel, F16Response>
> _httpResponseMapper;

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

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

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

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

public static F16Response Get(F16AppRequestModel appRequest, F16AppResponseModel appResponse)
{
Init();

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

namespace F16.Models;

public sealed class F16AppRequestModel : IServiceRequest<F16AppResponseModel>
{
public long TodoTaskId { get; set; }

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

namespace F16.Models;

public sealed class F16AppResponseModel : IServiceResponse
{
public F16Constant.AppCode AppCode { get; set; }

public BodyModel Body { get; set; }

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

namespace F16.Presentation;

public sealed class F16Endpoint : ControllerBase
{
private readonly F16Service _service;

public F16Endpoint(F16Service service)
{
_service = service;
}

[HttpPost(F16Constant.ENDPOINT_PATH)]
[Authorize(Policy = nameof(DefaultAuthorizationRequirement))]
[ServiceFilter<F16ValidationFilter>(Order = 1)]
public async Task<IActionResult> ExecuteAsync(
[FromBody] F16Request request,
CancellationToken ct
)
{
var appRequest = new F16AppRequestModel
{
TodoTaskId = request.TodoTaskId,
IsInMyDay = request.IsInMyDay,
};
var appResponse = await _service.ExecuteAsync(appRequest, ct);

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

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

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

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

namespace F16.Presentation;

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

public int AppCode { get; set; }

public BodyDto Body { get; set; }

public sealed class BodyDto { }
}
Loading
Loading