diff --git a/CommBank-Server/CommBank.csproj b/CommBank-Server/CommBank.csproj index 983cc88..10d0717 100644 --- a/CommBank-Server/CommBank.csproj +++ b/CommBank-Server/CommBank.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 enable enable CommBank_Server @@ -10,10 +10,11 @@ - + + - + diff --git a/CommBank-Server/Controllers/GoalController.cs b/CommBank-Server/Controllers/GoalController.cs index 98271a5..a20e88c 100644 --- a/CommBank-Server/Controllers/GoalController.cs +++ b/CommBank-Server/Controllers/GoalController.cs @@ -99,4 +99,34 @@ public async Task Delete(string id) return NoContent(); } + + [HttpPost("{id:length(24)}/icon")] + public async Task UpdateIcon(string id, UpdatedIcon updatedIcon) + { + var goal = await _goalsService.GetAsync(id); + + if (goal is null) + { + return NotFound(); + } + + goal.Icon = updatedIcon.Icon; + + await _goalsService.UpdateAsync(id, goal); + + return Ok(goal); + } + + [HttpGet("{id:length(24)}/icon")] + public async Task GetIcon(string id) + { + var goal = await _goalsService.GetAsync(id); + + if (goal is null) + { + return NotFound(); + } + + return Ok(new { icon = goal.Icon }); + } } \ No newline at end of file diff --git a/CommBank-Server/Models/Goal.cs b/CommBank-Server/Models/Goal.cs index 77ff1ad..5905567 100644 --- a/CommBank-Server/Models/Goal.cs +++ b/CommBank-Server/Models/Goal.cs @@ -17,7 +17,7 @@ public class Goal public double Balance { get; set; } = 0.00; - public DateTime Created { get; set; } = DateTime.Now; + public DateTime Created { get; set; } = DateTime.UtcNow; [BsonRepresentation(BsonType.ObjectId)] public List? TransactionIds { get; set; } @@ -27,4 +27,5 @@ public class Goal [BsonRepresentation(BsonType.ObjectId)] public string? UserId { get; set; } + public string? Icon { get; set; } } \ No newline at end of file diff --git a/CommBank-Server/Models/Transaction.cs b/CommBank-Server/Models/Transaction.cs index cd7c521..44bb579 100644 --- a/CommBank-Server/Models/Transaction.cs +++ b/CommBank-Server/Models/Transaction.cs @@ -16,7 +16,7 @@ public class Transaction public double Amount { get; set; } = 0.00; - public DateTime DateTime { get; set; } = DateTime.Now; + public DateTime DateTime { get; set; } = DateTime.UtcNow; [BsonRepresentation(BsonType.ObjectId)] public string? GoalId { get; set; } diff --git a/CommBank-Server/Program.cs b/CommBank-Server/Program.cs index a88e560..feb327f 100644 --- a/CommBank-Server/Program.cs +++ b/CommBank-Server/Program.cs @@ -1,53 +1,71 @@ using CommBank.Models; using CommBank.Services; using MongoDB.Driver; +using Newtonsoft.Json.Serialization; -var builder = WebApplication.CreateBuilder(args); +try +{ + var builder = WebApplication.CreateBuilder(args); -builder.Services.AddControllers(); + builder.Services.AddControllers(); -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); -builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json"); + builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json"); -var mongoClient = new MongoClient(builder.Configuration.GetConnectionString("CommBank")); -var mongoDatabase = mongoClient.GetDatabase("CommBank"); + Console.WriteLine("Attempting to connect to MongoDB..."); + var mongoClient = new MongoClient(builder.Configuration.GetConnectionString("CommBank")); + // Use the actual Atlas database name as shown in the cluster + var mongoDatabase = mongoClient.GetDatabase("commbank"); + Console.WriteLine("MongoDB connected to database: commbank"); -IAccountsService accountsService = new AccountsService(mongoDatabase); -IAuthService authService = new AuthService(mongoDatabase); -IGoalsService goalsService = new GoalsService(mongoDatabase); -ITagsService tagsService = new TagsService(mongoDatabase); -ITransactionsService transactionsService = new TransactionsService(mongoDatabase); -IUsersService usersService = new UsersService(mongoDatabase); + IAccountsService accountsService = new AccountsService(mongoDatabase); + IAuthService authService = new AuthService(mongoDatabase); + IGoalsService goalsService = new GoalsService(mongoDatabase); + ITagsService tagsService = new TagsService(mongoDatabase); + ITransactionsService transactionsService = new TransactionsService(mongoDatabase); + IUsersService usersService = new UsersService(mongoDatabase); -builder.Services.AddSingleton(accountsService); -builder.Services.AddSingleton(authService); -builder.Services.AddSingleton(goalsService); -builder.Services.AddSingleton(tagsService); -builder.Services.AddSingleton(transactionsService); -builder.Services.AddSingleton(usersService); + builder.Services.AddSingleton(accountsService); + builder.Services.AddSingleton(authService); + builder.Services.AddSingleton(goalsService); + builder.Services.AddSingleton(tagsService); + builder.Services.AddSingleton(transactionsService); + builder.Services.AddSingleton(usersService); -builder.Services.AddCors(); + builder.Services.AddCors(); -var app = builder.Build(); + var app = builder.Build(); -app.UseCors(builder => builder - .AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader()); + app.UseCors(builder => builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader()); -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} + if (app.Environment.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(); + } + else + { + app.UseHttpsRedirection(); + } -app.UseHttpsRedirection(); + app.UseAuthorization(); -app.UseAuthorization(); + app.MapControllers(); -app.MapControllers(); + // Add a simple health check endpoint + app.MapGet("/health", () => "OK"); -app.Run(); + app.Run(); +} +catch (Exception ex) +{ + Console.WriteLine($"Fatal error: {ex}"); + throw; +} diff --git a/CommBank-Server/Properties/launchSettings.json b/CommBank-Server/Properties/launchSettings.json index 2c9f444..da3c0a7 100644 --- a/CommBank-Server/Properties/launchSettings.json +++ b/CommBank-Server/Properties/launchSettings.json @@ -11,7 +11,7 @@ "profiles": { "CommBank_Server": { "commandName": "Project", - "launchBrowser": true, + "launchBrowser": false, "launchUrl": "swagger", "applicationUrl": "http://localhost:11366;http://localhost:5203", "environmentVariables": { diff --git a/CommBank-Server/Secrets.json b/CommBank-Server/Secrets.json index 0e5bf94..cdd514c 100644 --- a/CommBank-Server/Secrets.json +++ b/CommBank-Server/Secrets.json @@ -1,5 +1,7 @@ -{ + +{ "ConnectionStrings": { - "CommBank": "{CONNECTION_STRING}" + "CommBank": "mongodb+sv://username:password@cluster0.jja3hhp.mongodb.net/?appName=Cluster0" } -} \ No newline at end of file +} + diff --git a/CommBank.Tests/CommBank.Tests.csproj b/CommBank.Tests/CommBank.Tests.csproj index 4d9413f..4f7f67d 100644 --- a/CommBank.Tests/CommBank.Tests.csproj +++ b/CommBank.Tests/CommBank.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 enable enable @@ -10,6 +10,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/CommBank.Tests/GoalControllerTests.cs b/CommBank.Tests/GoalControllerTests.cs index 8380181..fb629ae 100644 --- a/CommBank.Tests/GoalControllerTests.cs +++ b/CommBank.Tests/GoalControllerTests.cs @@ -66,9 +66,32 @@ public async void Get() public async void GetForUser() { // Arrange - + var goals = collections.GetGoals(); + var users = collections.GetUsers(); + + // Ensure goals have a UserId to filter/assert against + var expectedUserId = users[0].Id!; + foreach (var g in goals) + { + g.UserId = expectedUserId; + } + + 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(expectedUserId); + // Assert + Assert.NotNull(result); + + foreach (Goal goal in result!) + { + Assert.IsAssignableFrom(goal); + Assert.Equal(expectedUserId, goal.UserId); + } } } \ No newline at end of file diff --git a/Connection/Connect.cs b/Connection/Connect.cs new file mode 100644 index 0000000..3ec008e --- /dev/null +++ b/Connection/Connect.cs @@ -0,0 +1,21 @@ + +using MongoDB.Driver; +using MongoDB.Bson; + +const string connectionUri = "mongodb+srv://username:password@cluster0.jja3hhp.mongodb.net/?appName=Cluster0"; + +var settings = MongoClientSettings.FromConnectionString(connectionUri); + +// Set the ServerApi field of the settings object to set the version of the Stable API on the client +settings.ServerApi = new ServerApi(ServerApiVersion.V1); + +// Create a new client and connect to the server +var client = new MongoClient(settings); + +// Send a ping to confirm a successful connection +try { + var result = client.GetDatabase("admin").RunCommand(new BsonDocument("ping", 1)); + Console.WriteLine("Pinged your deployment. You successfully connected to MongoDB!"); +} catch (Exception ex) { + Console.WriteLine(ex); +} diff --git a/http-test.http b/http-test.http new file mode 100644 index 0000000..763dc17 --- /dev/null +++ b/http-test.http @@ -0,0 +1,56 @@ +### Health Check +GET http://localhost:11366/health + +### Get All Goals (should be empty initially) +GET http://localhost:11366/api/Goal +Accept: application/json + +### Get All Accounts +GET http://localhost:11366/api/Account +Accept: application/json + +### Get All Users +GET http://localhost:11366/api/User +Accept: application/json + +### Get All Transactions +GET http://localhost:11366/api/Transaction +Accept: application/json + +### Get All Tags +GET http://localhost:11366/api/Tag +Accept: application/json + +### Create a new User +POST http://localhost:11366/api/User +Content-Type: application/json + +{ + "name": "Test User", + "email": "test@example.com", + "password": "TestPassword123" +} + +### Create a new Goal (you'll need a valid userId from the step above) +POST http://localhost:11366/api/Goal +Content-Type: application/json + +{ + "name": "Save Money", + "targetAmount": 5000, + "currentAmount": 0, + "userId": "696772c9be66d4f22d7e4d77" +} + +### adding icon to Goal (you'll need a valid goalId from the step above) +POST http://localhost:11366/api/Goal/696772f9be66d4f22d7e4d78/icon +Content-Type: application/json + +{ + "icon": "😡" +} + +### +### Get All Goals (should be empty initially) +GET http://localhost:11366/api/Goal/696772f9be66d4f22d7e4d78/icon +Accept: application/json diff --git a/test-serialization.cs b/test-serialization.cs new file mode 100644 index 0000000..50ce61b --- /dev/null +++ b/test-serialization.cs @@ -0,0 +1,59 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Driver; +using Newtonsoft.Json; + +// Simple test to see if the Goal serialization works +var settings = new JsonSerializerSettings +{ + DateFormatString = "yyyy-MM-ddTHH:mm:ssZ", + DateTimeZoneHandling = DateTimeZoneHandling.Utc +}; + +var goal = new Goal +{ + Id = ObjectId.GenerateNewId().ToString(), + Name = "Test Goal", + TargetAmount = 5000, + Balance = 1000, + TargetDate = DateTime.UtcNow.AddMonths(1), + Created = DateTime.UtcNow, + UserId = ObjectId.GenerateNewId().ToString() +}; + +try +{ + var json = JsonConvert.SerializeObject(goal, settings); + Console.WriteLine("Serialization successful:"); + Console.WriteLine(json); +} +catch (Exception ex) +{ + Console.WriteLine($"Serialization failed: {ex}"); +} + +public class Goal +{ + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string? Id { get; set; } + + public string? Name { get; set; } + + public ulong TargetAmount { get; set; } = 0; + + public DateTime TargetDate { get; set; } + + public double Balance { get; set; } = 0.00; + + public DateTime Created { get; set; } = DateTime.UtcNow; + + [BsonRepresentation(BsonType.ObjectId)] + public List? TransactionIds { get; set; } + + [BsonRepresentation(BsonType.ObjectId)] + public List? TagIds { get; set; } + + [BsonRepresentation(BsonType.ObjectId)] + public string? UserId { get; set; } +}