Merge branch 'master' of git.reim.ar:ReiMerc/temperature-alarm

This commit is contained in:
Jeas0001 2025-04-14 10:06:51 +02:00
commit 58ee243422
12 changed files with 126 additions and 134 deletions

View File

@ -1,9 +1,7 @@
using Api.DBAccess; using Api.DBAccess;
using Api.Models; using Api.Models;
using Api.Models.Devices; using Api.Models.Devices;
using Api.Models.Users;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Api.AMQP; using Api.AMQP;
namespace Api.BusinessLogic namespace Api.BusinessLogic
@ -29,7 +27,7 @@ namespace Api.BusinessLogic
{ {
var userDetails = await _dbAccess.ReadUserDetails(userId); var userDetails = await _dbAccess.ReadUserDetails(userId);
if (userDetails.Devices.Count == 0) { return new OkObjectResult(new { message = "Could not find any devices connected to the user" }); } if (userDetails.Devices.Count == 0) { return new ConflictObjectResult(new { message = "Could not find any devices connected to the user" }); }
List<GetDeviceDTO> devices = new List<GetDeviceDTO>(); List<GetDeviceDTO> devices = new List<GetDeviceDTO>();

View File

@ -258,7 +258,7 @@ namespace Api.BusinessLogic
_configuration["JwtSettings:Issuer"], _configuration["JwtSettings:Issuer"],
_configuration["JwtSettings:Audience"], _configuration["JwtSettings:Audience"],
claims, claims,
expires: DateTime.Now.AddHours(2), expires: DateTime.Now.AddHours(1),
signingCredentials: creds); signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token); return new JwtSecurityTokenHandler().WriteToken(token);

View File

@ -18,7 +18,7 @@ namespace Api.Controllers
_userLogic = userLogic; _userLogic = userLogic;
} }
//[Authorize] [Authorize]
[HttpGet("get")] [HttpGet("get")]
public async Task<IActionResult> ReadUser() public async Task<IActionResult> ReadUser()
{ {

View File

@ -6,7 +6,8 @@
<title>Temperature-Alarm-Web</title> <title>Temperature-Alarm-Web</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/luxon"></script> <script defer src="https://cdn.jsdelivr.net/npm/luxon"></script>
<link rel="stylesheet" href="/styles/auth.css"> <link rel="stylesheet" href="/styles/common.css">
<link rel="stylesheet" href="/styles/auth.css">
<link rel="stylesheet" href="/styles/devices.css" /> <link rel="stylesheet" href="/styles/devices.css" />
<script defer type="module" src="/scripts/devices.js"></script> <script defer type="module" src="/scripts/devices.js"></script>
</head> </head>
@ -26,19 +27,24 @@
<div class="addDeviceContainer"> <div class="addDeviceContainer">
<button id="addDevice">Add Device</button> <button id="addDevice">Add Device</button>
</div> </div>
<div class="tableConatiner"> <div style="display: flex; justify-content: center;">
<table> <div class="tableConatiner">
<tr> <table>
<th>Id</th> <thead>
<th>Placement(name)</th> <tr>
<th>Set Temp High</th> <th>Id</th>
<th>Set Temp Low</th> <th>Placement(name)</th>
<th>Latest Meassurement</th> <th>Set Temp High</th>
<th></th> <th>Set Temp Low</th>
</tr> <th>Latest Meassurement</th>
<tbody id="deviceTable"></tbody> <th></th>
</table> </tr>
</thead>
<tbody id="deviceTable"></tbody>
</table>
</div>
</div> </div>
<div id="get-error" class="error"></div>
</div> </div>
@ -52,6 +58,7 @@
<button type="button" class="cancelbtn">Cancel</button> <button type="button" class="cancelbtn">Cancel</button>
<button type="button" id="deletebtn">Delete</button> <button type="button" id="deletebtn">Delete</button>
</div> </div>
<div id="delete-error" class="error"></div>
</div> </div>
</form> </form>
</div> </div>
@ -76,8 +83,8 @@
<button type="button" id="editbtn">Save Changes</button> <button type="button" id="editbtn">Save Changes</button>
</div> </div>
<div id="form-error"></div> <div id="edit-error" class="error"></div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
@ -98,8 +105,8 @@
<button type="button" id="addbtn">Add</button> <button type="button" id="addbtn">Add</button>
</div> </div>
<div id="form-error"></div> <div id="add-error" class="error"></div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -26,7 +26,7 @@
</span> </span>
</div> </div>
<div id="form-error" class="error"></div> <div id="login-error" class="error"></div>
</div> </div>
</form> </form>
</body> </body>

View File

@ -45,7 +45,7 @@
<input type="text" placeholder="Enter username" id="uname" required> <input type="text" placeholder="Enter username" id="uname" required>
<button id="submitEditBtn" type="submit">Save Changes</button> <button id="submitEditBtn" type="submit">Save Changes</button>
<div id="editprofile-error" class="error"></div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,10 +1,11 @@
import { add, getDevices, update, deleteDevice } from "./services/devices.service.js"; import { add, getDevices, update, deleteDevice } from "./services/devices.service.js";
import { devices } from "../mockdata/devices.mockdata.js";
import { logout } from "../shared/utils.js"; import { logout } from "../shared/utils.js";
getDevices().then(res => { getDevices().then((res) => buildTable(res))
buildTable(res) .catch(error => {
}) document.getElementById("get-error").innerText = error;
document.getElementById("get-error").style.display = "block";
});
let selectedId = null; // Store the selected referenceId let selectedId = null; // Store the selected referenceId
@ -23,26 +24,32 @@ function buildTable(data) {
table.innerHTML = ""; // Clear existing rows before adding new ones table.innerHTML = ""; // Clear existing rows before adding new ones
data.forEach((device) => { data.forEach((device) => {
var row = document.createElement("tr"); const latestLog = device.latestLog;
row.innerHTML = ` const temperatureText = latestLog
<td>${device.referenceId}</td> ? `Temperature: ${latestLog.temperature}°C, Date: ${luxon.DateTime.fromISO(latestLog.date, { zone: "UTC" }).setZone("Europe/Copenhagen").toFormat("DD T")}`
<td>${device.name}</td> : "No logs yet";
<td>${device.tempHigh}</td>
<td>${device.tempLow}</td> const row = document.createElement("tr");
<td>Temperature: ${device.latestLog.temperature}°C, Date: ${luxon.DateTime.fromISO(device.latestLog.date, { zone: "UTC" }).setZone("Europe/Copenhagen").toFormat("DD T")}</td> row.innerHTML = `
<td style="width: 90px;"> <td>${device.referenceId}</td>
<img class="editIconbtn tableIcons" src="/img/Edit.png" data-id="${device.id}" data-referenceId="${device.referenceId}" data-name="${device.name}" data-tempHigh="${device.tempHigh}" data-tempLow="${device.tempLow}"> <td>${device.name}</td>
<img class="trashBtn tableIcons" src="/img/Trash.png" data-id="${device.id}" data-referenceId="${device.referenceId}"> <td>${device.tempHigh}</td>
</td> <td>${device.tempLow}</td>
`; <td>${temperatureText}</td>
table.appendChild(row); <td style="width: 90px;">
}); <img class="editIconbtn tableIcons" src="/img/Edit.png" data-id="${device.id}" data-referenceId="${device.referenceId}" data-name="${device.name}" data-tempHigh="${device.tempHigh}" data-tempLow="${device.tempLow}">
<img class="trashBtn tableIcons" src="/img/Trash.png" data-id="${device.id}" data-referenceId="${device.referenceId}">
</td>
`;
table.appendChild(row);
});
// Attach click event to all trash buttons // Attach click event to all trash buttons
document.querySelectorAll(".trashBtn").forEach((btn) => { document.querySelectorAll(".trashBtn").forEach((btn) => {
btn.onclick = function () { btn.onclick = function () {
selectedId = this.getAttribute("data-id"); // Store referenceId selectedId = this.getAttribute("data-id"); // Store referenceId
// document.getElementById("deleteDeviceHeader").innerHTML = `Delete Device ${this.getAttribute("data-referenceId")}`; document.getElementById("deleteDeviceHeader").innerHTML = `Delete Device ${this.getAttribute("data-referenceId")}`;
document.getElementById("deleteModal").style.display = "block"; document.getElementById("deleteModal").style.display = "block";
}; };
}); });
@ -81,6 +88,13 @@ document.querySelectorAll(".cancelbtn").forEach(button => {
document.getElementById("editModal").style.display = "none"; document.getElementById("editModal").style.display = "none";
document.getElementById("addModal").style.display = "none"; document.getElementById("addModal").style.display = "none";
document.getElementById("add-error").style.display = "none";
document.getElementById("add-error").innerText = "";
document.getElementById("delete-error").style.display = "none";
document.getElementById("delete-error").innerText = "";
document.getElementById("edit-error").style.display = "none";
document.getElementById("edit-error").innerText = "";
}; };
}); });
@ -99,26 +113,20 @@ tempLowInput.addEventListener("input", checkForChanges);
// Delete button logic // Delete button logic
document.getElementById("deletebtn").onclick = () => { document.getElementById("deletebtn").onclick = () => {
if (selectedId) { if (selectedId) {
deleteDevice(selectedId).then((response) => { deleteDevice(selectedId).then(() => location.reload())
if (response?.error) { .catch(error => {
document.getElementById("form-error").innerText = response.error; document.getElementById("delete-error").innerText = error;
document.getElementById("form-error").style.display = "block"; document.getElementById("delete-error").style.display = "block";
return;
}
window.location.reload();
}); });
} }
}; };
document.getElementById("addbtn").onclick = () => { document.getElementById("addbtn").onclick = () => {
const referenceId = document.getElementById("referenceId").value; const referenceId = document.getElementById("referenceId").value;
add(referenceId).then((response) => { add(referenceId).then(() => location.reload())
if (response?.error) { .catch(error => {
document.getElementById("form-error").innerText = response.error; document.getElementById("add-error").innerText = error;
document.getElementById("form-error").style.display = "block"; document.getElementById("add-error").style.display = "block";
return;
}
window.location.reload();
}); });
}; };
@ -129,14 +137,11 @@ document.getElementById("editbtn").onclick = () => {
const tempLow = document.getElementById("tempLow").value; const tempLow = document.getElementById("tempLow").value;
update(selectedId, name, tempHigh, tempLow).then((response) => { update(selectedId, name, tempHigh, tempLow).then(() => location.reload())
if (response?.error) { .catch(error => {
document.getElementById("form-error").innerText = response.error; document.getElementById("edit-error").innerText = error;
document.getElementById("form-error").style.display = "block"; document.getElementById("edit-error").style.display = "block";
return; });
}
window.location.reload();
});
} }
}; };

View File

@ -3,26 +3,23 @@ import { login } from "./services/users.service.js";
document.getElementById("loginForm").addEventListener("submit", function(event) { document.getElementById("loginForm").addEventListener("submit", function(event) {
event.preventDefault(); event.preventDefault();
document.getElementById("form-error").style.display = "none";
const emailOrUsername = document.getElementById("emailorusn").value; const emailOrUsername = document.getElementById("emailorusn").value;
const password = document.getElementById("psw").value; const password = document.getElementById("psw").value;
login(emailOrUsername, password) login(emailOrUsername, password).then((response) => {
.then(response => { if(response.token && response.refreshToken){
if(response.token && response.refreshToken){ document.cookie = `auth-token=${response.token}; Path=/`;
document.cookie = `auth-token=${response.token}; Path=/`; document.cookie = `refresh-token=${response.refreshToken}; Path=/`;
document.cookie = `refresh-token=${response.refreshToken}; Path=/`; localStorage.setItem("user", JSON.stringify({
localStorage.setItem("user", JSON.stringify({ id: response.id,
id: response.id, username: response.userName,
username: response.userName, }));
})); location.href = "/home";
location.href = "/home"; }
} })
}) .catch(error => {
.catch(error => { document.getElementById("login-error").innerText = error;
document.getElementById("form-error").innerText = error; document.getElementById("login-error").style.display = "block";
document.getElementById("form-error").style.display = "block"; });
});
}); });

View File

@ -75,18 +75,13 @@ document
.addEventListener("submit", function (event) { .addEventListener("submit", function (event) {
event.preventDefault(); // Prevents default form submission event.preventDefault(); // Prevents default form submission
document.getElementById("form-error").style.display = "none"; document.getElementById("editprofile-error").style.display = "none";
// Call function with form values // Call function with form values
update(emailInput.value, usernameInput.value).then((response) => { update(emailInput.value, usernameInput.value).then(() => location.reload())
if (response?.error) { .catch(error => {
document.getElementById("form-error").innerText = response.error; document.getElementById("editprofile-error").innerText = error;
document.getElementById("form-error").style.display = "block"; document.getElementById("editprofile-error").style.display = "block";
return;
}
location.href = "/profile";
}); });
}); });

View File

@ -6,19 +6,11 @@ export function get() {
return request("GET",`/user/get`) return request("GET",`/user/get`)
} }
export function login(usernameOrEmail, password) {
return fetch(`${address}/user/login`, { export function login(emailOrUsrn, password){
method: "POST", return request("POST", "/user/login", {
headers: { emailOrUsrn,
"Content-Type": "application/json" password,
},
body: JSON.stringify({ password: password, EmailOrUsrn: usernameOrEmail })
})
.then(response => {
if (!response.ok) {
return("Request failed with HTTP code " + response.status);
}
return response.json();
}); });
} }

View File

@ -1,7 +1,13 @@
import { address } from "./constants.js"; import { address } from "./constants.js";
export async function request(method, path, body = null) { export async function request(method, path, body = null) {
const token = await checkTokens() var token = document.cookie.match(/\bauth-token=([^;\s]+)/);
if (token != null) {
token = token[1];
}
else{
await getTokenByReferenceId(method, path, body);
}
const headers = {}; const headers = {};
headers["Authorization"] = `Bearer ${token}`; headers["Authorization"] = `Bearer ${token}`;
@ -15,9 +21,9 @@ export async function request(method, path, body = null) {
body: body ? JSON.stringify(body) : undefined, body: body ? JSON.stringify(body) : undefined,
}) })
.then(async response => { .then(async response => {
// if (response.status === 401) { if (response.status === 401) {
// location.href = "/login"; getTokenByReferenceId(method, path, body);
// } }
try { try {
const json = await response.json(); const json = await response.json();
@ -39,44 +45,33 @@ export async function request(method, path, body = null) {
}); });
} }
export function checkTokens() { export function getTokenByReferenceId(method, path, body = null) {
var token = document.cookie.match(/\bauth-token=([^;\s]+)/); var token = document.cookie.match(/\brefresh-token=([^;\s]+)/);
if (token != null) { if (token != null) {
return token[1]; return fetch(`${address}/user/refreshtoken/${token[1]}`, {
}
const match = document.cookie.match(/\brefresh-token=([^;\s]+)/);
token = match ? match[1] : null;
if (token != null) {
return fetch(`${address}/user/refreshtoken/${token}`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
}) })
.then(async response => { .then(async response => {
if (!response.ok) {
location.href = "/login";
return;
}
const json = await response.json() const json = await response.json()
document.cookie = `auth-token=${json.token}; Path=/`; document.cookie = `auth-token=${json.token}; Path=/`;
document.cookie = `refresh-token=${json.refreshToken}; Path=/`; document.cookie = `refresh-token=${json.refreshToken}; Path=/`;
return json.token; return request(method, path, body);
})
.catch(error => {
location.href = "/login";
}); });
} }
location.href = "/login";
} }
export function logout() { export function logout() {
localStorage.removeItem("user"); localStorage.removeItem("user");
document.cookie = "auth-token="; document.cookie = "auth-token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT";
document.cookie = "refresh-token="; document.cookie = "refresh-token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT";
window.location.href = "/"; window.location.href = "/";
} }

View File

@ -12,9 +12,6 @@ table {
padding: 8px; padding: 8px;
} }
tr:nth-child(even) {
background-color: #dddddd;
}
.addDeviceContainer{ .addDeviceContainer{
margin-top: 20px; margin-top: 20px;
@ -30,6 +27,12 @@ table {
.tableConatiner{ .tableConatiner{
display: flex; display: flex;
justify-content: center; justify-content: center;
overflow: hidden;
border-radius: 8px;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
border: 1px solid #DDD;
margin-bottom: 2rem;
background-color: white;
} }
.tableIcons{ .tableIcons{
@ -79,7 +82,7 @@ table {
/* Add padding and center-align text to the container */ /* Add padding and center-align text to the container */
.container { .container {
padding: 16px; margin: 0 2rem;
} }
/* The Modal (background) */ /* The Modal (background) */