summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-06-03 22:15:43 +0200
committerRory& <root@rory.gay>2025-06-03 22:15:43 +0200
commit2034f459d416afdead72e590f870567452b2c62a (patch)
tree167d52739a058498a5c5877e64f806553543973c
parentRemove admin account routes, fix multiple routes (diff)
downloadnodejs-final-assignment-2034f459d416afdead72e590f870567452b2c62a.tar.xz
Prepare for budgeting, move to native createdAt
-rw-r--r--src/db/schemas/sensorHistory.js9
-rw-r--r--src/db/schemas/spendHistory.js15
-rw-r--r--src/db/schemas/user.js152
-rw-r--r--testFrontend/SafeNSound.FakeUser/MonitorService.cs13
-rw-r--r--testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs47
5 files changed, 145 insertions, 91 deletions
diff --git a/src/db/schemas/sensorHistory.js b/src/db/schemas/sensorHistory.js

index 152f03a..e016079 100644 --- a/src/db/schemas/sensorHistory.js +++ b/src/db/schemas/sensorHistory.js
@@ -6,11 +6,6 @@ import { model, Schema, ObjectId } from 'mongoose'; */ export const sensorHistorySchema = new Schema( { - createdAt: { - type: Date, - default: Date.now, - immutable: true - }, sensor: { type: String, required: true, @@ -23,6 +18,10 @@ export const sensorHistorySchema = new Schema( } }, { + timestamps: { + createdAt: true, + updatedAt: false + }, timeseries: { timeField: 'createdAt' } diff --git a/src/db/schemas/spendHistory.js b/src/db/schemas/spendHistory.js
index b4c3f20..d1d6c2a 100644 --- a/src/db/schemas/spendHistory.js +++ b/src/db/schemas/spendHistory.js
@@ -11,23 +11,22 @@ export const spendHistorySchema = new Schema( required: true, immutable: true }, - items: { - type: [String], + reason: { + type: String, required: true, immutable: true }, - cost: { + amount: { type: Number, required: true, immutable: true - }, - createdAt: { - type: Date, - default: Date.now, - immutable: true } }, { + timestamps: { + createdAt: true, + updatedAt: false + }, timeseries: { timeField: 'createdAt' } diff --git a/src/db/schemas/user.js b/src/db/schemas/user.js
index 69ebb02..55e2e67 100644 --- a/src/db/schemas/user.js +++ b/src/db/schemas/user.js
@@ -11,23 +11,26 @@ export const AlarmType = Object.freeze({ TOILET: 'toilet' }); -export const deviceSchema = new Schema({ - name: { - type: String, - required: true, - trim: true - }, - createdAt: { - type: Date, - default: Date.now, - immutable: true +export const deviceSchema = new Schema( + { + name: { + type: String, + required: true, + trim: true + }, + lastSeen: { + type: Date, + default: Date.now, + required: true + } }, - lastSeen: { - type: Date, - default: Date.now, - required: true + { + timestamps: { + createdAt: true, + updatedAt: false + } } -}); +); export const alarmSchema = new Schema( { @@ -49,66 +52,69 @@ export const alarmSchema = new Schema( * User schema for MongoDB. * @type {module:mongoose.Schema} */ -export const userSchema = new Schema({ - username: { - type: String, - required: true, - unique: true, - trim: true - }, - passwordHash: { - type: String, - required: true - }, - email: { - type: String, - required: true, - unique: true, - trim: true - }, - type: { - type: String, - enum: Object.values(UserType), - default: 'user' - }, - createdAt: { - type: Date, - default: Date.now, - immutable: true - }, - devices: { - type: [deviceSchema], - default: [] - }, - alarm: { - type: alarmSchema - }, - monitoredUsers: { - type: [ObjectId], - ref: 'users' - }, - balance: { - type: Number, - default: 0 - }, - spendHistory: { - type: [ObjectId], - ref: 'spendHistory' - }, - emergencyContacts: { - type: String - }, - medicalInfo: { - type: String +export const userSchema = new Schema( + { + username: { + type: String, + required: true, + unique: true, + trim: true + }, + passwordHash: { + type: String, + required: true + }, + email: { + type: String, + required: true, + unique: true, + trim: true + }, + type: { + type: String, + enum: Object.values(UserType), + default: 'user' + }, + devices: { + type: [deviceSchema], + default: [] + }, + alarm: { + type: alarmSchema + }, + 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 + } }, - location: { - // https://stackoverflow.com/a/27218808 - // Longtitute, Latitude info - type: [Number], - index: { type: '2dsphere', sparse: true }, - count: 2 + { + timestamps: { + createdAt: true, + updatedAt: false + } } -}); +); export const DbUser = model('user', userSchema); diff --git a/testFrontend/SafeNSound.FakeUser/MonitorService.cs b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
index fa2022a..b1da7e6 100644 --- a/testFrontend/SafeNSound.FakeUser/MonitorService.cs +++ b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
@@ -87,11 +87,14 @@ public class MonitorService(ILogger<MonitorService> logger, UserStore userStore) while (!cancellationToken.IsCancellationRequested) { try { var user = userStore.GetRandomMonitor(); - // var alarms = await user.Client!.GetAllAlarms(); - // if(alarms.Count > 0) - // logger.LogInformation("Monitor {UserId} has outstanding alarms: {Alarm}", user.Auth.Username, alarms.ToJson(indent: false)); - // else - // logger.LogInformation("Monitor {UserId} found no alarms to query", user.Auth.Username); + var monitoredUsers = (await user.Client!.GetAssignedUsers()).ToArray(); + if (monitoredUsers.Length == 0) { + logger.LogInformation("Monitor {UserId} has no assigned users", user.Auth.Username); + continue; + } + var userId = Random.Shared.GetItems(monitoredUsers, 1).First(); + var budget = Random.Shared.NextDouble(); + await user.Client!.AddBudget(userId, budget); await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); } catch (Exception ex) { diff --git a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs
index 8b06c30..4376d3f 100644 --- a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs +++ b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs
@@ -118,6 +118,21 @@ public class SafeNSoundClient(SafeNSoundConfiguration config, string accessToken var res = await HttpClient.PostAsync("/auth/logout", null); res.EnsureSuccessStatusCode(); } + + public async Task AddBudget(string userId, BudgetWithReason budget) { + var res = await HttpClient.PatchAsJsonAsync($"/user/{userId}/budget", budget); + res.EnsureSuccessStatusCode(); + } + + public async Task<BudgetWithHistory> GetBudget(string userId = "@me") { + var res = await HttpClient.GetAsync( + userId == "@me" + ? $"/budget" + : $"/user/{userId}/budget" + ); + res.EnsureSuccessStatusCode(); + return (await res.Content.ReadFromJsonAsync<BudgetWithHistory>())!; + } } public class AlarmDto { @@ -140,4 +155,36 @@ public class DeviceDto { [JsonPropertyName("lastSeen")] public DateTime LastSeen { get; set; } +} + +public class Budget { + [JsonPropertyName("budget")] + public double Amount { get; set; } +} + +public class BudgetWithReason : Budget { + [JsonPropertyName("reason")] + public string? Reason { get; set; } +} + +public class BudgetWithHistory { + [JsonPropertyName("budget")] + public double Amount { get; set; } + + [JsonPropertyName("history")] + public List<BudgetHistoryEntry> History { get; set; } = new(); +} + +public class BudgetHistoryEntry { + [JsonPropertyName("venue")] + public string Venue { get; set; } + + [JsonPropertyName("amount")] + public double Amount { get; set; } + + [JsonPropertyName("reason")] + public string Reason { get; set; } + + [JsonPropertyName("createdAt")] + public DateTime CreatedAt { get; set; } } \ No newline at end of file