profileShare

rasmusjy / splitapp-backend-clean-onion

Read-only snapshot

No repository description.

main default branch 429 files Expires Sep 13, 2026, 9:06 AM
BudgetCategoriesController.cs 4,343 bytes
1 using App.BLL.DTO;
2 using App.BLL.Services;
3 using App.Domain;
4 using App.DTO.Mappers;
5 using App.DTO.v1;
6 using Asp.Versioning;
7 using Microsoft.AspNetCore.Authentication.JwtBearer;
8 using Microsoft.AspNetCore.Authorization;
9 using Microsoft.AspNetCore.Mvc;
10 using System.Net;
11 using System.Security.Claims;
12
13 namespace WebApp.ApiControllers;
14
15 [ApiVersion("1.0")]
16 [Route("api/v{version:apiVersion}/[controller]")]
17 [ApiController]
18 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
19 public class BudgetCategoriesController : ControllerBase
20 {
21 private readonly IBudgetCategoryService _budgetCategoryService;
22 private readonly ITripService _tripService;
23
24 public BudgetCategoriesController(IBudgetCategoryService budgetCategoryService, ITripService tripService)
25 {
26 _budgetCategoryService = budgetCategoryService;
27 _tripService = tripService;
28 }
29
30 private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
31
32 // GET: api/v1/budgetcategories/trip/{tripId}
33 [HttpGet("trip/{tripId:guid}")]
34 [Produces("application/json")]
35 [ProducesResponseType<List<BudgetCategoryDto>>((int)HttpStatusCode.OK)]
36 [ProducesResponseType((int)HttpStatusCode.Forbidden)]
37 public async Task<ActionResult<List<BudgetCategoryDto>>> GetTripBudgetCategories(Guid tripId)
38 {
39 var userId = GetUserId();
40
41 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
42
43 var categories = await _budgetCategoryService.GetByTripIdAsync(tripId, userId);
44
45 return Ok(categories.Select(BudgetCategoryMapper.MapToDto).ToList());
46 }
47
48 // POST: api/v1/budgetcategories
49 [HttpPost]
50 [Produces("application/json")]
51 [Consumes("application/json")]
52 [ProducesResponseType<BudgetCategoryDto>((int)HttpStatusCode.Created)]
53 [ProducesResponseType((int)HttpStatusCode.Forbidden)]
54 public async Task<ActionResult<BudgetCategoryDto>> CreateBudgetCategory([FromBody] BudgetCategoryCreateDto dto)
55 {
56 var userId = GetUserId();
57
58 var category = new BudgetCategoryBllDto
59 {
60 TripId = dto.TripId,
61 Name = dto.Name,
62 IconName = dto.IconName,
63 PlannedAmount = dto.PlannedAmount,
64 DisplayOrder = dto.DisplayOrder
65 };
66
67 var (created, errorCode) = await _budgetCategoryService.CreateAsync(category, userId);
68 if (created == null)
69 {
70 if (errorCode == "forbidden") return Forbid();
71 return NotFound();
72 }
73
74 return CreatedAtAction(null, new { id = created.Id }, BudgetCategoryMapper.MapToDto(created));
75 }
76
77 // PUT: api/v1/budgetcategories/{id}
78 [HttpPut("{id:guid}")]
79 [Consumes("application/json")]
80 [ProducesResponseType((int)HttpStatusCode.NoContent)]
81 [ProducesResponseType((int)HttpStatusCode.NotFound)]
82 [ProducesResponseType((int)HttpStatusCode.Forbidden)]
83 public async Task<IActionResult> UpdateBudgetCategory(Guid id, [FromBody] BudgetCategoryCreateDto dto)
84 {
85 var userId = GetUserId();
86
87 var incoming = new BudgetCategoryBllDto
88 {
89 Name = dto.Name,
90 IconName = dto.IconName,
91 PlannedAmount = dto.PlannedAmount,
92 DisplayOrder = dto.DisplayOrder
93 };
94
95 var (ok, errorCode) = await _budgetCategoryService.UpdateAsync(id, incoming, userId);
96 if (!ok)
97 {
98 return errorCode switch
99 {
100 "notfound" => NotFound(),
101 "forbidden" => Forbid(),
102 _ => NotFound()
103 };
104 }
105
106 return NoContent();
107 }
108
109 // DELETE: api/v1/budgetcategories/{id}
110 [HttpDelete("{id:guid}")]
111 [ProducesResponseType((int)HttpStatusCode.NoContent)]
112 [ProducesResponseType((int)HttpStatusCode.NotFound)]
113 [ProducesResponseType((int)HttpStatusCode.Forbidden)]
114 public async Task<IActionResult> DeleteBudgetCategory(Guid id)
115 {
116 var userId = GetUserId();
117
118 var (ok, errorCode) = await _budgetCategoryService.DeleteAsync(id, userId);
119 if (!ok)
120 {
121 return errorCode switch
122 {
123 "notfound" => NotFound(),
124 "forbidden" => Forbid(),
125 _ => NotFound()
126 };
127 }
128
129 return NoContent();
130 }
131 }
132