48 lines
2.6 KiB
C#
48 lines
2.6 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using QuestionsApi.Models;
|
|
using QuestionsApi.Services;
|
|
using System.Security.Claims;
|
|
|
|
namespace QuestionsApi.Controllers;
|
|
|
|
[ApiController, Route("api/app-feedback")]
|
|
public sealed class AppFeedbackController(AppFeedbackStore feedback) : ControllerBase
|
|
{
|
|
private const int MaxReviewerNoteLength = 2000;
|
|
|
|
[HttpPost, Authorize(Roles = "USER,SUPER")]
|
|
public async Task<IActionResult> Create(CreateAppFeedbackRequest request)
|
|
{
|
|
if (AppFeedbackValidator.Validate(request) is { } error) return BadRequest(error);
|
|
var report = await feedback.CreateAsync(UserId(), request);
|
|
return StatusCode(StatusCodes.Status201Created, new { id = report.Id, report.Category, report.Status, report.CreatedUtc });
|
|
}
|
|
|
|
[HttpGet, Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> List([FromQuery] string status = "open", [FromQuery] string category = "", [FromQuery] string userId = "", [FromQuery] int skip = 0, [FromQuery] int limit = 50)
|
|
{
|
|
status = status.Trim().ToLowerInvariant(); category = category.Trim().ToLowerInvariant(); userId = userId.Trim();
|
|
if (status != "all" && status != QuestionReportStatus.Open && !QuestionReportStatus.Terminal.Contains(status)) return BadRequest("status is invalid");
|
|
if (category.Length > 0 && !AppFeedbackCategory.All.Contains(category)) return BadRequest("category is invalid");
|
|
if (skip < 0 || limit is < 1 or > 100) return BadRequest("pagination is invalid");
|
|
return Ok(await feedback.SearchAsync(status, category, userId, skip, limit));
|
|
}
|
|
|
|
[HttpGet("{id}"), Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> Get(string id) => await feedback.GetAsync(id.Trim()) is { } report ? Ok(report) : NotFound();
|
|
|
|
[HttpPatch("{id}/status"), Authorize(Roles = "SUPER")]
|
|
public async Task<IActionResult> Close(string id, UpdateQuestionReportStatusRequest request)
|
|
{
|
|
var status = (request.Status ?? "").Trim().ToLowerInvariant();
|
|
var note = (request.ReviewerNote ?? "").Trim();
|
|
if (!QuestionReportStatus.Terminal.Contains(status)) return BadRequest("status must be resolved or dismissed");
|
|
if (note.Length > MaxReviewerNoteLength) return BadRequest($"reviewerNote must be {MaxReviewerNoteLength} characters or fewer");
|
|
var updated = await feedback.CloseAsync(id.Trim(), status, UserId(), note);
|
|
return updated is null ? Conflict("feedback is missing or already closed") : Ok(updated);
|
|
}
|
|
|
|
private string UserId() => User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue(ClaimTypes.Name) ?? User.Identity?.Name ?? "";
|
|
}
|