diff --git a/CommBank-Server/CommBank.csproj b/CommBank-Server/CommBank.csproj index 983cc882..58d4ddb5 100644 --- a/CommBank-Server/CommBank.csproj +++ b/CommBank-Server/CommBank.csproj @@ -30,6 +30,12 @@ - + + + + PreserveNewest + + + diff --git a/CommBank-Server/Data/Accounts.json b/CommBank-Server/Data/Accounts.json new file mode 100644 index 00000000..c94a91dc --- /dev/null +++ b/CommBank-Server/Data/Accounts.json @@ -0,0 +1,53 @@ +[{ + "_id": { + "$oid": "62a3e6aad25715026d1a2938" + }, + "Number": 123456789, + "Name": "Tag's Goal Saver", + "Balance": 6483.81, + "AccountType": "GoalSaver", + "TransactionIds": [ + { + "$oid": "62a3a284d07648900df72860" + }, + { + "$oid": "62a3a2ded07648900df72861" + }, + { + "$oid": "62a3a2ded07648900df72862" + }, + { + "$oid": "62a3a2ded07648900df72863" + }, + { + "$oid": "62a3a2ded07648900df72864" + }, + { + "$oid": "62a3a2ded07648900df72865" + }, + { + "$oid": "62a3a2ded07648900df72866" + }, + { + "$oid": "62a3a2ded07648900df72867" + }, + { + "$oid": "62a3a2ded07648900df72868" + }, + { + "$oid": "62a3a2ded07648900df72869" + }, + { + "$oid": "62a3a344d07648900df7286a" + }, + { + "$oid": "62a3a344d07648900df7286b" + }, + { + "$oid": "62a3a344d07648900df7286c" + }, + { + "$oid": "62a3a344d07648900df7286d" + } + ] +}] \ No newline at end of file diff --git a/CommBank-Server/Data/CollectionNameAttribute.cs b/CommBank-Server/Data/CollectionNameAttribute.cs new file mode 100644 index 00000000..982462b0 --- /dev/null +++ b/CommBank-Server/Data/CollectionNameAttribute.cs @@ -0,0 +1,7 @@ +namespace CommBank.Data; + +public class CollectionNameAttribute : Attribute +{ + public string Name { get; set; } + public CollectionNameAttribute(string name) => Name = name; +} \ No newline at end of file diff --git a/CommBank-Server/Data/Goals.json b/CommBank-Server/Data/Goals.json new file mode 100644 index 00000000..f42d18ba --- /dev/null +++ b/CommBank-Server/Data/Goals.json @@ -0,0 +1,94 @@ +[ + { + "_id": { + "$oid": "62a3f587102e921da1253d32" + }, + "Name": "House Down Payment", + "TargetAmount": 100000, + "TargetDate": { + "$date": { + "$numberLong": "1736312400000" + } + }, + "Balance": 73501.82, + "Created": { + "$date": { + "$numberLong": "1654912390857" + } + }, + "TransactionIds": null, + "TagIds": null, + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3f5e0102e921da1253d33" + }, + "Name": "Tesla Model Y", + "TargetAmount": 60000, + "TargetDate": { + "$date": { + "$numberLong": "1662004800000" + } + }, + "Balance": 43840.02, + "Created": { + "$date": { + "$numberLong": "1654912480950" + } + }, + "TransactionIds": null, + "TagIds": null, + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3f62e102e921da1253d34" + }, + "Name": "Trip to London", + "TargetAmount": 3500, + "TargetDate": { + "$date": { + "$numberLong": "1659412800000" + } + }, + "Created": { + "$date": { + "$numberLong": "1654912558236" + } + }, + "TransactionIds": null, + "TagIds": null, + "Balance": 753.89, + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a61945fa15f1cd18516a5f" + }, + "Name": "Trip to NYC", + "TargetAmount": 800, + "TargetDate": { + "$date": { + "$numberLong": "1702184400000" + } + }, + "Balance": 0, + "Created": { + "$date": { + "$numberLong": "1655053065668" + } + }, + "TransactionIds": null, + "TagIds": null, + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + } +] \ No newline at end of file diff --git a/CommBank-Server/Data/MongoDatabaseExtensions.cs b/CommBank-Server/Data/MongoDatabaseExtensions.cs new file mode 100644 index 00000000..1c720f73 --- /dev/null +++ b/CommBank-Server/Data/MongoDatabaseExtensions.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using CommBank.Data; +using MongoDB.Driver; + +namespace CommBank.Data; + +public static class MongoDatabaseExtensions +{ + public static IMongoCollection GetCollection(this IMongoDatabase database) + { + var attribute = typeof(T).GetCustomAttribute(); + var collection = database.GetCollection(attribute?.Name ?? typeof(T).Name + "s"); + return collection; + } +} \ No newline at end of file diff --git a/CommBank-Server/Data/MongoDbSeeder.cs b/CommBank-Server/Data/MongoDbSeeder.cs new file mode 100644 index 00000000..6c7bf17b --- /dev/null +++ b/CommBank-Server/Data/MongoDbSeeder.cs @@ -0,0 +1,95 @@ +using System.Reflection; +using System.Text.Json; +using CommBank.Models; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Driver; +using Tag = CommBank.Models.Tag; + +namespace CommBank.Data; + +public class MongoDbSeeder : IDisposable +{ + + private readonly IMongoDatabase _database; + private readonly IMongoCollection _accountsCollection; + private readonly IMongoCollection _goalsCollection; + private readonly IMongoCollection _tagsCollection; + private readonly IMongoCollection _transactionsCollection; + private readonly IMongoCollection _usersCollection; + + + + + public MongoDbSeeder(IMongoDatabase mongoDatabase) + { + _database = mongoDatabase; + _accountsCollection = mongoDatabase.GetCollection(); + _goalsCollection = mongoDatabase.GetCollection(); + _tagsCollection = mongoDatabase.GetCollection(); + _transactionsCollection = mongoDatabase.GetCollection(); + _usersCollection = mongoDatabase.GetCollection(); + } + + public async Task SeedAsync() + { + await SeedCollectionAsync("Accounts.json"); + await SeedCollectionAsync("Goals.json"); + await SeedCollectionAsync("Tags.json"); + await SeedCollectionAsync("Transactions.json"); + await SeedCollectionAsync("Users.json"); + } + + private async Task SeedCollectionAsync(string fileName) + { + var collectionName = typeof(T).GetCustomAttribute()?.Name ?? typeof(T).Name + "s"; + var collection = _database.GetCollection(collectionName); + + // Check if the collection is already seeded + bool hasData = await collection.Find(_ => true).AnyAsync(); + + if (!hasData) + { + var filePath = Path.Combine(AppContext.BaseDirectory, "Data", fileName); + + if (!File.Exists(filePath)) + { + Console.WriteLine($"Seed file not found: {filePath}"); + return; + } + + // Read and deserialize the JSON file + var jsonString = await File.ReadAllTextAsync(filePath); + + var documentArray = BsonSerializer.Deserialize(jsonString); + + var items = documentArray + .Select(doc => BsonSerializer.Deserialize(doc.AsBsonDocument)) + .ToList(); + + // Insert the data if the file wasn't empty + if (items is { Count: > 0 }) + { + await collection.InsertManyAsync(items); + Console.WriteLine($"Successfully seeded {items.Count} items into {collectionName}."); + } + } + } + + public void Dispose() + { + + + } +} + +public static class MongoDbSeederExtensions +{ + public static async Task SeedDataAsync(this IHost host) + { + using var scope = host.Services.CreateScope(); + var mongoDatabase = scope.ServiceProvider.GetRequiredService(); + using var seeder = new MongoDbSeeder(mongoDatabase); + await seeder.SeedAsync(); + } +} \ No newline at end of file diff --git a/CommBank-Server/Data/Tags.json b/CommBank-Server/Data/Tags.json new file mode 100644 index 00000000..202e1abc --- /dev/null +++ b/CommBank-Server/Data/Tags.json @@ -0,0 +1,26 @@ +[{ + "_id": { + "$oid": "62a39d27025ca1ba8f1f1c1e" + }, + "Name": "Groceries" +},{ + "_id": { + "$oid": "62a39d42025ca1ba8f1f1c1f" + }, + "Name": "Restaurant" +},{ + "_id": { + "$oid": "62a39d4e025ca1ba8f1f1c20" + }, + "Name": "Income" +},{ + "_id": { + "$oid": "62a39d5a025ca1ba8f1f1c21" + }, + "Name": "Gas" +},{ + "_id": { + "$oid": "62a39d63025ca1ba8f1f1c22" + }, + "Name": "Investment" +}] \ No newline at end of file diff --git a/CommBank-Server/Data/Transactions.json b/CommBank-Server/Data/Transactions.json new file mode 100644 index 00000000..9320984d --- /dev/null +++ b/CommBank-Server/Data/Transactions.json @@ -0,0 +1,310 @@ +[ + { + "_id": { + "$oid": "62a3a284d07648900df72860" + }, + "TransactionType": "Debit", + "Amount": 135.39, + "DateTime": { + "$date": { + "$numberLong": "1654891140391" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d27025ca1ba8f1f1c1e" + } + ], + "Description": "Whole Foods", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a2ded07648900df72861" + }, + "TransactionType": "Debit", + "Amount": 139.26, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d27025ca1ba8f1f1c1e" + } + ], + "Description": "Whole Foods", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a2ebd07648900df72862" + }, + "TransactionType": "Debit", + "Amount": 26.39, + "DateTime": { + "$date": { + "$numberLong": "1654891243091" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d42025ca1ba8f1f1c1f" + } + ], + "Description": "Chipotle", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a2ecd07648900df72863" + }, + "TransactionType": "Debit", + "Amount": 21.9, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d42025ca1ba8f1f1c1f" + } + ], + "Description": "Chipotle", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a316d07648900df72864" + }, + "TransactionType": "Credit", + "Amount": 5622.81, + "DateTime": { + "$date": { + "$numberLong": "1654891286080" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d4e025ca1ba8f1f1c20" + } + ], + "Description": "Dropbox", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a318d07648900df72865" + }, + "TransactionType": "Credit", + "Amount": 5622.92, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d4e025ca1ba8f1f1c20" + } + ], + "Description": "Dropbox", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a323d07648900df72866" + }, + "TransactionType": "Credit", + "Amount": 1439.18, + "DateTime": { + "$date": { + "$numberLong": "1654891299481" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d4e025ca1ba8f1f1c20" + } + ], + "Description": "Fencer", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a324d07648900df72867" + }, + "TransactionType": "Credit", + "Amount": 1439.89, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d4e025ca1ba8f1f1c20" + } + ], + "Description": "Fencer", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a337d07648900df72868" + }, + "TransactionType": "Debit", + "Amount": 44.52, + "DateTime": { + "$date": { + "$numberLong": "1654891319411" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d5a025ca1ba8f1f1c21" + } + ], + "Description": "Gas", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a338d07648900df72869" + }, + "TransactionType": "Debit", + "Amount": 44.13, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d5a025ca1ba8f1f1c21" + } + ], + "Description": "Gas", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a344d07648900df7286a" + }, + "TransactionType": "Debit", + "Amount": 1500, + "DateTime": { + "$date": { + "$numberLong": "1654891332111" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d63025ca1ba8f1f1c22" + } + ], + "Description": "Coinbase", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a344d07648900df7286b" + }, + "TransactionType": "Debit", + "Amount": 1500, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d63025ca1ba8f1f1c22" + } + ], + "Description": "Coinbase", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a348d07648900df7286c" + }, + "TransactionType": "Debit", + "Amount": 1500, + "DateTime": { + "$date": { + "$numberLong": "1654891336929" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d63025ca1ba8f1f1c22" + } + ], + "Description": "Titan", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + }, + { + "_id": { + "$oid": "62a3a349d07648900df7286d" + }, + "TransactionType": "Debit", + "Amount": 1500, + "DateTime": { + "$date": { + "$numberLong": "1654027230566" + } + }, + "GoalId": null, + "TagIds": [ + { + "$oid": "62a39d63025ca1ba8f1f1c22" + } + ], + "Description": "Titan", + "UserId": { + "$oid": "62a29c15f4605c4c9fa7f306" + } + } +] \ No newline at end of file diff --git a/CommBank-Server/Data/Users.json b/CommBank-Server/Data/Users.json new file mode 100644 index 00000000..aa8243cd --- /dev/null +++ b/CommBank-Server/Data/Users.json @@ -0,0 +1,69 @@ +[ + { + "_id": { + "$oid": "62a29c15f4605c4c9fa7f306" + }, + "Name": "Tag Ramotar", + "Email": "tag@dropbox.com", + "Password": "$2a$11$10VhY5XIwBeWA4uLIE.sr.c34UvwLRQPD8yy7z/4iiN6ez5z2Pg1S", + "AccountIds": null, + "GoalIds": [ + { + "$oid": "62a3f587102e921da1253d32" + }, + { + "$oid": "62a3f5e0102e921da1253d33" + }, + { + "$oid": "62a3f62e102e921da1253d34" + }, + { + "$oid": "62a61945fa15f1cd18516a5f" + } + ], + "TransactionIds": [ + { + "$oid": "62a3a284d07648900df72860" + }, + { + "$oid": "62a3a2ded07648900df72861" + }, + { + "$oid": "62a3a2ebd07648900df72862" + }, + { + "$oid": "62a3a2ebd07648900df72863" + }, + { + "$oid": "62a3a2ebd07648900df72864" + }, + { + "$oid": "62a3a2ebd07648900df72865" + }, + { + "$oid": "62a3a2ebd07648900df72866" + }, + { + "$oid": "62a3a2ebd07648900df72867" + }, + { + "$oid": "62a3a2ebd07648900df72868" + }, + { + "$oid": "62a3a2ebd07648900df72869" + }, + { + "$oid": "62a3a344d07648900df7286a" + }, + { + "$oid": "62a3a344d07648900df7286b" + }, + { + "$oid": "62a3a348d07648900df7286c" + }, + { + "$oid": "62a3a349d07648900df7286d" + } + ] + } +] \ No newline at end of file diff --git a/CommBank-Server/Models/Account.cs b/CommBank-Server/Models/Account.cs index cc62e354..7db26374 100644 --- a/CommBank-Server/Models/Account.cs +++ b/CommBank-Server/Models/Account.cs @@ -1,9 +1,11 @@ using MongoDB.Bson; using System.Text.Json.Serialization; +using CommBank.Data; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; +[CollectionName("Accounts")] public class Account { [BsonId] @@ -11,7 +13,7 @@ public class Account public string? Id { get; set; } public long? Number { get; set; } - + public string? Name { get; set; } public double Balance { get; set; } = 0; diff --git a/CommBank-Server/Models/Goal.cs b/CommBank-Server/Models/Goal.cs index 77ff1ad5..5ab251ca 100644 --- a/CommBank-Server/Models/Goal.cs +++ b/CommBank-Server/Models/Goal.cs @@ -1,8 +1,9 @@ -using MongoDB.Bson; +using CommBank.Data; +using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; - +[CollectionName("Goals")] public class Goal { [BsonId] @@ -10,6 +11,8 @@ public class Goal public string? Id { get; set; } public string? Name { get; set; } + + public string? Icon { get; set; } public UInt64 TargetAmount { get; set; } = 0; diff --git a/CommBank-Server/Models/Tag.cs b/CommBank-Server/Models/Tag.cs index 0fda50b8..7a5d1e8a 100644 --- a/CommBank-Server/Models/Tag.cs +++ b/CommBank-Server/Models/Tag.cs @@ -1,8 +1,10 @@ -using MongoDB.Bson; +using CommBank.Data; +using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; +[CollectionName("Tags")] public class Tag { [BsonId] diff --git a/CommBank-Server/Models/Transaction.cs b/CommBank-Server/Models/Transaction.cs index cd7c521b..ea49ea54 100644 --- a/CommBank-Server/Models/Transaction.cs +++ b/CommBank-Server/Models/Transaction.cs @@ -1,9 +1,11 @@ using MongoDB.Bson; using System.Text.Json.Serialization; +using CommBank.Data; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; +[CollectionName("Transactions")] public class Transaction { [BsonId] diff --git a/CommBank-Server/Models/User.cs b/CommBank-Server/Models/User.cs index 3fad72bf..03ab9626 100644 --- a/CommBank-Server/Models/User.cs +++ b/CommBank-Server/Models/User.cs @@ -1,8 +1,10 @@ -using MongoDB.Bson; +using CommBank.Data; +using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; +[CollectionName("Users")] public class User { [BsonId] diff --git a/CommBank-Server/Program.cs b/CommBank-Server/Program.cs index a88e560d..040a6a8c 100644 --- a/CommBank-Server/Program.cs +++ b/CommBank-Server/Program.cs @@ -1,4 +1,5 @@ -using CommBank.Models; +using CommBank.Data; +using CommBank.Models; using CommBank.Services; using MongoDB.Driver; @@ -12,6 +13,7 @@ builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json"); var mongoClient = new MongoClient(builder.Configuration.GetConnectionString("CommBank")); +builder.Services.AddScoped(x => mongoClient.GetDatabase("CommBank") ); var mongoDatabase = mongoClient.GetDatabase("CommBank"); IAccountsService accountsService = new AccountsService(mongoDatabase); @@ -32,6 +34,8 @@ var app = builder.Build(); +await app.SeedDataAsync(); + app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyMethod() diff --git a/CommBank-Server/Secrets.json b/CommBank-Server/Secrets.json deleted file mode 100644 index 0e5bf949..00000000 --- a/CommBank-Server/Secrets.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "CommBank": "{CONNECTION_STRING}" - } -} \ No newline at end of file diff --git a/CommBank.Tests/GoalControllerTests.cs b/CommBank.Tests/GoalControllerTests.cs index 8380181f..6bab0efd 100644 --- a/CommBank.Tests/GoalControllerTests.cs +++ b/CommBank.Tests/GoalControllerTests.cs @@ -66,9 +66,26 @@ public async void Get() public async void GetForUser() { // Arrange + var goals = collections.GetGoals(); + var users = collections.GetUsers(); + IGoalsService goalsService = new FakeGoalsService(goals, goals[0]); + IUsersService usersService = new FakeUsersService(users, users[0]); + GoalController controller = new(goalsService, usersService); // Act + var httpContext = new Microsoft.AspNetCore.Http.DefaultHttpContext(); + controller.ControllerContext.HttpContext = httpContext; + var result = await controller.GetForUser(goals[0].UserId!); + // Assert + Assert.NotNull(result); + + result!.ForEach(goal => + { + Assert.IsAssignableFrom(goal); + Assert.Equal(goals.First().UserId, goal.UserId); + }); + } } \ No newline at end of file