From f42dcd743a3461bba903255ffebf254c42b6891e Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Tue, 25 Mar 2025 14:24:36 +0100 Subject: [PATCH] profile gets data from db, changes to edituser --- backend/Api/BusinessLogic/UserLogic.cs | 41 ++++++++++++----- backend/Api/Controllers/UserController.cs | 34 ++++++++------ backend/Api/DBAccess/DBAccess.cs | 28 ++++++++++-- backend/Api/DBAccess/DBContext.cs | 1 + .../Api/Models/User/ChangePasswordRequest.cs | 8 ++++ backend/Api/Models/User/EditUserRequest.cs | 8 ++++ backend/Api/Models/{ => User}/User.cs | 2 +- frontend/home/index.html | 1 + frontend/index.html | 2 + frontend/login/index.html | 2 +- frontend/profile/index.html | 10 ++++- frontend/scripts/login.js | 14 +++++- frontend/scripts/profile.js | 45 ++++++++++++------- frontend/scripts/services/users.service.js | 24 +++++++--- frontend/shared/constants.js | 2 +- frontend/styles/auth.css | 30 +++++++++++-- frontend/styles/frontpage.css | 1 - frontend/styles/home.css | 25 ----------- frontend/styles/profile.css | 17 ++++++- 19 files changed, 209 insertions(+), 86 deletions(-) create mode 100644 backend/Api/Models/User/ChangePasswordRequest.cs create mode 100644 backend/Api/Models/User/EditUserRequest.cs rename backend/Api/Models/{ => User}/User.cs (91%) diff --git a/backend/Api/BusinessLogic/UserLogic.cs b/backend/Api/BusinessLogic/UserLogic.cs index 43d21f6..77b1800 100644 --- a/backend/Api/BusinessLogic/UserLogic.cs +++ b/backend/Api/BusinessLogic/UserLogic.cs @@ -1,5 +1,6 @@ using Api.DBAccess; using Api.Models; +using Api.Models.User; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; @@ -22,6 +23,14 @@ namespace Api.BusinessLogic _configuration = configuration; } + public async Task getUser(int userId) + { + User user = await _dbAccess.getUser(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 }); + } + public async Task RegisterUser(User user) { if (!new Regex(@".+@.+\..+").IsMatch(user.Email)) @@ -47,7 +56,6 @@ namespace Api.BusinessLogic return await _dbAccess.CreateUser(user); } - public async Task Login(Login login) { User user = await _dbAccess.Login(login); @@ -59,30 +67,43 @@ namespace Api.BusinessLogic if (user.Password == hashedPassword) { var token = GenerateJwtToken(user); - return new OkObjectResult(new { token, user.UserName, user.Id }); + return new OkObjectResult(new { token, user.Id}); } return new ConflictObjectResult(new { message = "Invalid password" }); } - public async Task EditProfile(User user, int userId) + public async Task EditProfile(EditUserRequest userRequest, int userId) { - if (!new Regex(@".+@.+\..+").IsMatch(user.Email)) + if (!new Regex(@".+@.+\..+").IsMatch(userRequest.Email)) { return new ConflictObjectResult(new { message = "Invalid email address" }); } - if (!PasswordSecurity(user.Password)) + + return await _dbAccess.UpdateUser(userRequest, userId); + } + + public async Task changePassword(ChangePasswordRequest passwordRequest, int userId) + { + var user = await _dbAccess.ReadUser(userId); + + string hashedPassword = ComputeHash(passwordRequest.OldPassword, SHA256.Create(), user.Salt); + + if (user.Password != hashedPassword) { - return new ConflictObjectResult(new { message = "Password is not up to the security standard" }); + return new ConflictObjectResult(new { message = "Old password is incorrect" }); + } - var profile = await _dbAccess.ReadUser(userId); + if (!PasswordSecurity(passwordRequest.NewPassword)) + { + return new ConflictObjectResult(new { message = "New password is not up to the security standard" }); + } - string hashedPassword = ComputeHash(user.Password, SHA256.Create(), profile.Salt); - user.Password = hashedPassword; + string hashedNewPassword = ComputeHash(passwordRequest.NewPassword, SHA256.Create(), user.Salt); - return await _dbAccess.UpdateUser(user, userId); + return await _dbAccess.updatePassword(hashedNewPassword, userId); } public async Task DeleteUser(int userId) diff --git a/backend/Api/Controllers/UserController.cs b/backend/Api/Controllers/UserController.cs index 186e1d4..567a416 100644 --- a/backend/Api/Controllers/UserController.cs +++ b/backend/Api/Controllers/UserController.cs @@ -1,12 +1,8 @@ using Microsoft.AspNetCore.Mvc; using Api.Models; -using Api.DBAccess; -using Microsoft.IdentityModel.Tokens; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Text; using Microsoft.AspNetCore.Authorization; using Api.BusinessLogic; +using Api.Models.User; namespace Api.Controllers { @@ -21,31 +17,43 @@ namespace Api.Controllers _userLogic = userLogic; } - [HttpPost("Login")] + //[Authorize] + [HttpGet("{userId}")] + public async Task GetUSer(int userId) + { + return await _userLogic.getUser(userId); + } + [HttpPost("login")] public async Task Login([FromBody] Login login) { return await _userLogic.Login(login); } - [HttpPost("Create")] + [HttpPost("create")] public async Task CreateUser([FromBody] User user) { return await _userLogic.RegisterUser(user); } - [Authorize] - [HttpPut("Edit/{userId}")] - public async Task EditUser([FromBody] User user, int userId) + //[Authorize] + [HttpPut("edit/{userId}")] + public async Task EditUser([FromBody] EditUserRequest userRequest, int userId) { - return await _userLogic.EditProfile(user, userId); + return await _userLogic.EditProfile(userRequest, userId); + } + + //[Authorize] + [HttpPut("change-password/{userId}")] + public async Task changePassword([FromBody] ChangePasswordRequest passwordRequest, int userId) + { + return await _userLogic.changePassword(passwordRequest, userId); } [Authorize] - [HttpDelete("Delete/{userId}")] + [HttpDelete("delete/{userId}")] public async Task DeleteUser(int userId) { return await _userLogic.DeleteUser(userId); } - } } diff --git a/backend/Api/DBAccess/DBAccess.cs b/backend/Api/DBAccess/DBAccess.cs index ad83328..e550f11 100644 --- a/backend/Api/DBAccess/DBAccess.cs +++ b/backend/Api/DBAccess/DBAccess.cs @@ -5,6 +5,7 @@ using System.Runtime.Intrinsics.Arm; using System.Security.Cryptography; using Microsoft.AspNetCore.Mvc; using static System.Runtime.InteropServices.JavaScript.JSType; +using Api.Models.User; namespace Api.DBAccess @@ -18,6 +19,12 @@ namespace Api.DBAccess _context = context; } + public async Task getUser(int userId) + { + return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); + } + + public async Task CreateUser(User user) { var users = await _context.Users.ToListAsync(); @@ -64,7 +71,7 @@ namespace Api.DBAccess return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); } - public async Task UpdateUser(User user, int userId) + public async Task UpdateUser(EditUserRequest user, int userId) { var profile = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); var users = await _context.Users.ToListAsync(); @@ -73,12 +80,12 @@ namespace Api.DBAccess foreach (var item in users) { - if (item.UserName == user.UserName) + if (item.UserName == user.UserName && userId != item.Id) { return new ConflictObjectResult(new { message = "Username is already in use." }); } - if (item.Email == user.Email) + if (item.Email == user.Email && userId != item.Id) { return new ConflictObjectResult(new { message = "Email is being used already" }); } @@ -88,7 +95,20 @@ namespace Api.DBAccess profile.Email = user.Email; - profile.Password = user.Password; + bool saved = await _context.SaveChangesAsync() == 1; + + if (saved) { return new OkObjectResult(profile); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); + } + + public async Task updatePassword(string newPassword, int userId) + { + 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; bool saved = await _context.SaveChangesAsync() == 1; diff --git a/backend/Api/DBAccess/DBContext.cs b/backend/Api/DBAccess/DBContext.cs index 5c23603..ae2427a 100644 --- a/backend/Api/DBAccess/DBContext.cs +++ b/backend/Api/DBAccess/DBContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Api.Models; +using Api.Models.User; namespace Api { diff --git a/backend/Api/Models/User/ChangePasswordRequest.cs b/backend/Api/Models/User/ChangePasswordRequest.cs new file mode 100644 index 0000000..6dff72d --- /dev/null +++ b/backend/Api/Models/User/ChangePasswordRequest.cs @@ -0,0 +1,8 @@ +namespace Api.Models.User +{ + public class ChangePasswordRequest + { + public string OldPassword { get; set; } + public string NewPassword { get; set; } + } +} diff --git a/backend/Api/Models/User/EditUserRequest.cs b/backend/Api/Models/User/EditUserRequest.cs new file mode 100644 index 0000000..6b3f6f8 --- /dev/null +++ b/backend/Api/Models/User/EditUserRequest.cs @@ -0,0 +1,8 @@ +namespace Api.Models.User +{ + public class EditUserRequest + { + public string UserName { get; set; } + public string Email { get; set; } + } +} diff --git a/backend/Api/Models/User.cs b/backend/Api/Models/User/User.cs similarity index 91% rename from backend/Api/Models/User.cs rename to backend/Api/Models/User/User.cs index 4583fab..37bbd8f 100644 --- a/backend/Api/Models/User.cs +++ b/backend/Api/Models/User/User.cs @@ -1,4 +1,4 @@ -namespace Api.Models +namespace Api.Models.User { public class User { diff --git a/frontend/home/index.html b/frontend/home/index.html index 403e197..fec875b 100644 --- a/frontend/home/index.html +++ b/frontend/home/index.html @@ -5,6 +5,7 @@ Temperature-Alarm-Web + diff --git a/frontend/index.html b/frontend/index.html index c30d98b..26a5fe8 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,6 +4,8 @@ Temperature Alarm + +
diff --git a/frontend/login/index.html b/frontend/login/index.html index 4b22dea..171130f 100644 --- a/frontend/login/index.html +++ b/frontend/login/index.html @@ -21,7 +21,7 @@
Dont have an account? Register diff --git a/frontend/profile/index.html b/frontend/profile/index.html index 3592996..a5752d3 100644 --- a/frontend/profile/index.html +++ b/frontend/profile/index.html @@ -10,6 +10,13 @@
+
+ Home + +
@@ -32,7 +39,6 @@ -
@@ -55,7 +61,7 @@ -
+
diff --git a/frontend/scripts/login.js b/frontend/scripts/login.js index e264a10..2348cd0 100644 --- a/frontend/scripts/login.js +++ b/frontend/scripts/login.js @@ -13,9 +13,21 @@ document.getElementById("loginForm").addEventListener("submit", function(event) if (response.error) { document.getElementById("form-error").innerText = response.error; document.getElementById("form-error").style.display = "block"; - return; } + else{ + if (typeof(Storage) !== "undefined") { + if(document.getElementById("rememberId").checked == true){ + localStorage.setItem("id", response.id); + localStorage.setItem("rememberLogin", true); + } + else{ + localStorage.setItem("rememberLogin", false); + sessionStorage.setItem("id", response.id); + } + + } + } location.href = "/home"; }); diff --git a/frontend/scripts/profile.js b/frontend/scripts/profile.js index ccca75d..3e28c13 100644 --- a/frontend/scripts/profile.js +++ b/frontend/scripts/profile.js @@ -1,15 +1,30 @@ import { profileData } from "../mockdata/profile.mockdata.js"; +import { get } from "./services/users.service.js"; +import { update } from "./services/users.service.js"; +import { updatePassword } from "./services/users.service.js"; -var table = document.getElementById(`profileCard`); +let idlocation = localStorage.getItem("rememberLogin") +let id; +if(idlocation){ + id = localStorage.getItem("id"); +} +else{ + id = localStorage.getItem("id"); +} +get(id).then(res => { + var table = document.getElementById(`profileCard`); table.innerHTML += `
-

${profileData.username}

-

${profileData.email}

+

${res.userName}

+

${res.email}

`; +}) + + var pswModal = document.getElementById("PasswordModal"); var editModal = document.getElementById("editModal"); @@ -33,20 +48,22 @@ window.onclick = (event) => { if (event.target == pswModal || event.target == editModal) { pswModal.style.display = "none"; editModal.style.display = "none"; + document.getElementById("form-error").innerText = ""; + document.getElementById("form-error").style.display = "none"; } }; document.getElementById("editForm").addEventListener("submit", function(event) { event.preventDefault(); // Prevents default form submission - document.getElementById("form-error-edit").style.display = "none"; + document.getElementById("form-error").style.display = "none"; // Get form values const email = document.getElementById("email").value; const username = document.getElementById("uname").value; // Call function with form values - update(email, username) + update(email, username, id) .then(response => { if (response?.error) { document.getElementById("form-error").innerText = response.error; @@ -55,37 +72,33 @@ document.getElementById("editForm").addEventListener("submit", function(event) { return; } - location.href = "/login"; + location.href = "/profile"; }); }); document.getElementById("PasswordForm").addEventListener("submit", function(event) { event.preventDefault(); // Prevents default form submission - document.getElementById("form-error-password").style.display = "none"; + document.getElementById("form-error").style.display = "none"; - // Get form values const oldPassword = document.getElementById("oldpsw").value; const newPassword = document.getElementById("psw").value; const repeatPassword = document.getElementById("rpsw").value; if (newPassword !== repeatPassword) { - let errorDiv = document.getElementById("form-error-password"); + let errorDiv = document.getElementById("form-error"); errorDiv.style.display = "block"; errorDiv.innerText = "Passwords do not match!"; return; } - // Call function with form values - update(email, username) + updatePassword(oldPassword, newPassword, id) .then(response => { - if (response?.error) { - document.getElementById("form-error").innerText = response.error; + //error messages do not work + if (response.error) { + document.getElementById("form-error").innerText = response.message; document.getElementById("form-error").style.display = "block"; - return; } - - location.href = "/login"; }); }); diff --git a/frontend/scripts/services/users.service.js b/frontend/scripts/services/users.service.js index 4b5fa02..234f275 100644 --- a/frontend/scripts/services/users.service.js +++ b/frontend/scripts/services/users.service.js @@ -1,6 +1,18 @@ import { address } from "../../shared/constants.js"; import { handleResponse } from "../../shared/utils.js"; + +export function get(userId) { + return fetch(`${address}/user/${userId}`, { + method: "GET", + headers: { + "Content-Type": "application/json" + }, + }) + .then(handleResponse) + .catch(err => { error: err.message }); +} + export function login(usernameOrEmail, password) { return fetch(`${address}/user/login`, { method: "POST", @@ -28,9 +40,9 @@ export function create(email, username, password, repeatPassword){ .catch(err => { error: err.message }); } -export function update(email, username){ - return fetch(`${address}/user/update`, { - method: "PATCH", +export function update(email, username, userId){ + return fetch(`${address}/user/edit/${userId}`, { + method: "PUT", headers: { "Content-Type": "application/json" }, @@ -40,9 +52,9 @@ export function update(email, username){ .catch(err => { error: err.message }); } -export function updatePassword(oldPassword, newPassword){ - return fetch(`${address}/user/update-password`, { - method: "PATCH", +export function updatePassword(oldPassword, newPassword, userId){ + return fetch(`${address}/user/change-password/${userId}`, { + method: "PUT", headers: { "Content-Type": "application/json" }, diff --git a/frontend/shared/constants.js b/frontend/shared/constants.js index a21da0c..6027ef9 100644 --- a/frontend/shared/constants.js +++ b/frontend/shared/constants.js @@ -1 +1 @@ -export const address = "hhttps://temperature.mercantec.tech/api" +export const address = "http://127.0.0.1:5000/api" diff --git a/frontend/styles/auth.css b/frontend/styles/auth.css index bb7a66a..47b65ea 100644 --- a/frontend/styles/auth.css +++ b/frontend/styles/auth.css @@ -1,7 +1,32 @@ body { font-family: Arial, Helvetica, sans-serif; + margin: 0; } +.topnav { + overflow: hidden; + background-color: #333; + } + + .topnav a { + float: left; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; + } + + .topnav a:hover { + background-color: #ddd; + color: black; + } + + .topnav a.active { + background-color: #04aa6d; + color: white; + } + /* Full-width input fields */ input[type=text], input[type=password], input[type=email] { width: 100%; @@ -15,12 +40,12 @@ input[type=text], input[type=password], input[type=email] { /* Set a style for all buttons */ button { background-color: #04AA6D; - color: white; padding: 14px 20px; margin: 8px 0; border: none; cursor: pointer; width: 100%; + border-radius: 20px; } button:hover { @@ -49,6 +74,3 @@ button:hover { margin-top: 1rem; } -button{ - border-radius: 20px; -} diff --git a/frontend/styles/frontpage.css b/frontend/styles/frontpage.css index f8cbe7a..f15df4b 100644 --- a/frontend/styles/frontpage.css +++ b/frontend/styles/frontpage.css @@ -4,7 +4,6 @@ } body { - margin: 0; font-family: sans-serif; } diff --git a/frontend/styles/home.css b/frontend/styles/home.css index 9eb7fac..2cb0679 100644 --- a/frontend/styles/home.css +++ b/frontend/styles/home.css @@ -1,5 +1,4 @@ body { - margin: 0; font-family: Arial, Helvetica, sans-serif; } @@ -8,30 +7,6 @@ body { opacity: 100%; } -.topnav { - overflow: hidden; - background-color: #333; -} - -.topnav a { - float: left; - color: #f2f2f2; - text-align: center; - padding: 14px 16px; - text-decoration: none; - font-size: 17px; -} - -.topnav a:hover { - background-color: #ddd; - color: black; -} - -.topnav a.active { - background-color: #04aa6d; - color: white; -} - table { font-family: arial, sans-serif; border-collapse: collapse; diff --git a/frontend/styles/profile.css b/frontend/styles/profile.css index 3d2c752..87f727d 100644 --- a/frontend/styles/profile.css +++ b/frontend/styles/profile.css @@ -49,8 +49,23 @@ h2{ padding: 20px; border: 1px solid #888; width: 80%; + -webkit-animation-name: animatetop; + -webkit-animation-duration: 0.4s; + animation-name: animatetop; + animation-duration: 0.4s } - + + /* Add Animation */ + @-webkit-keyframes animatetop { + from {top:-300px; opacity:0} + to {top:0; opacity:1} + } + + @keyframes animatetop { + from {top:-300px; opacity:0} + to {top:0; opacity:1} + } + /* The Close Button */ .close { color: #aaaaaa;