-
Notifications
You must be signed in to change notification settings - Fork 0
[WIP] Plan implementation for backend documentation updates #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c6760d7
9b2a7ef
aabd795
db43587
5514aa1
73c1202
6db8a88
afdcd3e
8239f1e
8887c02
ad071d6
b53c679
89c8c05
16f45d9
2df3e7b
80862a9
198716e
8449bb2
fde4b69
344b70e
dea845d
203c714
0e1ab70
bd1b04d
7894b2c
944ac7a
398e2fc
cdff00d
2b2b6fd
861b375
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,215 @@ | ||||||||||||
| using Microsoft.AspNetCore.Authorization; | ||||||||||||
| using Microsoft.AspNetCore.Mvc; | ||||||||||||
| using Taskdeck.Application.DTOs; | ||||||||||||
| using Taskdeck.Application.Interfaces; | ||||||||||||
| using Taskdeck.Application.Services; | ||||||||||||
| using Taskdeck.Domain.Entities; | ||||||||||||
| using Taskdeck.Domain.Exceptions; | ||||||||||||
|
|
||||||||||||
| namespace Taskdeck.Api.Controllers; | ||||||||||||
|
|
||||||||||||
| /// <summary> | ||||||||||||
| /// API endpoints for managing archived items and restoring them. | ||||||||||||
| /// </summary> | ||||||||||||
| [ApiController] | ||||||||||||
| [Authorize] | ||||||||||||
| [Route("api/archive")] | ||||||||||||
| public class ArchiveController : ControllerBase | ||||||||||||
| { | ||||||||||||
| private readonly IArchiveRecoveryService _archiveService; | ||||||||||||
| private readonly IUserContext _userContext; | ||||||||||||
|
|
||||||||||||
| public ArchiveController( | ||||||||||||
| IArchiveRecoveryService archiveService, | ||||||||||||
| IUserContext userContext) | ||||||||||||
| { | ||||||||||||
| _archiveService = archiveService; | ||||||||||||
| _userContext = userContext; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// <summary> | ||||||||||||
| /// Gets a list of archived items with optional filters. | ||||||||||||
| /// </summary> | ||||||||||||
| /// <param name="entityType">Filter by entity type (board, column, card)</param> | ||||||||||||
| /// <param name="boardId">Filter by board ID</param> | ||||||||||||
| /// <param name="status">Filter by restore status</param> | ||||||||||||
| /// <param name="limit">Maximum number of results (default: 100)</param> | ||||||||||||
| /// <param name="cancellationToken">Cancellation token</param> | ||||||||||||
| /// <returns>List of archive items</returns> | ||||||||||||
| [HttpGet("items")] | ||||||||||||
| public async Task<IActionResult> GetArchiveItems( | ||||||||||||
| [FromQuery] string? entityType, | ||||||||||||
| [FromQuery] Guid? boardId, | ||||||||||||
| [FromQuery] RestoreStatus? status, | ||||||||||||
| [FromQuery] int limit = 100, | ||||||||||||
| CancellationToken cancellationToken = default) | ||||||||||||
| { | ||||||||||||
| var result = await _archiveService.GetArchiveItemsAsync( | ||||||||||||
| entityType, | ||||||||||||
| boardId, | ||||||||||||
| status, | ||||||||||||
| limit, | ||||||||||||
| cancellationToken); | ||||||||||||
|
|
||||||||||||
| if (result.IsSuccess) | ||||||||||||
| return Ok(result.Value); | ||||||||||||
|
|
||||||||||||
| return result.ErrorCode switch | ||||||||||||
| { | ||||||||||||
| "NotFound" => NotFound(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | ||||||||||||
| "ValidationError" => BadRequest(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | ||||||||||||
| _ => Problem(result.ErrorMessage, statusCode: 500) | ||||||||||||
| }; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// <summary> | ||||||||||||
| /// Gets a specific archive item by ID. | ||||||||||||
| /// </summary> | ||||||||||||
| /// <param name="id">Archive item ID</param> | ||||||||||||
| /// <param name="cancellationToken">Cancellation token</param> | ||||||||||||
| /// <returns>Archive item details</returns> | ||||||||||||
| [HttpGet("items/{id}")] | ||||||||||||
| public async Task<IActionResult> GetArchiveItem(Guid id, CancellationToken cancellationToken = default) | ||||||||||||
| { | ||||||||||||
| var result = await _archiveService.GetArchiveItemByIdAsync(id, cancellationToken); | ||||||||||||
|
|
||||||||||||
| if (!result.IsSuccess) | ||||||||||||
| { | ||||||||||||
| return result.ErrorCode == "NotFound" | ||||||||||||
| ? NotFound(new { errorCode = result.ErrorCode, message = result.ErrorMessage }) | ||||||||||||
| : Problem(result.ErrorMessage, statusCode: 500); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return Ok(result.Value); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// <summary> | ||||||||||||
| /// Restores an archived item. | ||||||||||||
| /// </summary> | ||||||||||||
| /// <param name="entityType">Entity type (board, column, card)</param> | ||||||||||||
| /// <param name="entityId">Entity ID to restore</param> | ||||||||||||
| /// <param name="dto">Restore options</param> | ||||||||||||
| /// <param name="cancellationToken">Cancellation token</param> | ||||||||||||
| /// <returns>Restore result</returns> | ||||||||||||
| [HttpPost("{entityType}/{entityId}/restore")] | ||||||||||||
| public async Task<IActionResult> RestoreArchivedItem( | ||||||||||||
| string entityType, | ||||||||||||
| Guid entityId, | ||||||||||||
| [FromBody] RestoreArchiveItemDto dto, | ||||||||||||
| CancellationToken cancellationToken = default) | ||||||||||||
| { | ||||||||||||
| if (!TryNormalizeEntityType(entityType, out var normalizedEntityType, out var invalidTypeResult)) | ||||||||||||
| return invalidTypeResult!; | ||||||||||||
|
|
||||||||||||
| if (!TryGetCurrentUserId(out var restoredByUserId, out var userErrorResult)) | ||||||||||||
| return userErrorResult!; | ||||||||||||
|
|
||||||||||||
| var archiveItemResult = await _archiveService.GetArchiveItemByEntityAsync( | ||||||||||||
| normalizedEntityType, | ||||||||||||
| entityId, | ||||||||||||
| cancellationToken); | ||||||||||||
|
Comment on lines
+96
to
+110
|
||||||||||||
|
|
||||||||||||
| if (!archiveItemResult.IsSuccess) | ||||||||||||
| { | ||||||||||||
| return archiveItemResult.ErrorCode switch | ||||||||||||
| { | ||||||||||||
| "NotFound" => NotFound(new { errorCode = archiveItemResult.ErrorCode, message = archiveItemResult.ErrorMessage }), | ||||||||||||
| "ValidationError" => BadRequest(new { errorCode = archiveItemResult.ErrorCode, message = archiveItemResult.ErrorMessage }), | ||||||||||||
| "AuthenticationFailed" => Unauthorized(new { errorCode = archiveItemResult.ErrorCode, message = archiveItemResult.ErrorMessage }), | ||||||||||||
| "Unauthorized" => Unauthorized(new { errorCode = archiveItemResult.ErrorCode, message = archiveItemResult.ErrorMessage }), | ||||||||||||
| "Forbidden" => StatusCode(403, new { errorCode = archiveItemResult.ErrorCode, message = archiveItemResult.ErrorMessage }), | ||||||||||||
| _ => Problem(archiveItemResult.ErrorMessage, statusCode: 500) | ||||||||||||
| }; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| var archiveItem = archiveItemResult.Value; | ||||||||||||
| if (archiveItem.RestoreStatus != RestoreStatus.Available) | ||||||||||||
| { | ||||||||||||
| return Conflict(new | ||||||||||||
| { | ||||||||||||
| errorCode = ErrorCodes.InvalidOperation, | ||||||||||||
| message = $"Archive item for {normalizedEntityType} with ID {entityId} is in status {archiveItem.RestoreStatus}" | ||||||||||||
| }); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| var result = await _archiveService.RestoreArchiveItemAsync( | ||||||||||||
| archiveItem.Id, | ||||||||||||
| dto, | ||||||||||||
| restoredByUserId, | ||||||||||||
| cancellationToken); | ||||||||||||
|
|
||||||||||||
| if (!result.IsSuccess) | ||||||||||||
| { | ||||||||||||
| return result.ErrorCode switch | ||||||||||||
| { | ||||||||||||
| "NotFound" => NotFound(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | ||||||||||||
| "ValidationError" => BadRequest(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | ||||||||||||
| "Conflict" => Conflict(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | ||||||||||||
|
||||||||||||
| "Conflict" => Conflict(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | |
| "Conflict" => Conflict(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | |
| "Forbidden" => StatusCode(StatusCodes.Status403Forbidden, new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | |
| "InvalidOperation" => Conflict(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), | |
| "WipLimitExceeded" => Conflict(new { errorCode = result.ErrorCode, message = result.ErrorMessage }), |
Uh oh!
There was an error while loading. Please reload this page.