profileShare

rasmusjy / splitapp-backend-modular-monolith

Read-only snapshot

No repository description.

main default branch 418 files Expires Sep 13, 2026, 9:06 AM
PollsClientController.cs 4,748 bytes
1 using SplitApp.WebApp.Application.DTO;
2 using SplitApp.WebApp.Application.Services;
3 using SplitApp.Modules.Trips.Domain.Entities;
4 using SplitApp.Modules.Trips.Domain.Enums;
5 using SplitApp.Modules.Expenses.Domain.Entities;
6 using SplitApp.Modules.Expenses.Domain.Enums;
7 using SplitApp.Modules.Users.Domain.Entities;
8 using SplitApp.Modules.Users.Domain.Entities;
9 using Microsoft.AspNetCore.Authorization;
10 using Microsoft.AspNetCore.Identity;
11 using Microsoft.AspNetCore.Mvc;
12
13 namespace SplitApp.WebApp.Controllers;
14
15 [Authorize]
16 public class PollsClientController : Controller
17 {
18 private readonly ITripService _tripService;
19 private readonly IPollService _pollService;
20 private readonly UserManager<AppUser> _userManager;
21
22 public PollsClientController(
23 ITripService tripService,
24 IPollService pollService,
25 UserManager<AppUser> userManager)
26 {
27 _tripService = tripService;
28 _pollService = pollService;
29 _userManager = userManager;
30 }
31
32 private Guid GetUserId() => Guid.Parse(_userManager.GetUserId(User)!);
33
34 // GET: PollsClient?tripId=xxx
35 public async Task<IActionResult> Index(Guid tripId)
36 {
37 var userId = GetUserId();
38 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
39
40 var trip = await _tripService.GetByIdAsync(tripId, userId);
41 if (trip == null) return NotFound();
42
43 var polls = await _pollService.GetByTripIdAsync(tripId, userId);
44
45 ViewData["TripId"] = tripId;
46 ViewData["TripName"] = trip.Name;
47
48 return View(polls);
49 }
50
51 // GET: PollsClient/Create?tripId=xxx
52 public async Task<IActionResult> Create(Guid tripId)
53 {
54 var userId = GetUserId();
55 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
56
57 ViewData["TripId"] = tripId;
58 return View();
59 }
60
61 // POST: PollsClient/Create
62 [HttpPost]
63 [ValidateAntiForgeryToken]
64 public async Task<IActionResult> Create(Guid tripId, string question, bool allowMultipleVotes,
65 bool isAnonymous, string option1, string option2, string? option3, string? option4, string? option5)
66 {
67 var userId = GetUserId();
68 if (!await _tripService.IsParticipantAsync(tripId, userId)) return Forbid();
69
70 if (string.IsNullOrWhiteSpace(question) || string.IsNullOrWhiteSpace(option1) ||
71 string.IsNullOrWhiteSpace(option2))
72 {
73 ModelState.AddModelError("", "Question and at least 2 options are required.");
74 ViewData["TripId"] = tripId;
75 return View();
76 }
77
78 var poll = new TripPollBllDto
79 {
80 TripId = tripId,
81 CreatedByUserId = userId,
82 Question = question,
83 AllowMultipleVotes = allowMultipleVotes,
84 IsAnonymous = isAnonymous
85 };
86
87 var options = new[] { option1, option2, option3, option4, option5 }
88 .Where(o => !string.IsNullOrWhiteSpace(o))
89 .Select(o => o!)
90 .ToList();
91
92 var created = await _pollService.CreatePollWithOptionsAsync(poll, options);
93
94 return RedirectToAction(nameof(Details), new { id = created.Id });
95 }
96
97 // GET: PollsClient/Details/5
98 public async Task<IActionResult> Details(Guid id)
99 {
100 var userId = GetUserId();
101 var poll = await _pollService.GetByIdWithDetailsAsync(id, userId);
102
103 if (poll == null) return NotFound();
104
105 ViewData["TripId"] = poll.TripId;
106 ViewData["UserId"] = userId;
107 ViewData["IsCreator"] = poll.CreatedByUserId == userId;
108
109 return View(poll);
110 }
111
112 // POST: PollsClient/Vote
113 [HttpPost]
114 [ValidateAntiForgeryToken]
115 public async Task<IActionResult> Vote(Guid pollId, Guid optionId)
116 {
117 var userId = GetUserId();
118 var poll = await _pollService.GetByIdAsync(pollId, userId);
119
120 if (poll == null) return NotFound();
121
122 if (poll.ClosedAt != null) return RedirectToAction(nameof(Details), new { id = pollId });
123
124 await _pollService.ToggleVoteAsync(pollId, optionId, userId);
125
126 return RedirectToAction(nameof(Details), new { id = pollId });
127 }
128
129 // POST: PollsClient/Close/5
130 [HttpPost]
131 [ValidateAntiForgeryToken]
132 public async Task<IActionResult> Close(Guid id)
133 {
134 var userId = GetUserId();
135 var (ok, errorCode) = await _pollService.ClosePollAsync(id, userId, organizerAllowed: false);
136 if (!ok)
137 {
138 return errorCode switch
139 {
140 "notfound" => NotFound(),
141 "forbidden" => Forbid(),
142 _ => NotFound()
143 };
144 }
145
146 return RedirectToAction(nameof(Details), new { id });
147 }
148 }
149