Commit MWS backend source tree
The ASP.NET Core solution (mws.api/mws.application/mws.domain/ mws.infrastructure) existed only as untracked working files. Adding it to version control, plus a .gitignore for build output and local tooling directories, so the CQRS/mediator refactor plan has a real git history to branch and diff against.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
|
||||
namespace Mws.Api;
|
||||
|
||||
public static class ClaimsExtensions
|
||||
{
|
||||
public static Guid GetUserId(this ClaimsPrincipal principal)
|
||||
{
|
||||
var value = principal.FindFirstValue(JwtRegisteredClaimNames.Sub)
|
||||
?? principal.FindFirstValue(ClaimTypes.NameIdentifier)
|
||||
?? principal.FindFirstValue("sub");
|
||||
if (value is not null && Guid.TryParse(value, out var id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
throw new UnauthorizedAccessException("Invalid user identity");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Accounts;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/accounts")]
|
||||
[Authorize]
|
||||
public class AccountsController(IAccountService accountService) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<AccountDto>>> GetAll([FromQuery] string? q, CancellationToken ct)
|
||||
{
|
||||
return Ok(await accountService.GetAccountsAsync(User.GetUserId(), q, ct));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<AccountDto>> Create([FromBody] CreateAccountRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await accountService.CreateAccountAsync(User.GetUserId(), request, ct));
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<ActionResult<AccountDto>> Update(Guid id, [FromBody] UpdateAccountRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await accountService.UpdateAccountAsync(User.GetUserId(), id, request, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
await accountService.DeleteAccountAsync(User.GetUserId(), id, ct);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/reset-password")]
|
||||
public async Task<IActionResult> ResetPassword(Guid id, [FromBody] ResetPasswordRequest request, CancellationToken ct)
|
||||
{
|
||||
await accountService.ResetPasswordAsync(User.GetUserId(), id, request, ct);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Auth;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/auth")]
|
||||
[AllowAnonymous]
|
||||
public class AuthController(IAuthService authService) : ControllerBase
|
||||
{
|
||||
[HttpPost("login")]
|
||||
public async Task<ActionResult<LoginResponse>> Login([FromBody] LoginRequest request, CancellationToken ct)
|
||||
{
|
||||
var response = await authService.LoginAsync(request, ct);
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Documents;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api")]
|
||||
[Authorize]
|
||||
public class DocumentsController(IDocumentService documentService) : ControllerBase
|
||||
{
|
||||
[HttpGet("documents/search")]
|
||||
public async Task<ActionResult<List<DocumentNodeDto>>> Search([FromQuery] string? q, CancellationToken ct)
|
||||
{
|
||||
return Ok(await documentService.SearchAsync(User.GetUserId(), q ?? string.Empty, ct));
|
||||
}
|
||||
|
||||
[HttpGet("projects/{projectId:guid}/documents")]
|
||||
public async Task<ActionResult<List<DocumentNodeDto>>> GetTree(Guid projectId, CancellationToken ct)
|
||||
{
|
||||
return Ok(await documentService.GetTreeAsync(User.GetUserId(), projectId, ct));
|
||||
}
|
||||
|
||||
[HttpPost("projects/{projectId:guid}/documents")]
|
||||
public async Task<ActionResult<DocumentDto>> Create(Guid projectId, [FromBody] CreateDocumentRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await documentService.CreateAsync(User.GetUserId(), projectId, request, ct);
|
||||
return CreatedAtAction(nameof(Get), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpGet("documents/{id:guid}")]
|
||||
public async Task<ActionResult<DocumentDto>> Get(Guid id, CancellationToken ct)
|
||||
{
|
||||
return Ok(await documentService.GetAsync(User.GetUserId(), id, ct));
|
||||
}
|
||||
|
||||
[HttpPut("documents/{id:guid}")]
|
||||
public async Task<ActionResult<DocumentDto>> Update(Guid id, [FromBody] UpdateDocumentRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await documentService.UpdateAsync(User.GetUserId(), id, request, ct));
|
||||
}
|
||||
|
||||
[HttpPut("documents/{id:guid}/move")]
|
||||
public async Task<ActionResult<DocumentDto>> Move(Guid id, [FromBody] MoveDocumentRequest request, CancellationToken ct)
|
||||
{
|
||||
await documentService.MoveAsync(User.GetUserId(), id, request.NewParentId, ct);
|
||||
return Ok(await documentService.GetAsync(User.GetUserId(), id, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("documents/{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
await documentService.DeleteAsync(User.GetUserId(), id, ct);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Permissions;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/menu")]
|
||||
[Authorize]
|
||||
public class MenuController(IPermissionService permissions) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<MenuItemDto>>> GetMenu(CancellationToken ct)
|
||||
{
|
||||
return Ok(await permissions.GetMenuAsync(User.GetUserId(), ct));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Projects;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/projects/{projectId:guid}/members")]
|
||||
[Authorize]
|
||||
public class ProjectMembersController(IProjectMemberService memberService) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<ProjectMemberDto>>> GetAll(Guid projectId, CancellationToken ct)
|
||||
{
|
||||
return Ok(await memberService.GetMembersAsync(User.GetUserId(), projectId, ct));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<ProjectMemberDto>> Add(Guid projectId, [FromBody] AddMemberRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await memberService.AddMemberAsync(User.GetUserId(), projectId, request, ct));
|
||||
}
|
||||
|
||||
[HttpPut("{userId:guid}/document-permissions")]
|
||||
public async Task<ActionResult<ProjectMemberDto>> UpdateDocumentPermissions(
|
||||
Guid projectId, Guid userId, [FromBody] UpdateMemberDocumentPermissionsRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await memberService.UpdateMemberDocumentPermissionsAsync(User.GetUserId(), projectId, userId, request, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("{userId:guid}")]
|
||||
public async Task<IActionResult> Remove(Guid projectId, Guid userId, CancellationToken ct)
|
||||
{
|
||||
await memberService.RemoveMemberAsync(User.GetUserId(), projectId, userId, ct);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Projects;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/projects")]
|
||||
[Authorize]
|
||||
public class ProjectsController(IProjectService projectService) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<ProjectDto>>> GetAll(CancellationToken ct)
|
||||
{
|
||||
return Ok(await projectService.GetProjectsAsync(User.GetUserId(), ct));
|
||||
}
|
||||
|
||||
[HttpGet("search")]
|
||||
public async Task<ActionResult<List<ProjectDto>>> Search([FromQuery] string? q, CancellationToken ct)
|
||||
{
|
||||
return Ok(await projectService.SearchAsync(User.GetUserId(), q ?? string.Empty, ct));
|
||||
}
|
||||
|
||||
[HttpGet("{projectId:guid}")]
|
||||
public async Task<ActionResult<ProjectDto>> Get(Guid projectId, CancellationToken ct)
|
||||
{
|
||||
return Ok(await projectService.GetProjectAsync(User.GetUserId(), projectId, ct));
|
||||
}
|
||||
|
||||
[HttpGet("{projectId:guid}/overview")]
|
||||
public async Task<ActionResult<ProjectOverviewDto>> Overview(Guid projectId, CancellationToken ct)
|
||||
{
|
||||
return Ok(await projectService.GetOverviewAsync(User.GetUserId(), projectId, ct));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<ProjectDto>> Create([FromBody] CreateProjectRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await projectService.CreateProjectAsync(User.GetUserId(), request, ct);
|
||||
return CreatedAtAction(nameof(Get), new { projectId = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{projectId:guid}")]
|
||||
public async Task<ActionResult<ProjectDto>> Update(Guid projectId, [FromBody] UpdateProjectRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await projectService.UpdateProjectAsync(User.GetUserId(), projectId, request, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("{projectId:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid projectId, CancellationToken ct)
|
||||
{
|
||||
await projectService.ArchiveProjectAsync(User.GetUserId(), projectId, ct);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Permissions;
|
||||
using Mws.Application.Roles;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/roles")]
|
||||
[Authorize]
|
||||
public class RolesController(IRoleService roleService, IPermissionService permissions) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<RoleDto>>> GetAll(CancellationToken ct)
|
||||
{
|
||||
await permissions.EnsureAsync(User.GetUserId(), "roles", PermissionAction.View, ct);
|
||||
return Ok(await roleService.GetRolesAsync(ct));
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<ActionResult<RoleDto>> Get(Guid id, CancellationToken ct)
|
||||
{
|
||||
await permissions.EnsureAsync(User.GetUserId(), "roles", PermissionAction.View, ct);
|
||||
return Ok(await roleService.GetRoleAsync(id, ct));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<RoleDto>> Create([FromBody] SaveRoleRequest request, CancellationToken ct)
|
||||
{
|
||||
await permissions.EnsureAsync(User.GetUserId(), "roles", PermissionAction.Create, ct);
|
||||
return Ok(await roleService.CreateRoleAsync(request, ct));
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<ActionResult<RoleDto>> Update(Guid id, [FromBody] SaveRoleRequest request, CancellationToken ct)
|
||||
{
|
||||
await permissions.EnsureAsync(User.GetUserId(), "roles", PermissionAction.Edit, ct);
|
||||
return Ok(await roleService.UpdateRoleAsync(id, request, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
await permissions.EnsureAsync(User.GetUserId(), "roles", PermissionAction.Delete, ct);
|
||||
await roleService.DeleteRoleAsync(id, ct);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Common;
|
||||
using Mws.Application.Tasks;
|
||||
using TaskPriority = Mws.Domain.Tasks.TaskPriority;
|
||||
using TaskStatus = Mws.Domain.Tasks.TaskStatus;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api")]
|
||||
[Authorize]
|
||||
public class TasksController(ITaskService taskService) : ControllerBase
|
||||
{
|
||||
[HttpGet("tasks/search")]
|
||||
public async Task<ActionResult<List<TaskDto>>> Search([FromQuery] string? q, CancellationToken ct)
|
||||
{
|
||||
return Ok(await taskService.SearchAsync(User.GetUserId(), q ?? string.Empty, ct));
|
||||
}
|
||||
|
||||
[HttpGet("projects/{projectId:guid}/tasks")]
|
||||
public async Task<ActionResult<List<TaskDto>>> GetAll(
|
||||
Guid projectId,
|
||||
[FromQuery] string? status,
|
||||
[FromQuery] string? priority,
|
||||
[FromQuery] Guid? assigneeId,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var statusValue = ParseOptional<TaskStatus>(status);
|
||||
var priorityValue = ParseOptional<TaskPriority>(priority);
|
||||
return Ok(await taskService.GetTasksAsync(User.GetUserId(), projectId, statusValue, priorityValue, assigneeId, ct));
|
||||
}
|
||||
|
||||
[HttpPost("projects/{projectId:guid}/tasks")]
|
||||
public async Task<ActionResult<TaskDto>> Create(Guid projectId, [FromBody] CreateTaskRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await taskService.CreateAsync(User.GetUserId(), projectId, request, ct);
|
||||
return CreatedAtAction(nameof(Get), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpGet("tasks/{id:guid}")]
|
||||
public async Task<ActionResult<TaskDto>> Get(Guid id, CancellationToken ct)
|
||||
{
|
||||
return Ok(await taskService.GetAsync(User.GetUserId(), id, ct));
|
||||
}
|
||||
|
||||
[HttpPut("tasks/{id:guid}")]
|
||||
public async Task<ActionResult<TaskDto>> Update(Guid id, [FromBody] UpdateTaskRequest request, CancellationToken ct)
|
||||
{
|
||||
return Ok(await taskService.UpdateAsync(User.GetUserId(), id, request, ct));
|
||||
}
|
||||
|
||||
[HttpDelete("tasks/{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
await taskService.DeleteAsync(User.GetUserId(), id, ct);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private static TEnum? ParseOptional<TEnum>(string? value) where TEnum : struct, Enum
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Enum.TryParse<TEnum>(value, ignoreCase: true, out var result) ? result : throw new BadRequestException($"Invalid {typeof(TEnum).Name}: {value}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Mws.Application.Common;
|
||||
using Mws.Application.Auth;
|
||||
|
||||
namespace Mws.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/users")]
|
||||
[Authorize]
|
||||
public class UsersController(IUnitOfWork uow, IMapper mapper) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<UserDto>>> GetAll([FromQuery] string? q, CancellationToken ct)
|
||||
{
|
||||
var users = await uow.Users.SearchWithRoleAsync(q, 50, ct);
|
||||
return Ok(mapper.Map<List<UserDto>>(users));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Text.Json;
|
||||
using Mws.Application.Common;
|
||||
|
||||
namespace Mws.Api.Middleware;
|
||||
|
||||
public class ApiExceptionMiddleware(RequestDelegate next, ILogger<ApiExceptionMiddleware> logger)
|
||||
{
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await HandleAsync(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleAsync(HttpContext context, Exception ex)
|
||||
{
|
||||
var (statusCode, message) = ex switch
|
||||
{
|
||||
BadRequestException => (StatusCodes.Status400BadRequest, ex.Message),
|
||||
UnauthorizedException => (StatusCodes.Status401Unauthorized, ex.Message),
|
||||
ForbiddenException => (StatusCodes.Status403Forbidden, ex.Message),
|
||||
NotFoundException => (StatusCodes.Status404NotFound, ex.Message),
|
||||
_ => (StatusCodes.Status500InternalServerError, "An unexpected error occurred"),
|
||||
};
|
||||
|
||||
if (statusCode == StatusCodes.Status500InternalServerError)
|
||||
{
|
||||
logger.LogError(ex, "Unhandled exception in {Path}", context.Request.Path);
|
||||
}
|
||||
|
||||
context.Response.StatusCode = statusCode;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(JsonSerializer.Serialize(new { message }));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApiExceptionMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseApiExceptionMiddleware(this IApplicationBuilder app)
|
||||
=> app.UseMiddleware<ApiExceptionMiddleware>();
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi;
|
||||
using Mws.Api.Middleware;
|
||||
using Mws.Application.Auth;
|
||||
using Mws.Infrastructure;
|
||||
using Mws.Infrastructure.Persistence;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services
|
||||
.AddControllers()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(
|
||||
new System.Text.Json.Serialization.JsonStringEnumConverter());
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Title = "MWS API",
|
||||
Version = "v1"
|
||||
});
|
||||
|
||||
options.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "bearer",
|
||||
BearerFormat = "JWT",
|
||||
In = ParameterLocation.Header,
|
||||
Description = "JWT Authorization header using Bearer scheme."
|
||||
});
|
||||
|
||||
options.AddSecurityRequirement(document =>
|
||||
new OpenApiSecurityRequirement
|
||||
{
|
||||
[new OpenApiSecuritySchemeReference("bearer", document)] = []
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddInfrastructure(builder.Configuration);
|
||||
|
||||
var jwtSection = builder.Configuration.GetSection("Jwt");
|
||||
var jwtSecret = jwtSection["Secret"];
|
||||
var jwtIssuer = jwtSection["Issuer"];
|
||||
var jwtAudience = jwtSection["Audience"];
|
||||
|
||||
builder.Services
|
||||
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
|
||||
ValidIssuer = jwtIssuer,
|
||||
ValidAudience = jwtAudience,
|
||||
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret))
|
||||
};
|
||||
|
||||
options.MapInboundClaims = false;
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
var origins = builder.Configuration["Cors:Origins"];
|
||||
options.AddPolicy("Frontend", policy =>
|
||||
{
|
||||
policy
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.WithOrigins(origins.Split(';', StringSplitOptions.RemoveEmptyEntries));
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseApiExceptionMiddleware();
|
||||
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await db.Database.MigrateAsync();
|
||||
await DbSeeder.SeedAsync(db, scope.ServiceProvider.GetRequiredService<IPasswordHasher>());
|
||||
}
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.SwaggerEndpoint(
|
||||
"/swagger/v1/swagger.json",
|
||||
"MWS API v1");
|
||||
|
||||
options.EnablePersistAuthorization();
|
||||
});
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseCors("Frontend");
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:2000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:3000;http://localhost:2000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"Default": "Host=localhost;Port=5432;Database=mws;Username=postgres;Password=Pa55w0rd"
|
||||
},
|
||||
"Jwt": {
|
||||
"Secret": "mws-development-secret-key-change-me-in-production-123456",
|
||||
"Issuer": "Mws",
|
||||
"Audience": "Mws.Clients",
|
||||
"Expiration": "12:00:00"
|
||||
},
|
||||
"Cors": {
|
||||
"Origins": "*"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.EntityFrameworkCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>mws.backend.dotnet</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10"/>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\mws.application\mws.application.csproj" />
|
||||
<ProjectReference Include="..\mws.domain\mws.domain.csproj" />
|
||||
<ProjectReference Include="..\mws.infrastructure\mws.infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user