summaryrefslogtreecommitdiffstats
path: root/src/Controllers
diff options
context:
space:
mode:
authorivar <i@oiee.no>2025-10-19 23:41:23 +0200
committerivar <i@oiee.no>2025-10-19 23:41:23 +0200
commit3f4c0720e1e3421431e7baa20882a4a4512a7fab (patch)
tree734ca81d7d0841d8863e3f523ebba14c282dc681 /src/Controllers
downloadfagprove-3f4c0720e1e3421431e7baa20882a4a4512a7fab.tar.xz
fagprove-3f4c0720e1e3421431e7baa20882a4a4512a7fab.zip
InitialHEADmaster
Diffstat (limited to 'src/Controllers')
-rw-r--r--src/Controllers/AccountController.cs97
-rw-r--r--src/Controllers/BaseController.cs30
-rw-r--r--src/Controllers/CabinsController.cs93
-rw-r--r--src/Controllers/ReservationsController.cs137
-rw-r--r--src/Controllers/UsersController.cs93
5 files changed, 450 insertions, 0 deletions
diff --git a/src/Controllers/AccountController.cs b/src/Controllers/AccountController.cs
new file mode 100644
index 0000000..e1f6946
--- /dev/null
+++ b/src/Controllers/AccountController.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using IOL.Fagprove.Data;
+using IOL.Fagprove.Data.DTOs;
+using IOL.Fagprove.Services.Interfaces;
+using IOL.Fagprove.Utilities;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace IOL.Fagprove.Controllers
+{
+ public class AccountController : BaseController
+ {
+ private readonly AppDbContext _context;
+ private readonly IUserService _userService;
+
+ public AccountController(AppDbContext context, IUserService userService)
+ {
+ _context = context;
+ _userService = userService;
+ }
+
+ [HttpPost("login")]
+ [ValidateAntiForgeryToken]
+ [AllowAnonymous]
+ public async Task<ActionResult> Login(LoginDto data)
+ {
+ if (data.Password.IsMissing() || data.Username.IsMissing()) return BadRequest("Ett eller flere felt er ikke fylt inn.");
+ if (data.Username.IsEmail() == false) return BadRequest("Det ser ikke ut som en e-postadresse");
+ var user = _context.Users.SingleOrDefault(u => u.Email == data.Username);
+ var passwordMatches = PasswordHasher.PasswordMatches(user?.Password ?? string.Empty, data.Password ?? string.Empty);
+ if (user == default || passwordMatches == false) return BadRequest("E-postadresse eller passord er feil");
+
+ var claims = new List<Claim>
+ {
+ new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
+ new Claim(ClaimTypes.Name, user.Name),
+ new Claim(ClaimTypes.Role, user.Role.ToString())
+ };
+
+ var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
+ var authenticationProperties = new AuthenticationProperties
+ {
+ AllowRefresh = true,
+ IssuedUtc = DateTimeOffset.UtcNow
+ };
+
+ await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
+ new ClaimsPrincipal(claimsIdentity), authenticationProperties);
+ return Ok();
+ }
+
+ [HttpGet("logout")]
+ public async Task<ActionResult> Logout()
+ {
+ await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ return Redirect("/");
+ }
+
+ [AllowAnonymous]
+ [HttpPost("forgot")]
+ public ActionResult StartForgotPasswordFlow(string email)
+ {
+ var user = _context.Users.SingleOrDefault(u => u.Email == email);
+ if (user == default) return Ok();
+ var task = _userService.SetNewTemporaryPasswordAndNotifyUser(user);
+ if (task) return Ok();
+ return StatusCode(500);
+ }
+
+ [HttpPut("password")]
+ public ActionResult SetPasswordAfterTemporary(UpdatePasswordDto data)
+ {
+ var user = _context.Users.SingleOrDefault(u => u.Id == LoggedInUser.Id);
+ if (user == default)
+ {
+ SignOut();
+ return Unauthorized(new { error = "Vi fant deg ikke i våre systemer." });
+ }
+
+ if (data.Password.IsMissing() || data.Password.IsMissing())
+ {
+ return BadRequest(new { error = "Ett eller flere felt er ikke fylt inn." });
+ }
+ if (data.Password.Length <= 5) return BadRequest(new { error = "Passordet er ikke langt nok." });
+ if (data.Password != data.PasswordOnceMore) return BadRequest(new { error = "Passordene er forksjellige" });
+ var passwordIsUpdated = _userService.UpdatePassword(user, data.Password);
+ if (passwordIsUpdated) return Ok();
+ return StatusCode(500, new { error = "Noe gikk galt, vennligst prøv igjen senere." });
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Controllers/BaseController.cs b/src/Controllers/BaseController.cs
new file mode 100644
index 0000000..c90bfb4
--- /dev/null
+++ b/src/Controllers/BaseController.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Security.Claims;
+using IOL.Fagprove.Data.Enums;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using IOL.Fagprove.Utilities;
+
+namespace IOL.Fagprove.Controllers
+{
+ [Authorize]
+ [Produces(("application/json"))]
+ [ApiController]
+ [Route("api/[controller]")]
+ public class BaseController : ControllerBase
+ {
+ public LoggedInUserModel LoggedInUser => new LoggedInUserModel
+ {
+ Id = User.GetClaimValue(ClaimTypes.NameIdentifier).ToGuid(),
+ Name = User.GetClaimValue(ClaimTypes.Name),
+ Role = User.GetClaimValue(ClaimTypes.Role).ToUserRole()
+ };
+
+ public class LoggedInUserModel
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ public UserRole Role { get; set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Controllers/CabinsController.cs b/src/Controllers/CabinsController.cs
new file mode 100644
index 0000000..4fe87cc
--- /dev/null
+++ b/src/Controllers/CabinsController.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection.Metadata;
+using IOL.Fagprove.Data;
+using IOL.Fagprove.Data.DTOs;
+using IOL.Fagprove.Data.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using IOL.Fagprove.Utilities;
+
+namespace IOL.Fagprove.Controllers
+{
+ [Authorize("Administrator")]
+ public class CabinsController : BaseController
+ {
+ private readonly AppDbContext _context;
+
+ public CabinsController(AppDbContext context)
+ {
+ _context = context;
+ }
+
+ [HttpGet]
+ public ActionResult<List<CabinDto>> GetCabins()
+ {
+ var cabins = _context.Cabins.ToList();
+ var res = new List<CabinDto>();
+ foreach (var cabin in cabins)
+ {
+ var fieldName = StaticData.CabinFields.FirstOrDefault(s => s.Id == cabin.CategoryId)?.Name ?? "Ukjent";
+ res.Add(new CabinDto
+ {
+ Capacity = cabin.Capacity,
+ Description = cabin.Description,
+ Id = cabin.Id,
+ Name = cabin.Name,
+ Price = cabin.Price,
+ CategoryId = cabin.CategoryId,
+ CategoryName = fieldName
+ });
+ }
+
+ return res;
+ }
+
+ [HttpPost("create")]
+ public ActionResult CreateCabin(ReservationObject data)
+ {
+ if (data.Name.IsMissing()) return BadRequest(new {error = "Navn er påkrevd"});
+ data.CreatedBy = LoggedInUser.Id;
+ data.CreatedUtc = DateTime.UtcNow;
+ _context.Cabins.Add(data);
+ _context.SaveChanges();
+ return Ok(data.Name);
+ }
+
+ [HttpPut("update")]
+ public ActionResult UpdateCabin(ReservationObject data)
+ {
+ if (data.Name.IsMissing()) return BadRequest("Navn er påkrevd");
+ if (data.Id == Guid.Empty) return BadRequest();
+ var cabinExists = _context.Cabins.Any(c => c.Id == data.Id);
+ if (!cabinExists) return BadRequest(new {error = "Fant ikke hytten"});
+ data.ModifiedBy = LoggedInUser.Id;
+ data.ModifiedUtc = DateTime.UtcNow;
+ _context.Cabins.Update(data);
+ _context.Entry(data).Property(x => x.CreatedBy).IsModified = false;
+ _context.Entry(data).Property(x => x.CreatedUtc).IsModified = false;
+ _context.Entry(data).Property(x => x.Id).IsModified = false;
+ _context.SaveChanges();
+ return Ok();
+ }
+
+ [HttpDelete("delete")]
+ public ActionResult DeleteCabin(CabinDto data)
+ {
+ var cabinToRemove = _context.Cabins.SingleOrDefault(c => c.Id == data.Id);
+ if (cabinToRemove == default) return Ok();
+ _context.Cabins.Remove(cabinToRemove);
+ var existingFutureReservationsForThisCabin = _context.Reservations.Where(r => r.ReservationObjectId == cabinToRemove.Id
+ && DateTime.Compare(r.From, DateTime.Today) >= 0).ToList();
+ if (existingFutureReservationsForThisCabin.Count != 0)
+ {
+ _context.Reservations.RemoveRange(existingFutureReservationsForThisCabin);
+ }
+
+ _context.SaveChanges();
+ return Ok();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Controllers/ReservationsController.cs b/src/Controllers/ReservationsController.cs
new file mode 100644
index 0000000..912f591
--- /dev/null
+++ b/src/Controllers/ReservationsController.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Runtime.InteropServices.ComTypes;
+using Flurl.Util;
+using IOL.Fagprove.Data;
+using IOL.Fagprove.Data.DTOs;
+using IOL.Fagprove.Data.Enums;
+using IOL.Fagprove.Data.Models;
+using IOL.Fagprove.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Graph;
+using IOL.Fagprove.Services;
+
+namespace IOL.Fagprove.Controllers
+{
+ public class ReservationsController : BaseController
+ {
+ private readonly AppDbContext _context;
+ private readonly IAppReservationService _reservationService;
+
+ public ReservationsController(AppDbContext context, IAppReservationService reservationService)
+ {
+ _context = context;
+ _reservationService = reservationService;
+ }
+ // /api/reservations
+ [HttpGet]
+ public ActionResult<List<Reservation>> GetReservationsForUser()
+ {
+ return _context.Reservations.Where(r => r.UserId == LoggedInUser.Id).ToList();
+ }
+
+ [HttpGet("all")]
+ [Authorize("Administrator")]
+ public ActionResult<List<ReservationDto>> GetAllReservations()
+ {
+ return _context.Reservations.Select(r => new ReservationDto
+ {
+ Id = r.Id,
+ Cabin = _context.Cabins.SingleOrDefault(c => c.Id == r.ReservationObjectId).Name ?? "",
+ From = r.From.ToString("dd-MM-yyyy"),
+ To = r.To.ToString("dd-MM-yyyy"),
+ Status = r.Status,
+ Name = _context.Users.SingleOrDefault(u => u.Id == r.UserId).Name ?? "Ukjent bruker"
+ }).ToList();
+ }
+
+ [HttpGet("occupancy")]
+ public ActionResult<List<DateTime>> GetOccupany(Guid cabinId)
+ {
+ var today = DateTime.Today;
+ var reservationsForThisCabin = _context.Reservations.Where(r => r.ReservationObjectId == cabinId
+ && r.From > today && r.Status == ReservationStatus.Granted).ToList();
+ if (reservationsForThisCabin.Count == 0) return default;
+ var occupiedDates = new List<DateTime>();
+ foreach (var reservation in reservationsForThisCabin)
+ {
+ for (var dt = reservation.From; dt <= reservation.To; dt = dt.AddDays(1))
+ {
+ occupiedDates.Add(dt.Date);
+ }
+ }
+
+ return occupiedDates;
+ }
+
+ [HttpPost("create")]
+ public ActionResult CreateReservation(Reservation data)
+ {
+ var reservationIsPossible = _reservationService.ReservationIsPossible(data);
+ if (!reservationIsPossible) return BadRequest(new {error = "Reservasjonen er ikke mulig lenger."});
+ data.UserId = LoggedInUser.Id;
+ data.CreatedBy = LoggedInUser.Id;
+ data.CreatedUtc = DateTime.UtcNow;
+ data.Status = ReservationStatus.Pending;
+ _context.Reservations.Add(data);
+ _context.SaveChanges();
+ return Ok();
+ }
+
+ [HttpGet("grant")]
+ [Authorize("Administrator")]
+ public ActionResult GrantReservation(Guid id)
+ {
+ if (id == Guid.Empty) return BadRequest();
+ var reservation = _context.Reservations.SingleOrDefault(r => r.Id == id);
+ if (reservation == default) return BadRequest(new {error = "Fant ikke reservasjonen"});
+ if (reservation.Status == ReservationStatus.Granted || reservation.Status == ReservationStatus.Expired) return BadRequest(new {error = "Denne reservasjonen er allerede godkjent"});
+ reservation.Status = ReservationStatus.Granted;
+ reservation.ModifiedBy = LoggedInUser.Id;
+ reservation.ModifiedUtc = DateTime.UtcNow;
+ _context.Reservations.Update(reservation);
+ _context.Entry(reservation).Property(x => x.CreatedBy).IsModified = false;
+ _context.Entry(reservation).Property(x => x.CreatedUtc).IsModified = false;
+ _context.Entry(reservation).Property(x => x.Id).IsModified = false;
+ _context.SaveChanges();
+ // TODO: Inform user if mail fails
+ var emailSent = _reservationService.SendReservationStatusMail(reservation);
+ return Ok();
+ }
+
+ [HttpGet("deny")]
+ [Authorize("Administrator")]
+ public ActionResult DenyReservation(Guid id)
+ {
+ if (id == Guid.Empty) return BadRequest();
+ var reservation = _context.Reservations.SingleOrDefault(r => r.Id == id);
+ if (reservation == default) return BadRequest(new {error = "Fant ikke reservasjonen"});
+ if (reservation.Status == ReservationStatus.Rejected || reservation.Status == ReservationStatus.Expired) return BadRequest(new {error = "Denne reservasjonen er allerede avvist"});
+ reservation.Status = ReservationStatus.Rejected;
+ reservation.ModifiedBy = LoggedInUser.Id;
+ reservation.ModifiedUtc = DateTime.UtcNow;
+ _context.Reservations.Update(reservation);
+ _context.Entry(reservation).Property(x => x.CreatedBy).IsModified = false;
+ _context.Entry(reservation).Property(x => x.CreatedUtc).IsModified = false;
+ _context.Entry(reservation).Property(x => x.Id).IsModified = false;
+ _context.SaveChanges();
+ // TODO: Inform user if mail fails
+ var emailSent = _reservationService.SendReservationStatusMail(reservation);
+ return Ok();
+ }
+
+ [HttpDelete("delete")]
+ public ActionResult DeleteReservation(Guid reservationId)
+ {
+ var reservation = _context.Reservations.SingleOrDefault(r => r.Id == reservationId);
+ if (reservation == default) return BadRequest(new {error = "Fant ikke reservasjonen"});
+ if (reservation.UserId != LoggedInUser.Id) return Unauthorized(new {error = "Du har ikke lov til å slette denne reservasjonen"});
+ _context.Reservations.Remove(reservation);
+ _context.SaveChanges();
+ return Ok();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Controllers/UsersController.cs b/src/Controllers/UsersController.cs
new file mode 100644
index 0000000..0d3211b
--- /dev/null
+++ b/src/Controllers/UsersController.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using IOL.Fagprove.Data;
+using IOL.Fagprove.Data.DTOs;
+using IOL.Fagprove.Data.Models;
+using IOL.Fagprove.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace IOL.Fagprove.Controllers
+{
+ [Authorize("Administrator")]
+ public class UsersController : BaseController
+ {
+ private readonly AppDbContext _context;
+ private readonly IUserService _userService;
+
+ public UsersController(AppDbContext context, IUserService userService)
+ {
+ _context = context;
+ _userService = userService;
+ }
+
+ [HttpGet]
+ public ActionResult<List<UserDto>> GetUsers()
+ {
+ return _context.Users.Select(u => new UserDto
+ {
+ Email = u.Email,
+ Id = u.Id,
+ Name = u.Name,
+ Role = u.Role
+ }).ToList();
+ }
+
+ [HttpPost("create")]
+ public ActionResult CreateUser(UserDto payload)
+ {
+ var userExists = _context.Users.Any(u => u.Email == payload.Email);
+ if (userExists)
+ return BadRequest(new {error = "En bruker med den e-postadressen finnes allerede"});
+ var newUser = new User
+ {
+ Email = payload.Email,
+ Name = payload.Name,
+ Role = payload.Role,
+ CreatedBy = LoggedInUser.Id,
+ CreatedUtc = DateTime.UtcNow,
+ Id = Guid.NewGuid()
+ };
+ _context.Users.Add(newUser);
+ _context.SaveChanges();
+ var welcomeTask = _userService.SetTemporaryPasswordAndSendWelcomeMail(newUser);
+ if (!welcomeTask)
+ return StatusCode(500, new {error = "En feil oppstod, prøv igjen senere"});
+ return Ok(payload);
+ }
+
+ [HttpDelete("delete")]
+ public ActionResult DeleteUser(UserDto payload)
+ {
+ var userToDelete = _context.Users.SingleOrDefault(u => u.Id == payload.Id);
+ if (userToDelete == default) return BadRequest(new {error = "Fant ikke brukeren"});
+ _context.Users.Remove(userToDelete);
+ _context.SaveChanges();
+ return Ok(userToDelete.Name);
+ }
+
+ [HttpPut("update")]
+ public ActionResult UpdateUser(UserDto payload)
+ {
+ var user = _context.Users.SingleOrDefault(u => u.Id == payload.Id);
+ if (user == default) return BadRequest(new {error = "Fant ikke brukeren"});
+ if (user.Email != payload.Email)
+ {
+ var userExists = _context.Users.Any(u => u.Email == payload.Email);
+ if (userExists) return BadRequest(new {error = "En bruker med den e-postadressen finnes allerede"});
+ }
+ user.ModifiedBy = LoggedInUser.Id;
+ user.ModifiedUtc = DateTime.UtcNow;
+ user.Email = payload.Email;
+ user.Name = payload.Name;
+ user.Role = payload.Role;
+ _context.Users.Update(user);
+ _context.Entry(user).Property(x => x.CreatedBy).IsModified = false;
+ _context.Entry(user).Property(x => x.CreatedUtc).IsModified = false;
+ _context.Entry(user).Property(x => x.Id).IsModified = false;
+ _context.SaveChanges();
+ return Ok();
+ }
+ }
+} \ No newline at end of file