source: KernelRecordsMVC.Web/Controllers/AccountController.cs@ d2eccb3

main
Last change on this file since d2eccb3 was fa0fbaf, checked in by mmilevski <markomilevski3@…>, 4 weeks ago

Added major improvements.

  • Property mode set to 100644
File size: 10.0 KB
Line 
1using System.Security.Claims;
2using KernelRecordsMVC.Application.ViewModels;
3using KernelRecordsMVC.Infrastructure.Data;
4using KernelRecordsMVC.Models;
5using Microsoft.AspNetCore.Authentication;
6using Microsoft.AspNetCore.Mvc;
7using Microsoft.EntityFrameworkCore;
8
9namespace KernelRecordsMVC.Web.Controllers;
10
11public class AccountController : Controller
12{
13 private readonly KernelRecordsContext _context;
14
15 public AccountController(KernelRecordsContext context)
16 {
17 _context = context;
18 }
19
20
21 // =========================================================
22 // REGISTER - GET
23 // =========================================================
24
25 [HttpGet]
26 public IActionResult Register()
27 {
28 return View();
29 }
30
31
32 // =========================================================
33 // REGISTER - POST
34 // =========================================================
35
36 [HttpPost]
37 [ValidateAntiForgeryToken]
38 public IActionResult Register(RegisterViewModel model)
39 {
40 if (!ModelState.IsValid)
41 return View(model);
42
43 if (_context.Users.Any(x => x.Username == model.Username))
44 {
45 ModelState.AddModelError(
46 "Username",
47 "Username is already taken.");
48
49 return View(model);
50 }
51
52 if (_context.Users.Any(x => x.Email == model.Email))
53 {
54 ModelState.AddModelError(
55 "Email",
56 "Email is already registered.");
57
58 return View(model);
59 }
60
61 var user = new User
62 {
63 Email = model.Email,
64 Username = model.Username,
65
66 // TODO:
67 // Replace with password hashing later.
68 Password = model.Password,
69
70 DateCreated = DateTime.Today,
71 ShippingAddress = model.ShippingAddress,
72 TelephoneNumber = model.TelephoneNumber
73 };
74
75 _context.Users.Add(user);
76
77 _context.SaveChanges();
78
79
80 // Every normal registered user is a Consumer.
81 var consumer = new Consumer
82 {
83 UserId = user.UserId,
84 PointsCollected = 0
85 };
86
87 _context.Consumers.Add(consumer);
88
89 _context.SaveChanges();
90
91 return RedirectToAction(nameof(Login));
92 }
93
94
95 // =========================================================
96 // LOGIN - GET
97 // =========================================================
98
99 [HttpGet]
100 public IActionResult Login()
101 {
102 return View();
103 }
104
105
106 // =========================================================
107 // LOGIN - POST
108 // =========================================================
109
110 [HttpPost]
111 [ValidateAntiForgeryToken]
112 public async Task<IActionResult> Login(
113 LoginViewModel model)
114 {
115 if (!ModelState.IsValid)
116 return View(model);
117
118 var user = _context.Users
119 .FirstOrDefault(x =>
120 x.Username == model.Username &&
121 x.Password == model.Password);
122
123 if (user == null)
124 {
125 ModelState.AddModelError(
126 "",
127 "Invalid username or password.");
128
129 return View(model);
130 }
131
132
133 // =====================================================
134 // DETERMINE ACCOUNT TYPE
135 // =====================================================
136
137 var admin = _context.Admins
138 .FirstOrDefault(x => x.UserId == user.UserId);
139
140 string role;
141
142 if (admin != null)
143 {
144 role = "Admin";
145 }
146 else
147 {
148 role = "Consumer";
149 }
150
151
152 // =====================================================
153 // CREATE CLAIMS
154 // =====================================================
155
156 var claims = new List<Claim>
157 {
158 new Claim(
159 ClaimTypes.NameIdentifier,
160 user.UserId.ToString()),
161
162 new Claim(
163 ClaimTypes.Name,
164 user.Username),
165
166 new Claim(
167 ClaimTypes.Email,
168 user.Email),
169
170 new Claim(
171 ClaimTypes.Role,
172 role)
173 };
174
175
176 if (admin != null)
177 {
178 claims.Add(
179 new Claim(
180 "AdminType",
181 admin.Type.ToString()));
182 }
183
184
185 var identity = new ClaimsIdentity(
186 claims,
187 "Cookies");
188
189 var principal =
190 new ClaimsPrincipal(identity);
191
192
193 // =====================================================
194 // SIGN IN
195 // =====================================================
196
197 await HttpContext.SignInAsync(
198 "Cookies",
199 principal);
200
201
202 // =====================================================
203 // KEEP SESSION FOR EXISTING CODE
204 // =====================================================
205
206 HttpContext.Session.SetInt32(
207 "UserId",
208 checked((int)user.UserId));
209
210 HttpContext.Session.SetString(
211 "Username",
212 user.Username);
213
214 HttpContext.Session.SetString(
215 "Role",
216 role);
217
218 if (admin != null)
219 {
220 HttpContext.Session.SetString(
221 "AdminType",
222 admin.Type.ToString());
223 }
224
225
226 return RedirectToAction(
227 "Index",
228 "Home");
229 }
230
231
232 // =========================================================
233 // PROFILE - GET
234 // =========================================================
235
236 [HttpGet]
237 public IActionResult Profile()
238 {
239 // Get logged-in user's ID from authentication claims.
240 var userIdClaim = User.FindFirst(
241 ClaimTypes.NameIdentifier);
242
243 if (userIdClaim == null)
244 return RedirectToAction(nameof(Login));
245
246 if (!long.TryParse(
247 userIdClaim.Value,
248 out var userId))
249 {
250 return RedirectToAction(nameof(Login));
251 }
252
253
254 // Load user + consumer information.
255 var user = _context.Users
256 .Include(x => x.Consumer)
257 .FirstOrDefault(x =>
258 x.UserId == userId);
259
260 if (user == null)
261 return NotFound();
262
263
264 var model = new ProfileViewModel
265 {
266 UserId = user.UserId,
267
268 Username = user.Username,
269
270 Email = user.Email,
271
272 TelephoneNumber =
273 user.TelephoneNumber,
274
275 ShippingAddress =
276 user.ShippingAddress,
277
278 DateCreated =
279 user.DateCreated,
280
281 PointsCollected =
282 user.Consumer?.PointsCollected ?? 0
283 };
284
285
286 return View(model);
287 }
288
289
290 // =========================================================
291 // PROFILE - POST
292 // =========================================================
293
294 [HttpPost]
295 [ValidateAntiForgeryToken]
296 public async Task<IActionResult> Profile(
297 ProfileViewModel model)
298 {
299 // Get the currently authenticated user.
300 var userIdClaim = User.FindFirst(
301 ClaimTypes.NameIdentifier);
302
303 if (userIdClaim == null)
304 return RedirectToAction(nameof(Login));
305
306 if (!long.TryParse(
307 userIdClaim.Value,
308 out var userId))
309 {
310 return RedirectToAction(nameof(Login));
311 }
312
313
314 if (!ModelState.IsValid)
315 return View(model);
316
317
318 var user = _context.Users
319 .FirstOrDefault(x =>
320 x.UserId == userId);
321
322 if (user == null)
323 return NotFound();
324
325
326 // =====================================================
327 // CHECK EMAIL
328 // =====================================================
329
330 var emailExists = _context.Users.Any(x =>
331 x.Email == model.Email &&
332 x.UserId != userId);
333
334 if (emailExists)
335 {
336 ModelState.AddModelError(
337 nameof(model.Email),
338 "This email is already registered.");
339
340 return View(model);
341 }
342
343
344 // =====================================================
345 // UPDATE USER
346 // =====================================================
347
348 user.Email = model.Email;
349
350 user.TelephoneNumber =
351 model.TelephoneNumber;
352
353 user.ShippingAddress =
354 model.ShippingAddress;
355
356
357 _context.SaveChanges();
358
359
360 TempData["Success"] =
361 "Your profile has been updated successfully.";
362
363
364 // =====================================================
365 // REFRESH EMAIL CLAIM
366 // =====================================================
367
368 var claims = new List<Claim>
369 {
370 new Claim(
371 ClaimTypes.NameIdentifier,
372 user.UserId.ToString()),
373
374 new Claim(
375 ClaimTypes.Name,
376 user.Username),
377
378 new Claim(
379 ClaimTypes.Email,
380 user.Email),
381
382 new Claim(
383 ClaimTypes.Role,
384 User.IsInRole("Admin")
385 ? "Admin"
386 : "Consumer")
387 };
388
389
390 var identity = new ClaimsIdentity(
391 claims,
392 "Cookies");
393
394 var principal =
395 new ClaimsPrincipal(identity);
396
397
398 await HttpContext.SignInAsync(
399 "Cookies",
400 principal);
401
402
403 // Keep session synchronized.
404 HttpContext.Session.SetString(
405 "Username",
406 user.Username);
407
408
409 return RedirectToAction(nameof(Profile));
410 }
411
412
413 // =========================================================
414 // LOGOUT
415 // =========================================================
416
417 [HttpPost]
418 [ValidateAntiForgeryToken]
419 public async Task<IActionResult> Logout()
420 {
421 await HttpContext.SignOutAsync("Cookies");
422
423 HttpContext.Session.Clear();
424
425 return RedirectToAction(
426 "Index",
427 "Home");
428 }
429}
Note: See TracBrowser for help on using the repository browser.