/
Kovalenko
/
TODO
Обзор
Документация
Войти
/
Kovalenko
/
TODO
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
lab3
TaskApi/Controllers/V1/TasksController.cs
208 строк
7 KB
Kovalenko1
that's all
10 янв 2026, 10:20
10 янв 2026, 10:20
4c1ccf3
Код
Авторство
О чём код?
using System.Globalization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TaskApi.Data; using TaskApi.Dtos.V1; using TaskApi.Models; namespace TaskApi.Controllers.V1; [ApiController] [Authorize] [ApiExplorerSettings(GroupName = "v1")] [Route("api/v1/tasks")] public class TasksController : ControllerBase { private readonly AppDbContext _db; public TasksController(AppDbContext db) { _db = db; } [HttpGet] [ProducesResponseType(typeof(IEnumerable<TaskResponseV1>), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task<ActionResult<IEnumerable<TaskResponseV1>>> GetTasks( [FromQuery] int? page, [FromQuery] int? pageSize, [FromQuery] string? include) { var includeFields = ApiHelpers.ParseIncludeFields(include, ApiHelpers.TaskFieldsV1, out var includeError); if (includeError is not null) { return BadRequest(includeError); } if (!ApiHelpers.TryGetPagination(page, pageSize, out var resolvedPage, out var resolvedPageSize, out var usePagination, out var paginationError)) { return BadRequest(paginationError); } var userId = ApiHelpers.GetUserId(User); IQueryable<TaskItem> query = _db.Tasks.AsNoTracking() .Where(task => task.UserId == userId); IQueryable<TaskItem> ordered = query.OrderByDescending(task => task.CreatedAt); if (usePagination) { var totalCount = await query.CountAsync(); Response.Headers["X-Total-Count"] = totalCount.ToString(CultureInfo.InvariantCulture); Response.Headers["X-Page"] = resolvedPage.ToString(CultureInfo.InvariantCulture); Response.Headers["X-Page-Size"] = resolvedPageSize.ToString(CultureInfo.InvariantCulture); ordered = ordered.Skip((resolvedPage - 1) * resolvedPageSize).Take(resolvedPageSize); } var tasks = await ordered.ToListAsync(); if (includeFields is null) { return Ok(tasks.Select(ApiHelpers.MapTaskV1)); } return Ok(tasks.Select(task => ApiHelpers.ShapeTask(task, includeFields))); } [HttpGet("{id:guid}")] [ProducesResponseType(typeof(TaskResponseV1), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task<ActionResult<TaskResponseV1>> GetTask(Guid id, [FromQuery] string? include) { var includeFields = ApiHelpers.ParseIncludeFields(include, ApiHelpers.TaskFieldsV1, out var includeError); if (includeError is not null) { return BadRequest(includeError); } var userId = ApiHelpers.GetUserId(User); var task = await _db.Tasks.AsNoTracking() .FirstOrDefaultAsync(item => item.Id == id && item.UserId == userId); if (task is null) { return NotFound(); } if (includeFields is null) { return Ok(ApiHelpers.MapTaskV1(task)); } return Ok(ApiHelpers.ShapeTask(task, includeFields)); } [HttpPost] [ProducesResponseType(typeof(TaskResponseV1), StatusCodes.Status201Created)] [ProducesResponseType(typeof(TaskResponseV1), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status409Conflict)] public async Task<ActionResult<TaskResponseV1>> CreateTask( [FromBody] TaskCreateRequestV1 request, [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey) { var title = ApiHelpers.NormalizeRequired(request.Title); if (title is null) { return BadRequest("Title is required."); } var userId = ApiHelpers.GetUserId(User); var key = ApiHelpers.NormalizeOptional(idempotencyKey); var requestHash = key is null ? null : ApiHelpers.ComputeRequestHash(request); if (key is not null && requestHash is not null) { var (existingTask, error) = await ApiHelpers.TryGetIdempotentTaskAsync(_db, userId, key, requestHash); if (error is not null) { return Conflict(error); } if (existingTask is not null) { return Ok(ApiHelpers.MapTaskV1(existingTask)); } } var now = DateTimeOffset.UtcNow; var task = new TaskItem { Id = Guid.NewGuid(), UserId = userId, Title = title, Description = request.Description?.Trim() ?? string.Empty, Status = request.Status, DueDate = request.DueDate, CreatedAt = now, UpdatedAt = now }; _db.Tasks.Add(task); if (key is not null && requestHash is not null) { _db.IdempotencyKeys.Add(new IdempotencyKey { Id = Guid.NewGuid(), UserId = userId, Key = key, RequestHash = requestHash, TaskId = task.Id, CreatedAt = now }); } await _db.SaveChangesAsync(); return Created($"/api/v1/tasks/{task.Id}", ApiHelpers.MapTaskV1(task)); } [HttpPut("{id:guid}")] [ProducesResponseType(typeof(TaskResponseV1), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task<ActionResult<TaskResponseV1>> UpdateTask(Guid id, [FromBody] TaskUpdateRequestV1 request) { var title = ApiHelpers.NormalizeRequired(request.Title); if (title is null) { return BadRequest("Title is required."); } var userId = ApiHelpers.GetUserId(User); var task = await _db.Tasks.FirstOrDefaultAsync(item => item.Id == id && item.UserId == userId); if (task is null) { return NotFound(); } task.Title = title; task.Description = request.Description?.Trim() ?? string.Empty; task.Status = request.Status; task.DueDate = request.DueDate; task.UpdatedAt = DateTimeOffset.UtcNow; await _db.SaveChangesAsync(); return Ok(ApiHelpers.MapTaskV1(task)); } [HttpDelete("{id:guid}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task<IActionResult> DeleteTask(Guid id) { var userId = ApiHelpers.GetUserId(User); var task = await _db.Tasks.FirstOrDefaultAsync(item => item.Id == id && item.UserId == userId); if (task is null) { return NotFound(); } _db.Tasks.Remove(task); await _db.SaveChangesAsync(); return NoContent(); } }