From 2d6bdcd62110c521cbc36661088e0315a9583feb Mon Sep 17 00:00:00 2001 From: effileo Date: Thu, 5 Mar 2026 21:00:02 +0300 Subject: [PATCH 1/5] Task 5 Complete: API connected to MongoDB and verified with Postman --- .gitignore | 3 + CommBank-Server/CommBank.csproj | 4 +- CommBank-Server/Models/Goal.cs | 4 +- CommBank-Server/Program.cs | 26 ++- CommBank-Server/Secrets.json | 6 +- CommBank-Server/Services/AccountService.cs | 10 +- CommBank-Server/appsettings.Development.json | 8 + POSTMAN_TESTING.md | 181 +++++++++++++++++++ 8 files changed, 232 insertions(+), 10 deletions(-) create mode 100644 POSTMAN_TESTING.md diff --git a/.gitignore b/.gitignore index 6769715..2f13dfa 100644 --- a/.gitignore +++ b/.gitignore @@ -282,6 +282,9 @@ _pkginfo.txt # but keep track of directories ending in .cache !*.[Cc]ache/ +# Secrets (connection strings, API keys) +**/Secrets.json + # Others ClientBin/ ~$* diff --git a/CommBank-Server/CommBank.csproj b/CommBank-Server/CommBank.csproj index 983cc88..b57f2c4 100644 --- a/CommBank-Server/CommBank.csproj +++ b/CommBank-Server/CommBank.csproj @@ -1,7 +1,7 @@ - net6.0 + net9.0 enable enable CommBank_Server @@ -13,7 +13,7 @@ - + diff --git a/CommBank-Server/Models/Goal.cs b/CommBank-Server/Models/Goal.cs index 77ff1ad..ed46440 100644 --- a/CommBank-Server/Models/Goal.cs +++ b/CommBank-Server/Models/Goal.cs @@ -1,4 +1,4 @@ -using MongoDB.Bson; +using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace CommBank.Models; @@ -11,6 +11,8 @@ public class Goal public string? Name { get; set; } + public string? Icon { get; set; } + public UInt64 TargetAmount { get; set; } = 0; public DateTime TargetDate { get; set; } diff --git a/CommBank-Server/Program.cs b/CommBank-Server/Program.cs index a88e560..8f450ff 100644 --- a/CommBank-Server/Program.cs +++ b/CommBank-Server/Program.cs @@ -1,17 +1,37 @@ -using CommBank.Models; +using System.Text.Json.Serialization; +using CommBank.Models; using CommBank.Services; using MongoDB.Driver; +// Prefer TLS 1.2 for MongoDB Atlas (helps avoid "TLS alert: InternalError" on Windows) +System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; + var builder = WebApplication.CreateBuilder(args); -builder.Services.AddControllers(); +builder.Services.AddControllers() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(System.Text.Json.JsonNamingPolicy.CamelCase, allowIntegerValues: false)); + }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json"); -var mongoClient = new MongoClient(builder.Configuration.GetConnectionString("CommBank")); +var connectionString = builder.Configuration.GetConnectionString("CommBank"); +var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); +mongoClientSettings.ServerSelectionTimeout = TimeSpan.FromSeconds(60); +// On Windows, OCSP revocation check can cause TLS "InternalError" handshake failure with Atlas +var ssl = mongoClientSettings.SslSettings ?? new SslSettings(); +ssl.CheckCertificateRevocation = false; +mongoClientSettings.SslSettings = ssl; +// Development-only: relax TLS cert validation if Windows still fails (remove in production) +if (builder.Environment.IsDevelopment()) +{ + mongoClientSettings.AllowInsecureTls = true; +} +var mongoClient = new MongoClient(mongoClientSettings); var mongoDatabase = mongoClient.GetDatabase("CommBank"); IAccountsService accountsService = new AccountsService(mongoDatabase); diff --git a/CommBank-Server/Secrets.json b/CommBank-Server/Secrets.json index 0e5bf94..699ad0b 100644 --- a/CommBank-Server/Secrets.json +++ b/CommBank-Server/Secrets.json @@ -1,5 +1,5 @@ -{ +{ "ConnectionStrings": { - "CommBank": "{CONNECTION_STRING}" + "CommBank": "mongodb+srv://aorta_db:aorta@aorta.boe9w7l.mongodb.net/?appName=Aorta" } -} \ No newline at end of file +} diff --git a/CommBank-Server/Services/AccountService.cs b/CommBank-Server/Services/AccountService.cs index 52d1cb9..28f9615 100644 --- a/CommBank-Server/Services/AccountService.cs +++ b/CommBank-Server/Services/AccountService.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Options; using CommBank.Models; using MongoDB.Driver; +using MongoDB.Bson; namespace CommBank.Services; @@ -19,8 +20,15 @@ public async Task> GetAsync() => public async Task GetAsync(string id) => await _accountsCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); - public async Task CreateAsync(Account newAccount) => + public async Task CreateAsync(Account newAccount) + { + if (string.IsNullOrWhiteSpace(newAccount.Id) || !ObjectId.TryParse(newAccount.Id, out _)) + { + newAccount.Id = ObjectId.GenerateNewId().ToString(); + } + await _accountsCollection.InsertOneAsync(newAccount); + } public async Task UpdateAsync(string id, Account updatedAccount) => await _accountsCollection.ReplaceOneAsync(x => x.Id == id, updatedAccount); diff --git a/CommBank-Server/appsettings.Development.json b/CommBank-Server/appsettings.Development.json index ce16a2e..25fc0c3 100644 --- a/CommBank-Server/appsettings.Development.json +++ b/CommBank-Server/appsettings.Development.json @@ -4,6 +4,14 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } + }, + "ConnectionStrings": { + "DefaultConnection": "mongodb+srv://fitaalemayehu12_db_user:4UViJN00WpXWqe1E@aorta.boe9w7l.mongodb.net/?appName=Aorta" + }, + "MongoDbSettings": { + "ConnectionString": "mongodb+srv://fitaalemayehu12_db_user:4UViJN00WpXWqe1E@aorta.boe9w7l.mongodb.net/?appName=Aorta", + "DatabaseName": "commbank" } } + diff --git a/POSTMAN_TESTING.md b/POSTMAN_TESTING.md new file mode 100644 index 0000000..4feff1b --- /dev/null +++ b/POSTMAN_TESTING.md @@ -0,0 +1,181 @@ +# Testing the CommBank API with Postman + +## 1. Start the server + +From the repo root: + +```bash +cd CommBank-Server +dotnet run +``` + +Or run from Visual Studio / Rider. The API will listen on **http://localhost:5203** (or http://localhost:11366 — check the console for the port). + +Use this as your **Base URL** in Postman: `http://localhost:5203` (replace with your actual port if different). + +--- + +## 2. Set up Postman + +- **Headers:** For POST/PUT, set `Content-Type: application/json` (Postman usually does this when you pick "raw" + "JSON"). +- **Body:** For POST/PUT, choose **Body** → **raw** → **JSON**. + +--- + +## 3. Test the main endpoints + +### Health check (optional) + +- **GET** `http://localhost:5203/swagger/index.html` + Opens Swagger UI in the browser so you can see all endpoints. + +--- + +### Accounts + +| Method | URL | Body (for POST/PUT) | +|--------|-----|----------------------| +| GET all | `http://localhost:5203/api/Account` | — | +| GET one | `http://localhost:5203/api/Account/{id}` | — | +| POST | `http://localhost:5203/api/Account` | See below | +| PUT | `http://localhost:5203/api/Account/{id}` | Same shape as POST | +| DELETE | `http://localhost:5203/api/Account/{id}` | — | + +**Example POST body (create account):** +```json +{ + "name": "My Savings", + "number": 12345678, + "balance": 0, + "accountType": "goalSaver" +} +``` +Use `"accountType": "goalSaver"` or `"netBankSaver"`. For GET one / PUT / DELETE, `{id}` must be a 24-character MongoDB ObjectId (e.g. from a previous GET or POST response). + +--- + +### Users + +| Method | URL | Body | +|--------|-----|------| +| GET all | `http://localhost:5203/api/User` | — | +| GET one | `http://localhost:5203/api/User/{id}` | — | +| POST | `http://localhost:5203/api/User` | See below | +| PUT | `http://localhost:5203/api/User/{id}` | Same shape | +| DELETE | `http://localhost:5203/api/User/{id}` | — | + +**Example POST body (create user — password is hashed by the server):** +```json +{ + "name": "Test User", + "email": "test@example.com", + "password": "secret123", + "accountIds": [], + "goalIds": [], + "transactionIds": [] +} +``` + +--- + +### Auth (login) + +- **POST** `http://localhost:5203/api/Auth/Login` + +**Body:** +```json +{ + "email": "test@example.com", + "password": "secret123" +} +``` +- Success: **204 No Content**. +- Wrong email/password: **404 Not Found**. + +--- + +### Goals + +| Method | URL | Body | +|--------|-----|------| +| GET all | `http://localhost:5203/api/Goal` | — | +| GET one | `http://localhost:5203/api/Goal/{id}` | — | +| GET by user | `http://localhost:5203/api/Goal/User/{userId}` | — | +| POST | `http://localhost:5203/api/Goal` | See below | +| PUT | `http://localhost:5203/api/Goal/{id}` | Same shape | +| DELETE | `http://localhost:5203/api/Goal/{id}` | — | + +**Example POST body:** +```json +{ + "name": "Holiday Fund", + "icon": "plane", + "targetAmount": 5000, + "targetDate": "2026-12-31T00:00:00Z", + "balance": 0, + "userId": "PUT_A_USER_OBJECT_ID_HERE" +} +``` +`icon` is optional. Get a real `userId` from GET `/api/User`. + +--- + +### Transactions + +| Method | URL | Body | +|--------|-----|------| +| GET all | `http://localhost:5203/api/Transaction` | — | +| GET one | `http://localhost:5203/api/Transaction/{id}` | — | +| GET by user | `http://localhost:5203/api/Transaction/User/{userId}` | — | +| POST | `http://localhost:5203/api/Transaction` | See below | +| PUT | `http://localhost:5203/api/Transaction/{id}` | Same shape | +| DELETE | `http://localhost:5203/api/Transaction/{id}` | — | + +**Example POST body:** +```json +{ + "transactionType": "credit", + "amount": 100.50, + "dateTime": "2026-03-05T12:00:00Z", + "description": "Salary", + "userId": "PUT_A_USER_OBJECT_ID_HERE" +} +``` +Use `transactionType`: `"credit"`, `"debit"`, or `"transfer"`. `goalId` and `tagIds` are optional. + +--- + +### Tags + +| Method | URL | Body | +|--------|-----|------| +| GET all | `http://localhost:5203/api/Tag` | — | +| GET one | `http://localhost:5203/api/Tag/{id}` | — | +| POST | `http://localhost:5203/api/Tag` | `{ "name": "Groceries" }` | +| PUT | `http://localhost:5203/api/Tag/{id}` | `{ "name": "Food" }` | +| DELETE | `http://localhost:5203/api/Tag/{id}` | — | + +--- + +## 4. Suggested test order + +1. **GET** `/api/Account` and `/api/User` — see if the server and DB connection work (empty arrays `[]` is OK). +2. **POST** `/api/User` — create a user; copy the returned `id`. +3. **POST** `/api/Auth/Login` — login with that user’s email/password (expect 204). +4. **POST** `/api/Account` — create an account (use `"accountType": "goalSaver"` or `"netBankSaver"`). +5. **POST** `/api/Goal` — create a goal with the user’s `userId`; optionally include `"icon": "plane"`. +6. **GET** `/api/Goal` or `/api/Goal/User/{userId}` — confirm the goal (and optional `icon`) is returned. +7. **POST** `/api/Transaction` and **POST** `/api/Tag` — then GET to verify. + +--- + +## 5. What to expect + +- **GET (list):** `200` with a JSON array (possibly empty `[]`). +- **GET (one):** `200` with one object, or `404` if id not found. +- **POST:** `201 Created` with the created resource (including generated `id`) in the response. +- **PUT:** `204 No Content` on success, `404` if id not found. +- **DELETE:** `204 No Content` on success, `404` if id not found. +- **Login:** `204` on success, `404` if email/password wrong. + +If you get **400**, check the request body (valid JSON, correct field names like `accountType`, `transactionType`, and allowed enum values). If you get **500**, check the server console and that MongoDB is reachable (e.g. connection string and Atlas network access). From 8af79887931523781be3f2b062d5dc10d0d0b92f Mon Sep 17 00:00:00 2001 From: effileo Date: Thu, 5 Mar 2026 21:07:38 +0300 Subject: [PATCH 2/5] Security: Remove sensitive connection string --- CommBank-Server/appsettings.Development.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CommBank-Server/appsettings.Development.json b/CommBank-Server/appsettings.Development.json index 25fc0c3..8e38b41 100644 --- a/CommBank-Server/appsettings.Development.json +++ b/CommBank-Server/appsettings.Development.json @@ -6,10 +6,10 @@ } }, "ConnectionStrings": { - "DefaultConnection": "mongodb+srv://fitaalemayehu12_db_user:4UViJN00WpXWqe1E@aorta.boe9w7l.mongodb.net/?appName=Aorta" - }, + "CommBank": "YOUR_CONNECTION_STRING_HERE" +}, "MongoDbSettings": { - "ConnectionString": "mongodb+srv://fitaalemayehu12_db_user:4UViJN00WpXWqe1E@aorta.boe9w7l.mongodb.net/?appName=Aorta", + "ConnectionString": "YOUR_CONNECTION_STRING_HERE", "DatabaseName": "commbank" } } From 29fbc9e212e51bd198669bb18e7535026e61a2fb Mon Sep 17 00:00:00 2001 From: effileo Date: Thu, 5 Mar 2026 21:31:47 +0300 Subject: [PATCH 3/5] Final: Added Icon field to Goal model and verified with Postman --- CommBank-Server/Secrets.json | 5 ----- CommBank-Server/Secrets.json.example | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 CommBank-Server/Secrets.json create mode 100644 CommBank-Server/Secrets.json.example diff --git a/CommBank-Server/Secrets.json b/CommBank-Server/Secrets.json deleted file mode 100644 index 699ad0b..0000000 --- a/CommBank-Server/Secrets.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "CommBank": "mongodb+srv://aorta_db:aorta@aorta.boe9w7l.mongodb.net/?appName=Aorta" - } -} diff --git a/CommBank-Server/Secrets.json.example b/CommBank-Server/Secrets.json.example new file mode 100644 index 0000000..c10b90b --- /dev/null +++ b/CommBank-Server/Secrets.json.example @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "CommBank": "mongodb+srv://:@.mongodb.net/?appName=YourApp" + } +} From d029c1e292c181fcc585e46277fe6d5766308e4c Mon Sep 17 00:00:00 2001 From: effileo Date: Thu, 5 Mar 2026 22:23:48 +0300 Subject: [PATCH 4/5] some files update with README.md and response --- README.md | 1 + expected_response.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 README.md create mode 100644 expected_response.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..13c6c1a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Completed all tasks including MongoDB integration and Goal Model modification. diff --git a/expected_response.md b/expected_response.md new file mode 100644 index 0000000..260ab01 --- /dev/null +++ b/expected_response.md @@ -0,0 +1,18 @@ +# Expected Response + +Example response from **GET /api/Goal** after completing MongoDB integration and adding the optional `icon` field to the Goal model (real data from this project): + +```json +{ + "id": "69a9cb57f72212af18e0c289", + "name": "Buy a Car", + "icon": "car-emoji", + "targetAmount": 20000, + "targetDate": "2026-12-31T00:00:00Z", + "balance": 500, + "created": "2026-03-05T21:28:39.0119093+03:00", + "transactionIds": null, + "tagIds": null, + "userId": null +} +``` From d79388727e77e5272198bb0b7518a0aa2cce7257 Mon Sep 17 00:00:00 2001 From: effileo Date: Tue, 10 Mar 2026 19:10:01 +0300 Subject: [PATCH 5/5] Goals: PUT preserves UserId/Icon, GetForUser test, tests target net9.0 Made-with: Cursor --- CommBank-Server/Controllers/GoalController.cs | 3 ++- CommBank-Server/Program.cs | 3 ++- CommBank-Server/appsettings.Development.json | 8 +++---- CommBank.Tests/CommBank.Tests.csproj | 2 +- CommBank.Tests/GoalControllerTests.cs | 24 ++++++++++++++++--- README.md | 17 +++++++++++++ 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/CommBank-Server/Controllers/GoalController.cs b/CommBank-Server/Controllers/GoalController.cs index 98271a5..d014799 100644 --- a/CommBank-Server/Controllers/GoalController.cs +++ b/CommBank-Server/Controllers/GoalController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using CommBank.Services; using CommBank.Models; @@ -79,6 +79,7 @@ public async Task Update(string id, Goal updatedGoal) } updatedGoal.Id = goal.Id; + updatedGoal.UserId = goal.UserId ?? updatedGoal.UserId; await _goalsService.UpdateAsync(id, updatedGoal); diff --git a/CommBank-Server/Program.cs b/CommBank-Server/Program.cs index 8f450ff..8e2d53f 100644 --- a/CommBank-Server/Program.cs +++ b/CommBank-Server/Program.cs @@ -17,7 +17,8 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); -builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("Secrets.json"); +builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("Secrets.json", optional: true); var connectionString = builder.Configuration.GetConnectionString("CommBank"); var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString); diff --git a/CommBank-Server/appsettings.Development.json b/CommBank-Server/appsettings.Development.json index 8e38b41..5509279 100644 --- a/CommBank-Server/appsettings.Development.json +++ b/CommBank-Server/appsettings.Development.json @@ -1,4 +1,4 @@ -{ +{ "Logging": { "LogLevel": { "Default": "Information", @@ -6,10 +6,10 @@ } }, "ConnectionStrings": { - "CommBank": "YOUR_CONNECTION_STRING_HERE" -}, + "CommBank": "mongodb+srv://YOUR_DB_USERNAME:YOUR_DB_PASSWORD@aorta.boe9w7l.mongodb.net/?appName=Aorta" + }, "MongoDbSettings": { - "ConnectionString": "YOUR_CONNECTION_STRING_HERE", + "ConnectionString": "mongodb+srv://YOUR_DB_USERNAME:YOUR_DB_PASSWORD@aorta.boe9w7l.mongodb.net/?appName=Aorta", "DatabaseName": "commbank" } } diff --git a/CommBank.Tests/CommBank.Tests.csproj b/CommBank.Tests/CommBank.Tests.csproj index 4d9413f..95c6765 100644 --- a/CommBank.Tests/CommBank.Tests.csproj +++ b/CommBank.Tests/CommBank.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net9.0 enable enable diff --git a/CommBank.Tests/GoalControllerTests.cs b/CommBank.Tests/GoalControllerTests.cs index 8380181..c5df1e4 100644 --- a/CommBank.Tests/GoalControllerTests.cs +++ b/CommBank.Tests/GoalControllerTests.cs @@ -1,4 +1,4 @@ -using CommBank.Controllers; +using CommBank.Controllers; using CommBank.Services; using CommBank.Models; using CommBank.Tests.Fake; @@ -66,9 +66,27 @@ public async void Get() public async void GetForUser() { // Arrange - + var goals = collections.GetGoals(); + var users = collections.GetUsers(); + var userId = users[0].Id!; + goals[0].UserId = userId; + goals[1].UserId = userId; + goals[2].UserId = userId; + 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(userId); + // Assert + Assert.NotNull(result); + foreach (Goal goal in result!) + { + Assert.IsAssignableFrom(goal); + Assert.Equal(userId, goal.UserId); + } } } \ No newline at end of file diff --git a/README.md b/README.md index 13c6c1a..9febb0d 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ Completed all tasks including MongoDB integration and Goal Model modification. + +## Running the server + +1. **Set the MongoDB connection string** (required for `dotnet run` to work): + - Open `CommBank-Server/appsettings.Development.json`. + - Replace `YOUR_CONNECTION_STRING_HERE` with your real MongoDB connection string in both `ConnectionStrings:CommBank` and `MongoDbSettings:ConnectionString`. + - Or create `CommBank-Server/Secrets.json` (same folder as `Program.cs`) with: + ```json + { + "ConnectionStrings": { + "CommBank": "mongodb+srv://user:password@cluster.xxxxx.mongodb.net/?retryWrites=true&w=majority" + } + } + ``` +2. From `CommBank-Server` run: `dotnet run`. + +**Getting a free connection string:** Sign up at [MongoDB Atlas](https://www.mongodb.com/cloud/atlas), create a free M0 cluster, add a database user, add network access (e.g. `0.0.0.0/0` for testing), then use the “Connect” → “Drivers” connection string.