summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-06-01 17:41:31 +0200
committerRory& <root@rory.gay>2025-06-01 17:41:31 +0200
commit27cda7df659852317d751b4354f75dd54878d4a7 (patch)
tree6447a352b3b8395a3f51c4c4c647bc004473218a
parentRewrite routing (diff)
downloadnodejs-final-assignment-27cda7df659852317d751b4354f75dd54878d4a7.tar.xz
Add sensor history, balance
-rw-r--r--flake.lock6
-rw-r--r--plan.md12
-rw-r--r--src/api/middlewares/authMiddleware.js8
-rw-r--r--src/api/routes.js21
-rw-r--r--src/api/routes/auth/deviceRoutes.js4
-rw-r--r--src/api/routes/budgetRoutes.js6
-rw-r--r--src/db/dbAccess/user.js2
-rw-r--r--src/db/schemas/index.js2
-rw-r--r--src/db/schemas/sensorHistory.js34
-rw-r--r--src/db/schemas/spendHistory.js52
-rw-r--r--src/db/schemas/user.js21
-rw-r--r--src/dto/auth/DeviceDto.js36
-rw-r--r--test.http39
-rw-r--r--testFrontend/SafeNSound.Frontend/Pages/Alarm.razor6
14 files changed, 150 insertions, 99 deletions
diff --git a/flake.lock b/flake.lock

index f12b903..887a767 100644 --- a/flake.lock +++ b/flake.lock
@@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748460289, - "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=", + "lastModified": 1748693115, + "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", "type": "github" }, "original": { diff --git a/plan.md b/plan.md
index 7e54a64..cbedbd5 100644 --- a/plan.md +++ b/plan.md
@@ -26,15 +26,17 @@ - [ ] Get current budget - [ ] Review spending history - [ ] Request additional budget in case of emergency -- [-] Emergency alarm - - [ ] Get alarm list (monitor) - - [ ] Silencing/clearing +- [x] Emergency alarm + - [x] Get alarm list (monitor) + - [x] Silencing/clearing - [ ] Optional: integration with park's emergency services -- [ ] Emergency contact & info card +- [x] Emergency contact & info card + - [ ] Endpoints - [ ] Limitations on consumptions - [ ] Allergies - [ ] Sugar intake limitations -- [ ] Location tracking +- [x] Location tracking + - [ ] Endpoints - [ ] Sensor tracking (sugar level, heart rate, temperature, ...) - [ ] Day planning (meetups, departure, ...) - [ ] Location of activities diff --git a/src/api/middlewares/authMiddleware.js b/src/api/middlewares/authMiddleware.js
index 19de4d8..3a71e45 100644 --- a/src/api/middlewares/authMiddleware.js +++ b/src/api/middlewares/authMiddleware.js
@@ -30,9 +30,13 @@ export function validateAuth(options) { }; } -export const requireUser = validateAuth({ roles: [UserType.USER] }); -export const requireMonitor = validateAuth({ roles: [UserType.MONITOR] }); +export const requireAuth = validateAuth({}); export const requireAdmin = validateAuth({ roles: [UserType.ADMIN] }); +export const requireMonitor = validateAuth({ roles: [UserType.MONITOR] }); +export const requireUser = validateAuth({ roles: [UserType.USER] }); +export const requireUserOrMonitor = validateAuth({ + roles: [UserType.USER, UserType.MONITOR] +}); class AuthValidationOptions { roles; diff --git a/src/api/routes.js b/src/api/routes.js
index ade440e..e808d50 100644 --- a/src/api/routes.js +++ b/src/api/routes.js
@@ -1,11 +1,13 @@ import * as routes from './routes/index.js'; -function logHttpEntry(method, route, exampleBody) { +function logHttpEntry(method, route, exampleBody, description) { + if (description) console.log('%', '#', description); + console.log('%', method, '{{baseUrl}}' + route, 'HTTP/1.1'); if (exampleBody) { console.log('%', 'Content-Type: application/json'); console.log('% '); - console.log('%', exampleBody); + console.log('%', JSON.stringify(exampleBody, null, 4)); console.log('% '); } console.log('% '); @@ -22,17 +24,22 @@ export function registerRoutes(app) { * @type {RouteDescription} */ const route = routes[routeName]; - console.log( - `Registering ${routeName} (${route.path})`, - routes[routeName] - ); Object.keys(route.methods).forEach(routeMethodName => { /** * @type {RouteMethod} */ const routeMethod = route.methods[routeMethodName]; - console.log(routeMethodName, routeMethod); + console.log( + 'Registering', + routeMethodName.toUpperCase(), + route.path + ); + logHttpEntry( + routeMethodName.toUpperCase(), + route.path, + routeMethod.exampleBody + ); app[routeMethodName](route.path, [ ...routeMethod.middlewares, routeMethod.method diff --git a/src/api/routes/auth/deviceRoutes.js b/src/api/routes/auth/deviceRoutes.js
index ac4514f..849a48c 100644 --- a/src/api/routes/auth/deviceRoutes.js +++ b/src/api/routes/auth/deviceRoutes.js
@@ -1,5 +1,5 @@ -import { deleteUser, loginUser, registerUser } from '#db/index.js'; -import { AuthDto, RegisterDto } from '#dto/index.js'; +import { registerUser } from '#db/index.js'; +import { RegisterDto } from '#dto/index.js'; import { validateAuth } from '#api/middlewares/index.js'; import { RouteDescription, RouteMethod } from '#api/RouteDescription.js'; diff --git a/src/api/routes/budgetRoutes.js b/src/api/routes/budgetRoutes.js
index 1cebffe..a808f58 100644 --- a/src/api/routes/budgetRoutes.js +++ b/src/api/routes/budgetRoutes.js
@@ -5,6 +5,7 @@ import { } from '#api/middlewares/index.js'; import { UserType } from '#db/schemas/index.js'; import { RouteDescription, RouteMethod } from '#api/RouteDescription.js'; +import {getUserById} from "#db/dbAccess/index.js"; /** * @type {RouteDescription} @@ -14,7 +15,10 @@ export const getBudgetByUserRoute = { methods: { get: new RouteMethod({ middlewares: [requireMonitor], - async method(req, res) {} + async method(req, res) { + if (!req.) + const user = await getUserById(req.); + } }) } }; diff --git a/src/db/dbAccess/user.js b/src/db/dbAccess/user.js
index 4ab70fd..3900c16 100644 --- a/src/db/dbAccess/user.js +++ b/src/db/dbAccess/user.js
@@ -7,7 +7,7 @@ import { generateJwtToken } from '#util/jwtUtils.js'; async function whoAmI(token) {} -async function getUserById(id) { +export async function getUserById(id) { const user = await DbUser.findById(id); if (!user) { throw new SafeNSoundError({ diff --git a/src/db/schemas/index.js b/src/db/schemas/index.js
index ee1c337..ef18499 100644 --- a/src/db/schemas/index.js +++ b/src/db/schemas/index.js
@@ -1 +1,3 @@ export * from './user.js'; +export * from './spendHistory.js'; +export * from './sensorHistory.js'; diff --git a/src/db/schemas/sensorHistory.js b/src/db/schemas/sensorHistory.js new file mode 100644
index 0000000..0cf1187 --- /dev/null +++ b/src/db/schemas/sensorHistory.js
@@ -0,0 +1,34 @@ +import { model, Schema, ObjectId } from 'mongoose'; + +/** + * User schema for MongoDB. + * @type {module:mongoose.Schema} + */ +export const sensorHistorySchema = new Schema( + { + createdAt: { + type: Date, + default: Date.now, + immutable: true + }, + sensor: { + type: String, + required: true, + immutable: true + }, + value: { + type: Number, + required: true, + immutable: true + } + }, + { + timeseries: { + timeField: 'createdAt' + } + } +); + +export const DbSpendHistory = model('sensorHistory', sensorHistorySchema); + +console.log('[MONGODB] sensorHistory schema initialized successfully!'); diff --git a/src/db/schemas/spendHistory.js b/src/db/schemas/spendHistory.js
index b12bcc3..b4c3f20 100644 --- a/src/db/schemas/spendHistory.js +++ b/src/db/schemas/spendHistory.js
@@ -1,29 +1,39 @@ -import { model, Schema } from 'mongoose'; -import { hash, compare } from 'bcrypt'; -import {ref} from "joi"; +import { model, Schema, ObjectId } from 'mongoose'; /** * User schema for MongoDB. * @type {module:mongoose.Schema} */ -export const spendHistorySchema = new Schema({ - spentBy: { - type: ObjectId, - ref: "users" +export const spendHistorySchema = new Schema( + { + venue: { + type: String, + required: true, + immutable: true + }, + items: { + type: [String], + required: true, + immutable: true + }, + cost: { + type: Number, + required: true, + immutable: true + }, + createdAt: { + type: Date, + default: Date.now, + immutable: true + } + }, + { + timeseries: { + timeField: 'createdAt' + } } - createdAt: { - type: Date, - default: Date.now, - immutable: true - } -}); - -export const UserType = Object.freeze({ - USER: 'user', - MONITOR: 'monitor', - ADMIN: 'admin' -}); +); -export const DbUser = model('user', userSchema); +export const DbSpendHistory = model('spendHistory', spendHistorySchema); -console.log('[MONGODB] User schema initialized successfully!'); +console.log('[MONGODB] spendHistory schema initialized successfully!'); diff --git a/src/db/schemas/user.js b/src/db/schemas/user.js
index f8802d7..7680319 100644 --- a/src/db/schemas/user.js +++ b/src/db/schemas/user.js
@@ -84,6 +84,27 @@ export const userSchema = new Schema({ monitoredUsers: { type: [ObjectId], ref: 'users' + }, + balance: { + type: Number, + default: 0 + }, + spendHistory: { + type: [ObjectId], + ref: 'spendHistory' + }, + emergencyContacts: { + type: String + }, + medicalInfo: { + type: String + }, + location: { + // https://stackoverflow.com/a/27218808 + // Longtitute, Latitude info + type: [Number], + index: { type: '2dsphere', sparse: true }, + count: 2 } }); diff --git a/src/dto/auth/DeviceDto.js b/src/dto/auth/DeviceDto.js deleted file mode 100644
index 40f1959..0000000 --- a/src/dto/auth/DeviceDto.js +++ /dev/null
@@ -1,36 +0,0 @@ -import { SafeNSoundError } from '#util/error.js'; -import Joi from 'joi'; - -export class RegisterDto { - static schema = new Joi.object({ - username: Joi.string().required(), - email: Joi.string().email().required(), - password: Joi.string().required(), - type: Joi.string().valid('user', 'monitor', 'admin').required() - }); - - username; - email; - password; - type = 'user'; - - static async create(data) { - const obj = new RegisterDto(); - for (const key of Object.keys(data)) { - if (key in obj) { - obj[key] = data[key]; - } - } - - try { - return await RegisterDto.schema.validateAsync(obj); - } catch (e) { - console.log(e); - throw new SafeNSoundError({ - errCode: 'JOI_VALIDATION_ERROR', - message: e.message, - validation_details: e.details - }); - } - } -} diff --git a/test.http b/test.http
index 66dfa1e..98b1ebd 100644 --- a/test.http +++ b/test.http
@@ -1,59 +1,58 @@ -@base -GET /budget/:id/add HTTP/1.1 +GET {{baseUrl}}/budget/:id/add HTTP/1.1 ### -GET /admin/users HTTP/1.1 +GET {{baseUrl}}/admin/users HTTP/1.1 ### -GET /admin/user/:id HTTP/1.1 +GET {{baseUrl}}/admin/user/:id HTTP/1.1 ### -DELETE /admin/user/:id HTTP/1.1 +DELETE {{baseUrl}}/admin/user/:id HTTP/1.1 ### -GET /alarm/:id HTTP/1.1 +GET {{baseUrl}}/alarm/:id HTTP/1.1 ### -DELETE /alarm/:id HTTP/1.1 +PUT {{baseUrl}}/alarm/:id HTTP/1.1 ### -GET /alarms HTTP/1.1 +GET {{baseUrl}}/alarms HTTP/1.1 ### -GET /alarm/@me HTTP/1.1 +GET {{baseUrl}}/alarm/@me HTTP/1.1 ### -PUT /alarm/@me HTTP/1.1 +PUT {{baseUrl}}/alarm/@me HTTP/1.1 ### -DELETE /alarm/@me HTTP/1.1 +DELETE {{baseUrl}}/alarm/@me HTTP/1.1 ### -DELETE /auth/delete HTTP/1.1 +DELETE {{baseUrl}}/auth/delete HTTP/1.1 ### -GET /budget/:id HTTP/1.1 +GET {{baseUrl}}/budget/:id HTTP/1.1 ### -GET /budget/@me HTTP/1.1 +GET {{baseUrl}}/budget/@me HTTP/1.1 ### -GET /auth/devices HTTP/1.1 +GET {{baseUrl}}/auth/devices HTTP/1.1 ### -GET / HTTP/1.1 +GET {{baseUrl}}/ HTTP/1.1 ### -POST /auth/login HTTP/1.1 +POST {{baseUrl}}/auth/login HTTP/1.1 ### -POST /auth/logout HTTP/1.1 +POST {{baseUrl}}/auth/logout HTTP/1.1 ### -POST /auth/register HTTP/1.1 +POST {{baseUrl}}/auth/register HTTP/1.1 ### -GET /status HTTP/1.1 +GET {{baseUrl}}/status HTTP/1.1 ### diff --git a/testFrontend/SafeNSound.Frontend/Pages/Alarm.razor b/testFrontend/SafeNSound.Frontend/Pages/Alarm.razor
index 9b90ef4..9b2ee9d 100644 --- a/testFrontend/SafeNSound.Frontend/Pages/Alarm.razor +++ b/testFrontend/SafeNSound.Frontend/Pages/Alarm.razor
@@ -1,7 +1,7 @@ @page "/Alarm" <h1>Alarm</h1> - +<LinkButton OnClick="@RaiseAlarm">Raise alarm</LinkButton> <br/><br/> @if (Exception != null) { @@ -33,4 +33,8 @@ } } + private async Task RaiseAlarm() { + await App.Client!.SetAlarm(new() { }); + } + } \ No newline at end of file