diff --git a/backend/Api/BusinessLogic/DeviceLogic.cs b/backend/Api/BusinessLogic/DeviceLogic.cs index ebb1d0a..b49db03 100644 --- a/backend/Api/BusinessLogic/DeviceLogic.cs +++ b/backend/Api/BusinessLogic/DeviceLogic.cs @@ -3,6 +3,7 @@ using Api.Models; using Api.Models.Devices; using Api.Models.Users; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; namespace Api.BusinessLogic { @@ -25,14 +26,28 @@ namespace Api.BusinessLogic /// returns the devices in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason public async Task GetDevices(int userId) { - var profile = await _dbAccess.ReadUser(userId); + var userDetails = await _dbAccess.ReadUserDetails(userId); - if (profile == null) { return new ConflictObjectResult(new { message = "Could not find user" }); } + if (userDetails.Devices.Count == 0) { return new OkObjectResult(new { message = "Could not find any devices connected to the user" }); } - var devices = await _dbAccess.ReadDevices(userId); - if (devices.Count == 0) { return new OkObjectResult(new { message = "Could not find any devices connected to the user" }); } + List devices = new List(); + foreach (var item in userDetails.Devices) + { + var latestLog = item.Logs?.OrderByDescending(log => log.Date).FirstOrDefault(); // Get the latest log + GetDeviceDTO device = new GetDeviceDTO + { + Id = item.Id, + Name = item.Name, + TempHigh = item.TempHigh, + TempLow = item.TempLow, + ReferenceId = item.ReferenceId, + LatestLog = latestLog + }; + + devices.Add(device); + } return new OkObjectResult(devices); } @@ -45,12 +60,10 @@ namespace Api.BusinessLogic /// returns true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason public async Task AddDevice(string referenceId, int userId) { - var profile = await _dbAccess.ReadUser(userId); + var user = await _dbAccess.ReadUserDetails(userId); var possibleDevice = _dbAccess.ReadDevice(referenceId); if (possibleDevice != null) { return new ConflictObjectResult(new { message = "Device with given referenceId already exists" }); } - - - if (profile == null) { return new ConflictObjectResult(new { message = "Could not find user" }); } + if (user == null) { return new ConflictObjectResult(new { message = "Could not find user" }); } Device device = new Device { @@ -61,8 +74,49 @@ namespace Api.BusinessLogic Logs = new List(), }; + user.Devices.Add(device); - return await _dbAccess.CreateDevice(device, userId); + return await _dbAccess.CreateDevice(user); + } + + /// + /// Checks if the deviceId matches a device + /// + /// The updated info + /// The device to be edited + /// returns the updated device in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason + public async Task EditDevice(EditDeviceRequest request, int deviceId) + { + var device = await _dbAccess.ReadDevice(deviceId); + if (device != null) + { + if (device.Name == "" || device.Name == null) + return new ConflictObjectResult(new { message = "Please enter a name" }); + + device.Name = request.Name; + device.TempLow = request.TempLow; + device.TempHigh = request.TempHigh; + + } + + return await _dbAccess.EditDevice(device); + } + + /// + /// deletes a device + /// + /// the id used to delete + /// Used for deleting device from devices list in user + /// returns OK + public async Task DeleteDevice(int deviceId) + { + var device = await _dbAccess.ReadDevice(deviceId); + if (device != null) + { + return await _dbAccess.DeleteDevice(device); + + } + return new ConflictObjectResult(new { message = "Invalid user" }); } /// @@ -83,27 +137,5 @@ namespace Api.BusinessLogic return new OkObjectResult(logs); } - - /// - /// Checks if the deviceId matches a device - /// - /// The updated info - /// The device to be edited - /// returns the updated device in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task EditDevice(EditDeviceRequest device, int deviceId) - { - return await _dbAccess.EditDevice(device, deviceId); - } - - /// - /// deletes a device - /// - /// the id used to delete - /// Used for deleting device from devices list in user - /// returns OK - public async Task DeleteDevice(int deviceId, int userId) - { - return await _dbAccess.DeleteDevice(deviceId, userId); - } } } diff --git a/backend/Api/BusinessLogic/UserLogic.cs b/backend/Api/BusinessLogic/UserLogic.cs index 1a005cf..d17d16a 100644 --- a/backend/Api/BusinessLogic/UserLogic.cs +++ b/backend/Api/BusinessLogic/UserLogic.cs @@ -4,12 +4,14 @@ using Api.Models.Devices; using Api.Models.Users; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace Api.BusinessLogic { @@ -26,7 +28,7 @@ namespace Api.BusinessLogic public async Task getUser(int userId) { - User user = await _dbAccess.getUser(userId); + User user = await _dbAccess.ReadUser(userId); if (user == null || user.Id == 0) { return new ConflictObjectResult(new { message = "Could not find user" }); } return new OkObjectResult(new { user.Id, user.UserName, user.Email }); @@ -40,29 +42,44 @@ namespace Api.BusinessLogic /// /// The new user /// returns true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task RegisterUser(User user) + public async Task RegisterUser(CreateUserRequest request) { - if (!new Regex(@".+@.+\..+").IsMatch(user.Email)) + if (!new Regex(@".+@.+\..+").IsMatch(request.Email)) { return new ConflictObjectResult(new { message = "Invalid email address" }); } - if (!PasswordSecurity(user.Password)) + if (!PasswordSecurity(request.Password)) { return new ConflictObjectResult(new { message = "Password is not up to the security standard" }); } - if (user.Devices == null) + var users = await _dbAccess.ReadAllUsers(); + + foreach (var item in users) { - user.Devices = new List(); + if (item.UserName == request.UserName) + { + return new ConflictObjectResult(new { message = "Username is already in use." }); + } + + if (item.Email == request.Email) + { + return new ConflictObjectResult(new { message = "Email is being used already" }); + } } string salt = Guid.NewGuid().ToString(); - string hashedPassword = ComputeHash(user.Password, SHA256.Create(), salt); - - user.Salt = salt; - user.Password = hashedPassword; + string hashedPassword = ComputeHash(request.Password, SHA256.Create(), salt); + User user = new User + { + UserName = request.UserName, + Email = request.Email, + Password = hashedPassword, + Salt = salt, + Devices = new List() + }; return await _dbAccess.CreateUser(user); } @@ -75,7 +92,7 @@ namespace Api.BusinessLogic /// Returns a jwt token, username and userid public async Task Login(Login login) { - User user = await _dbAccess.Login(login); + User user = await _dbAccess.ReadUserForLogin(login.EmailOrUsrn); if (user == null || user.Id == 0) { return new ConflictObjectResult(new { message = "Could not find user" }); } @@ -84,8 +101,8 @@ namespace Api.BusinessLogic if (user.Password == hashedPassword) { var token = GenerateJwtToken(user); - user.RefreshToken = Guid.NewGuid().ToString(); - _dbAccess.UpdatesRefreshToken(user.RefreshToken, user.Id); + user = await UpdateRefreshToken(user); + return new OkObjectResult(new { token, user.UserName, user.Id, refreshToken = user.RefreshToken }); } @@ -103,12 +120,42 @@ namespace Api.BusinessLogic /// returns the updated user in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason public async Task EditProfile(EditUserRequest userRequest, int userId) { - return await _dbAccess.UpdateUser(userRequest, userId); + var profile = await _dbAccess.ReadUser(userId); + var users = await _dbAccess.ReadAllUsers(); + + if (profile == null) { return new ConflictObjectResult(new { message = "User does not exist" }); } + + foreach (var item in users) + { + if (item.UserName == userRequest.UserName && userId != item.Id) + { + return new ConflictObjectResult(new { message = "Username is already in use." }); + } + + if (item.Email == userRequest.Email && userId != item.Id) + { + return new ConflictObjectResult(new { message = "Email is being used already" }); + } + } + + if (userRequest.Email == "" || userRequest.Email == null) + return new ConflictObjectResult(new { message = "Please enter an email" }); + + if (userRequest.UserName == "" || userRequest.UserName == null) + return new ConflictObjectResult(new { message = "Please enter a username" }); + + profile.Email = userRequest.Email; + profile.UserName = userRequest.UserName; + + + return await _dbAccess.UpdateUser(profile); } public async Task changePassword(ChangePasswordRequest passwordRequest, int userId) { var user = await _dbAccess.ReadUser(userId); + if (user == null) { return new ConflictObjectResult(new { message = "User does not exist" }); } + string hashedPassword = ComputeHash(passwordRequest.OldPassword, SHA256.Create(), user.Salt); @@ -124,8 +171,9 @@ namespace Api.BusinessLogic } string hashedNewPassword = ComputeHash(passwordRequest.NewPassword, SHA256.Create(), user.Salt); + user.Password = hashedNewPassword; - return await _dbAccess.updatePassword(hashedNewPassword, userId); + return await _dbAccess.updatePassword(user); } /// @@ -135,12 +183,19 @@ namespace Api.BusinessLogic /// returns the true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason public async Task DeleteUser(int userId) { - return await _dbAccess.DeleteUser(userId); + var user = await _dbAccess.ReadUserDetails(userId); + if (user != null) + { + return await _dbAccess.DeleteUser(user); + + } + return new ConflictObjectResult(new { message = "Invalid user" }); + } public async Task RefreshToken(string refreshToken) { - User user = await _dbAccess.ReadUser(refreshToken); + User user = await _dbAccess.ReadUserByRefreshToken(refreshToken); if (user == null) { return new ConflictObjectResult(new { message = "Could not match refreshtoken" }); } return new OkObjectResult(GenerateJwtToken(user)); } @@ -206,5 +261,13 @@ namespace Api.BusinessLogic return new JwtSecurityTokenHandler().WriteToken(token); } + + private async Task UpdateRefreshToken(User user) + { + user.RefreshToken = Guid.NewGuid().ToString(); + user.RefreshTokenExpiresAt = DateTime.Now.AddDays(7); + await _dbAccess.UpdateUser(user); + return user; + } } } diff --git a/backend/Api/Controllers/DeviceController.cs b/backend/Api/Controllers/DeviceController.cs index ac3693b..ffafd8e 100644 --- a/backend/Api/Controllers/DeviceController.cs +++ b/backend/Api/Controllers/DeviceController.cs @@ -75,10 +75,10 @@ namespace Api.Controllers [HttpDelete("Delete/{deviceId}")] public async Task DeleteDevice(int deviceId) { - var claims = HttpContext.User.Claims; - string userIdString = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value; - int userId = Convert.ToInt32(userIdString); - return await _deviceLogic.DeleteDevice(deviceId, userId); + //var claims = HttpContext.User.Claims; + //string userIdString = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value; + //int userId = Convert.ToInt32(userIdString); + return await _deviceLogic.DeleteDevice(deviceId); } } } diff --git a/backend/Api/Controllers/UserController.cs b/backend/Api/Controllers/UserController.cs index de1267f..e5a6a72 100644 --- a/backend/Api/Controllers/UserController.cs +++ b/backend/Api/Controllers/UserController.cs @@ -36,7 +36,7 @@ namespace Api.Controllers // Sends the user to userLogic [HttpPost("Create")] - public async Task CreateUser([FromBody] User user) + public async Task CreateUser([FromBody] CreateUserRequest user) { return await _userLogic.RegisterUser(user); } diff --git a/backend/Api/DBAccess/DBAccess.cs b/backend/Api/DBAccess/DBAccess.cs index ad33dfd..fd887ac 100644 --- a/backend/Api/DBAccess/DBAccess.cs +++ b/backend/Api/DBAccess/DBAccess.cs @@ -7,7 +7,7 @@ using Api.Models.Users; using Microsoft.AspNetCore.Http.HttpResults; using System.Collections.Generic; - +//All EF Core database calls namespace Api.DBAccess { public class DbAccess @@ -18,82 +18,71 @@ namespace Api.DBAccess { _context = context; } - - public async Task getUser(int userId) - { - return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); - } - /// - /// Creates a user using entityframework core + /// Gets one user on id /// - /// Need the entire user obj - /// returns true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task CreateUser(User user) - { - var users = await _context.Users.ToListAsync(); - - foreach (var item in users) - { - if (item.UserName == user.UserName) - { - return new ConflictObjectResult(new { message = "Username is already in use." }); - } - - if (item.Email == user.Email) - { - return new ConflictObjectResult(new { message = "Email is being used already" }); - } - } - - _context.Users.Add(user); - bool saved = await _context.SaveChangesAsync() == 1; - - if (saved) { return new OkObjectResult(true); } - - return new ConflictObjectResult(new { message = "Could not save to databse" }); - } - - /// - /// Returns a user that matches either the email or username - /// - /// Has a username or email and a password here the password is not used - /// (user) that matches the login - public async Task Login(Login login) - { - User user = new User(); - if (!login.EmailOrUsrn.Contains("@")) - { - user = await _context.Users.FirstOrDefaultAsync(u => u.UserName == login.EmailOrUsrn); - } - else - { - user = await _context.Users.FirstOrDefaultAsync(u => u.Email == login.EmailOrUsrn); - } - - if (user == null || user.Id == 0) { return new User(); } - return user; - } - - // Returns a user according to userID + /// used to get the specific user + /// returns a user object from the database based on the given id public async Task ReadUser(int userId) { return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); } + public async Task ReadUserDetails(int userId) + { + return await _context.Users + .Include(u => u.Devices) + .ThenInclude(u => u.Logs) + .FirstOrDefaultAsync(u => u.Id == userId); + } + // Returns a user according to refreshToken - public async Task ReadUser(string refreshToken) + public async Task ReadUserByRefreshToken(string refreshToken) { return await _context.Users.FirstOrDefaultAsync(u => u.RefreshToken == refreshToken); } - // Updates the refreshtoken saved in DB - public async void UpdatesRefreshToken(string refreshToken, int userId) + /// + /// Used to check both email and login for the login. + /// + /// stores the input of username or email + /// returns a user object from the database based on the given email or username + public async Task ReadUserForLogin(string emailOrUsername) { - var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); + if (emailOrUsername.Contains("@")) + { + return await _context.Users.FirstOrDefaultAsync(u => u.Email == emailOrUsername); + } + else + { + return await _context.Users.FirstOrDefaultAsync(u => u.UserName == emailOrUsername); + } + } + + /// + /// Gets all users + /// + /// Return a list of users + public async Task> ReadAllUsers() + { + return await _context.Users.ToListAsync(); + } + + /// + /// Creates a user + /// + /// Need the entire user obj + /// returns true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason + public async Task CreateUser(User user) + { + _context.Users.Add(user); + + bool saved = await _context.SaveChangesAsync() == 1; + + if (saved) { return new OkObjectResult(true); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); - user.RefreshToken = refreshToken; - user.RefreshTokenExpiresAt = DateTime.Now.AddDays(7); } /// @@ -102,55 +91,25 @@ namespace Api.DBAccess /// Contains the updated user info /// Has the id for the user that is to be updated /// returns the updated user in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task UpdateUser(EditUserRequest user, int userId) + public async Task UpdateUser(User user) { - var profile = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); - var users = await _context.Users.ToListAsync(); - - if (profile == null) { return new ConflictObjectResult(new { message = "User does not exist" }); } - - foreach (var item in users) - { - if (item.UserName == user.UserName && userId != item.Id) - { - return new ConflictObjectResult(new { message = "Username is already in use." }); - } - - if (item.Email == user.Email && userId != item.Id) - { - return new ConflictObjectResult(new { message = "Email is being used already" }); - } - } - - if(user.Email == "" || user.Email == null) - return new ConflictObjectResult(new { message = "Please enter an email" }); - - if (user.UserName == "" || user.UserName == null) - return new ConflictObjectResult(new { message = "Please enter a username" }); - - profile.Email = user.Email; - profile.UserName = user.UserName; - - + _context.Entry(user).State = EntityState.Modified; bool saved = await _context.SaveChangesAsync() == 1; - if (saved) { return new OkObjectResult(profile); } + if (saved) { return new OkObjectResult(user);} return new ConflictObjectResult(new { message = "Could not save to database" }); + } - public async Task updatePassword(string newPassword, int userId) + public async Task updatePassword(User user) { - var profile = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); - - if (profile == null) { return new ConflictObjectResult(new { message = "User does not exist" }); } - - profile.Password = newPassword; + _context.Entry(user).State = EntityState.Modified; bool saved = await _context.SaveChangesAsync() == 1; - if (saved) { return new OkObjectResult(profile); } + if (saved) { return new OkObjectResult(user); } return new ConflictObjectResult(new { message = "Could not save to database" }); } @@ -160,90 +119,50 @@ namespace Api.DBAccess /// /// The Id of the user that is to be deleted /// returns true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task DeleteUser(int userId) + public async Task DeleteUser(User user) { - var user = await _context.Users.Include(u => u.Devices).FirstOrDefaultAsync(u => u.Id == userId); - if (user != null) - { - if (user.Devices != null && user.Devices.Count > 0) - { - foreach (var item in user.Devices) - { - var device = await _context.Devices.Include(d => d.Logs).FirstOrDefaultAsync(d => d.Id == item.Id); - if (device != null) { _context.Devices.Remove(device); } - } - } - _context.Users.Remove(user); - bool saved = await _context.SaveChangesAsync() >= 0; - - if (saved) { return new OkObjectResult(saved); } - - return new ConflictObjectResult(new { message = "Could not save to database" }); - } - return new ConflictObjectResult(new { message = "Invalid user" }); - } - - // Returns devices according to userID - public async Task> ReadDevices(int userId) - { - var user = await _context.Users.Include(u => u.Devices).ThenInclude(u => u.Logs).FirstOrDefaultAsync(u => u.Id == userId); - - if (user == null || user.Devices == null) { return new List(); } - - List devices = new List(); - - foreach (var item in user.Devices) - { - var latestLog = item.Logs?.OrderByDescending(log => log.Date).FirstOrDefault(); // Get the latest log - GetDeviceDTO device = new GetDeviceDTO - { - Id = item.Id, - Name = item.Name, - TempHigh = item.TempHigh, - TempLow = item.TempLow, - ReferenceId = item.ReferenceId, - LatestLog = latestLog - }; - - devices.Add(device); - } - - return devices; - } - - /// - /// Creates a user using entityframework core - /// - /// The device that is going to be created - /// The user that owns the device - /// returns the true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task CreateDevice(Device device, int userId) - { - var user = await _context.Users.Include(u => u.Devices).FirstOrDefaultAsync(u => u.Id == userId); - - if (user == null || user.Devices == null) { return new ConflictObjectResult(new { message = "User did not have a device list" }); } - - user.Devices.Add(device); - - bool saved = await _context.SaveChangesAsync() == 1; + _context.Users.Remove(user); + bool saved = await _context.SaveChangesAsync() >= 0; if (saved) { return new OkObjectResult(saved); } return new ConflictObjectResult(new { message = "Could not save to database" }); } + // Returns all devices + public List ReadDevices() + { + return _context.Devices.ToList(); + } + // Returns a device according to deviceId public async Task ReadDevice(int deviceId) { return await _context.Devices.FirstOrDefaultAsync(d => d.Id == deviceId); } - // Returns a device according to refenreId + // Returns a device according to referenceId public Device ReadDevice(string referenceId) { return _context.Devices.FirstOrDefault(d => d.ReferenceId == referenceId); } + /// + /// Creates a user using entityframework core + /// + /// The device that is going to be created + /// The user that owns the device + /// returns the true in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason + public async Task CreateDevice(User user) + { + _context.Entry(user).State = EntityState.Modified; + + bool saved = await _context.SaveChangesAsync() == 2; + + if (saved) { return new OkObjectResult(user.Id); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); + } /// /// Updates a device in the database @@ -251,62 +170,25 @@ namespace Api.DBAccess /// Contains the updated device info /// Has the id for the device that is to be updated /// returns the updated device in a OkObjectResult and if there is some error it returns a ConflictObjectResult and a message that explain the reason - public async Task EditDevice(EditDeviceRequest request, int deviceId) + public async Task EditDevice(Device device) { - var device = await _context.Devices.FirstOrDefaultAsync(d => d.Id == deviceId); - if (device != null) - { - if (device.Name == "" || device.Name == null) - return new ConflictObjectResult(new { message = "Please enter a name" }); + _context.Entry(device).State = EntityState.Modified; + + bool saved = await _context.SaveChangesAsync() == 1; - device.Name = request.Name; - device.TempLow = request.TempLow; - device.TempHigh = request.TempHigh; + if (saved) { return new OkObjectResult(device); } - bool saved = await _context.SaveChangesAsync() >= 0; - - if (saved) { return new OkObjectResult(saved); } - - return new ConflictObjectResult(new { message = "Could not save to database" }); - } - return new ConflictObjectResult(new { message = "Invalid device. May already be deleted" }); + return new ConflictObjectResult(new { message = "Could not save to database" }); } - public async Task DeleteDevice(int deviceId, int userId) + public async Task DeleteDevice(Device device) { - var user = await _context.Users - .Include(u => u.Devices) // Ensure devices are loaded - .FirstOrDefaultAsync(u => u.Id == userId); + _context.Devices.Remove(device); + bool saved = await _context.SaveChangesAsync() >= 0; - if (user == null) - { - return new NotFoundObjectResult(new { message = "User not found" }); - } + if (saved) { return new OkObjectResult(saved); } - var device = user.Devices?.FirstOrDefault(d => d.Id == deviceId); - - if (device != null || user.Devices != null) - { - user.Devices.Remove(device); - bool userDeviceDeleted = await _context.SaveChangesAsync() > 0; - if (userDeviceDeleted) - { - _context.Devices.Remove(device); - bool saved = await _context.SaveChangesAsync() > 0; - - if (saved) return new OkObjectResult(new { message = "Device deleted successfully" }); - } - - return new ConflictObjectResult(new { message = "Could not save to database" }); - } - - return new NotFoundObjectResult(new { message = "Device not found or already deleted" }); - } - - // Returns all devices - public List ReadDevices() - { - return _context.Devices.ToList(); + return new ConflictObjectResult(new { message = "Could not save to database" }); } /// diff --git a/backend/Api/Migrations/20250403144251_removeNullableLists.Designer.cs b/backend/Api/Migrations/20250403144251_removeNullableLists.Designer.cs new file mode 100644 index 0000000..04ae996 --- /dev/null +++ b/backend/Api/Migrations/20250403144251_removeNullableLists.Designer.cs @@ -0,0 +1,138 @@ +// +using System; +using Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Api.Migrations +{ + [DbContext(typeof(DBContext))] + [Migration("20250403144251_removeNullableLists")] + partial class removeNullableLists + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.3"); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ReferenceId") + .HasColumnType("TEXT"); + + b.Property("TempHigh") + .HasColumnType("REAL"); + + b.Property("TempLow") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Api.Models.TemperatureLogs", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("DeviceId") + .HasColumnType("INTEGER"); + + b.Property("TempHigh") + .HasColumnType("REAL"); + + b.Property("TempLow") + .HasColumnType("REAL"); + + b.Property("Temperature") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.ToTable("TemperatureLogs"); + }); + + modelBuilder.Entity("Api.Models.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .HasColumnType("TEXT"); + + b.Property("RefreshTokenExpiresAt") + .HasColumnType("TEXT"); + + b.Property("Salt") + .HasColumnType("TEXT"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.HasOne("Api.Models.Users.User", null) + .WithMany("Devices") + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Api.Models.TemperatureLogs", b => + { + b.HasOne("Api.Models.Devices.Device", null) + .WithMany("Logs") + .HasForeignKey("DeviceId"); + }); + + modelBuilder.Entity("Api.Models.Devices.Device", b => + { + b.Navigation("Logs"); + }); + + modelBuilder.Entity("Api.Models.Users.User", b => + { + b.Navigation("Devices"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/Api/Migrations/20250403144251_removeNullableLists.cs b/backend/Api/Migrations/20250403144251_removeNullableLists.cs new file mode 100644 index 0000000..c7aa064 --- /dev/null +++ b/backend/Api/Migrations/20250403144251_removeNullableLists.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class removeNullableLists : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/backend/Api/Models/Devices/Device.cs b/backend/Api/Models/Devices/Device.cs index ee95a16..c41db5f 100644 --- a/backend/Api/Models/Devices/Device.cs +++ b/backend/Api/Models/Devices/Device.cs @@ -12,6 +12,6 @@ public string? ReferenceId { get; set; } - public List? Logs { get; set; } + public List Logs { get; set; } } } diff --git a/backend/Api/Models/Users/CreateUserRequest.cs b/backend/Api/Models/Users/CreateUserRequest.cs new file mode 100644 index 0000000..def72d7 --- /dev/null +++ b/backend/Api/Models/Users/CreateUserRequest.cs @@ -0,0 +1,11 @@ +namespace Api.Models.Users +{ + public class CreateUserRequest + { + public string UserName { get; set; } + + public string Password { get; set; } + + public string Email { get; set; } + } +} diff --git a/backend/Api/Models/Users/User.cs b/backend/Api/Models/Users/User.cs index e9729fa..05c6a75 100644 --- a/backend/Api/Models/Users/User.cs +++ b/backend/Api/Models/Users/User.cs @@ -18,6 +18,6 @@ namespace Api.Models.Users public DateTime RefreshTokenExpiresAt { get; set; } - public List? Devices { get; set; } + public List Devices { get; set; } } } diff --git a/frontend/profile/index.html b/frontend/profile/index.html index 98ff11b..9c740e4 100644 --- a/frontend/profile/index.html +++ b/frontend/profile/index.html @@ -38,10 +38,10 @@
- + - + diff --git a/frontend/scripts/devices.js b/frontend/scripts/devices.js index b76d1e3..401c711 100644 --- a/frontend/scripts/devices.js +++ b/frontend/scripts/devices.js @@ -3,9 +3,7 @@ import { devices } from "../mockdata/devices.mockdata.js"; import { logout } from "../shared/utils.js"; getDevices().then(res => { - if(!res.message){ - buildTable(res) - } + buildTable(res) }) let selectedId = null; // Store the selected referenceId @@ -33,11 +31,6 @@ function buildTable(data) { table.appendChild(row); }); - - document.getElementById("addDevice").onclick = () => { - document.getElementById("addModal").style.display = "block"; - } - // Attach click event to all trash buttons document.querySelectorAll(".trashBtn").forEach((btn) => { btn.onclick = function () { @@ -60,6 +53,11 @@ function buildTable(data) { }); } +document.getElementById("addDevice").onclick = () => { + document.getElementById("referenceId").value = ""; + document.getElementById("addModal").style.display = "block"; +} + document.querySelectorAll(".cancelbtn").forEach(button => { button.onclick = () => { @@ -72,15 +70,27 @@ document.querySelectorAll(".cancelbtn").forEach(button => { // Delete button logic document.getElementById("deletebtn").onclick = () => { if (selectedId) { - deleteDevice(selectedId); // Call delete function with referenceId - window.location.reload(); + deleteDevice(selectedId).then((response) => { + if (response?.error) { + document.getElementById("form-error").innerText = response.error; + document.getElementById("form-error").style.display = "block"; + return; + } + window.location.reload(); + }); } }; document.getElementById("addbtn").onclick = () => { const referenceId = document.getElementById("referenceId").value; - add(referenceId); // Call delete function with referenceId - window.location.reload(); + add(referenceId).then((response) => { + if (response?.error) { + document.getElementById("form-error").innerText = response.error; + document.getElementById("form-error").style.display = "block"; + return; + } + window.location.reload(); + }); }; document.getElementById("editbtn").onclick = () => { @@ -96,7 +106,7 @@ document.getElementById("editbtn").onclick = () => { document.getElementById("form-error").style.display = "block"; return; } - location.href = "/devices"; + window.location.reload(); }); } };