profileShare

rasmusjy / splitapp-backend-clean-onion

Read-only snapshot

No repository description.

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