Skip to content
Open
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
30 changes: 30 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
49 changes: 49 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Controllers/ArticlesController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Mvc;
using RestApiTask.Models.DTOs;
using RestApiTask.Services.Interfaces;
using AutoMapper;

namespace RestApiTask.Controllers;

[ApiController]
[Route("articles")]
public class ArticlesController : ControllerBase
{
private readonly IArticleService _service;
private readonly IMapper _mapper;

public ArticlesController(IArticleService service, IMapper mapper)
{
_service = service;
_mapper = mapper;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<ArticleResponseTo>>> GetAll() => Ok(await _service.GetAllAsync());

[HttpGet("{id}")]
public async Task<ActionResult<ArticleResponseTo>> GetById(long id) => Ok(await _service.GetByIdAsync(id));

[HttpPost]
public async Task<ActionResult<ArticleResponseTo>> Create([FromBody] ArticleRequestTo request)
{
var result = await _service.CreateAsync(request);
return StatusCode(201, result);
}

[HttpPut]
public async Task<ActionResult<ArticleResponseTo>> Update([FromBody] ArticleResponseTo responseDto)
{
var requestDto = _mapper.Map<ArticleRequestTo>(responseDto);
var result = await _service.UpdateAsync(responseDto.Id, requestDto);
return Ok(result);
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
await _service.DeleteAsync(id);
return NoContent();
}

}
48 changes: 48 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Controllers/MarkersController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc;
using RestApiTask.Models.DTOs;
using RestApiTask.Services.Interfaces;
using AutoMapper;

namespace RestApiTask.Controllers;

[ApiController]
[Route("markers")]
public class MarkersController : ControllerBase
{
private readonly IMarkerService _service;
private readonly IMapper _mapper;

public MarkersController(IMarkerService service, IMapper mapper)
{
_service = service;
_mapper = mapper;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<MarkerResponseTo>>> GetAll() => Ok(await _service.GetAllAsync());

[HttpGet("{id}")]
public async Task<ActionResult<MarkerResponseTo>> GetById(long id) => Ok(await _service.GetByIdAsync(id));

[HttpPost]
public async Task<ActionResult<MarkerResponseTo>> Create([FromBody] MarkerRequestTo request)
{
var result = await _service.CreateAsync(request);
return StatusCode(201, result);
}

[HttpPut]
public async Task<ActionResult<MarkerResponseTo>> Update([FromBody] MarkerResponseTo responseDto)
{
var requestDto = _mapper.Map<MarkerRequestTo>(responseDto);
var result = await _service.UpdateAsync(responseDto.Id, requestDto);
return Ok(result);
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
await _service.DeleteAsync(id);
return NoContent();
}
}
48 changes: 48 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Controllers/MessagesController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc;
using RestApiTask.Models.DTOs;
using RestApiTask.Services.Interfaces;
using AutoMapper;

namespace RestApiTask.Controllers;

[ApiController]
[Route("messages")]
public class MessagesController : ControllerBase
{
private readonly IMessageService _service;
private readonly IMapper _mapper;

public MessagesController(IMessageService service, IMapper mapper)
{
_service = service;
_mapper = mapper;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<MessageResponseTo>>> GetAll() => Ok(await _service.GetAllAsync());

[HttpGet("{id}")]
public async Task<ActionResult<MessageResponseTo>> GetById(long id) => Ok(await _service.GetByIdAsync(id));

[HttpPost]
public async Task<ActionResult<MessageResponseTo>> Create([FromBody] MessageRequestTo request)
{
var result = await _service.CreateAsync(request);
return StatusCode(201, result);
}

[HttpPut]
public async Task<ActionResult<MessageResponseTo>> Update([FromBody] MessageResponseTo responseDto)
{
var requestDto = _mapper.Map<MessageRequestTo>(responseDto);
var result = await _service.UpdateAsync(responseDto.Id, requestDto);
return Ok(result);
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
await _service.DeleteAsync(id);
return NoContent();
}
}
48 changes: 48 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Controllers/WritersController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc;
using RestApiTask.Models.DTOs;
using RestApiTask.Services.Interfaces;
using AutoMapper;

namespace RestApiTask.Controllers;

[ApiController]
[Route("writers")]
public class WritersController : ControllerBase
{
private readonly IWriterService _service;
private readonly IMapper _mapper;

public WritersController(IWriterService service, IMapper mapper)
{
_service = service;
_mapper = mapper;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<WriterResponseTo>>> GetAll() => Ok(await _service.GetAllAsync());

[HttpGet("{id}")]
public async Task<ActionResult<WriterResponseTo>> GetById(long id) => Ok(await _service.GetByIdAsync(id));

[HttpPost]
public async Task<ActionResult<WriterResponseTo>> Create([FromBody] WriterRequestTo request)
{
var result = await _service.CreateAsync(request);
return StatusCode(201, result);
}

[HttpPut] // Без {id} в URL
public async Task<ActionResult<WriterResponseTo>> Update([FromBody] WriterResponseTo responseDto)
{
var requestDto = _mapper.Map<WriterRequestTo>(responseDto);
var result = await _service.UpdateAsync(responseDto.Id, requestDto);
return Ok(result);
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
await _service.DeleteAsync(id);
return NoContent();
}
}
29 changes: 29 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# См. статью по ссылке https://aka.ms/customizecontainer, чтобы узнать как настроить контейнер отладки и как Visual Studio использует этот Dockerfile для создания образов для ускорения отладки.

# Этот этап используется при запуске из VS в быстром режиме (по умолчанию для конфигурации отладки)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080


# Этот этап используется для сборки проекта службы
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["RestApiTask.csproj", "."]
RUN dotnet restore "./RestApiTask.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./RestApiTask.csproj" -c $BUILD_CONFIGURATION -o /app/build

# Этот этап используется для публикации проекта службы, который будет скопирован на последний этап
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./RestApiTask.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# Этот этап используется в рабочей среде или при запуске из VS в обычном режиме (по умолчанию, когда конфигурация отладки не используется)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RestApiTask.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using RestApiTask.Infrastructure.Exceptions;
using RestApiTask.Models;

namespace RestApiTask.Infrastructure;

public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next) => _next = next;

public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);

// Перехват 404/405, если они не вызвали исключение (защита от HTML)
if ((context.Response.StatusCode == 404 || context.Response.StatusCode == 405) && !context.Response.HasStarted)
{
context.Response.ContentType = "application/json";
var response = new ErrorResponse("Resource or Method not found", $"{context.Response.StatusCode}00");
await context.Response.WriteAsJsonAsync(response);
}
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}

private static Task HandleExceptionAsync(HttpContext context, Exception ex)
{
var (statusCode, subCode) = ex switch
{
NotFoundException => (StatusCodes.Status404NotFound, "01"),
ValidationException => (StatusCodes.Status400BadRequest, "01"),
_ => (StatusCodes.Status500InternalServerError, "00")
};

context.Response.ContentType = "application/json";
context.Response.StatusCode = statusCode;

var response = new ErrorResponse(ex.Message, $"{statusCode}{subCode}");
return context.Response.WriteAsJsonAsync(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace RestApiTask.Infrastructure.Exceptions
{
public class NotFoundException : Exception
{
public NotFoundException(string message) : base(message)
{

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace RestApiTask.Infrastructure.Exceptions
{
public class ValidationException : Exception
{
public ValidationException(string message) : base(message)
{

}
}
}
36 changes: 36 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Mappings/MappingProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using AutoMapper;
using RestApiTask.Models.DTOs;
using RestApiTask.Models.Entities;

namespace RestApiTask.Mappings
{

public class MappingProfile : Profile
{
public MappingProfile()
{
// Writer Mappings
CreateMap<WriterRequestTo, Writer>();
CreateMap<Writer, WriterResponseTo>();

// Article Mappings
CreateMap<ArticleRequestTo, Article>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(_ => DateTime.UtcNow))
.ForMember(dest => dest.Modified, opt => opt.MapFrom(_ => DateTime.UtcNow));
CreateMap<Article, ArticleResponseTo>();

// Marker Mappings
CreateMap<MarkerRequestTo, Marker>();
CreateMap<Marker, MarkerResponseTo>();

// Message Mappings
CreateMap<MessageRequestTo, Message>();
CreateMap<Message, MessageResponseTo>();

CreateMap<WriterResponseTo, WriterRequestTo>();
CreateMap<ArticleResponseTo, ArticleRequestTo>();
CreateMap<MarkerResponseTo, MarkerRequestTo>();
CreateMap<MessageResponseTo, MessageRequestTo>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace RestApiTask.Models.DTOs
{
public record ArticleRequestTo(long WriterId, string Title, string Content);
}
12 changes: 12 additions & 0 deletions 351002/Yemyalyanenka/RestApiTask/Models/DTOs/ArticleResponseTo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace RestApiTask.Models.DTOs
{
public class ArticleResponseTo
{
public long Id { get; set; }
public long WriterId { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace RestApiTask.Models.DTOs
{
public record MarkerRequestTo(string Name);
}
Loading