From e2ad89c10da4636fa373360b4352c83e648c47a5 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 18 Apr 2026 14:15:00 -0600 Subject: [PATCH 1/2] fix postman collection --- backend/petshop-api.postman_collection.json | 559 +++++++++++++++++++- 1 file changed, 548 insertions(+), 11 deletions(-) diff --git a/backend/petshop-api.postman_collection.json b/backend/petshop-api.postman_collection.json index 37b5245f..d11713f7 100644 --- a/backend/petshop-api.postman_collection.json +++ b/backend/petshop-api.postman_collection.json @@ -203,7 +203,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"username\": \"newcustomer{{$timestamp}}\",\n \"password\": \"password123\",\n \"email\": \"new{{$timestamp}}@example.com\",\n \"phone\": \"+1-555-01{{$randomInt}}\",\n \"fullName\": \"New Customer\"\n}" + "raw": "{\n \"username\": \"newcustomer{{$timestamp}}\",\n \"password\": \"password123\",\n \"email\": \"new{{$timestamp}}@example.com\",\n \"phone\": \"+1-555-01{{$randomInt}}\",\n \"firstName\": \"New\",\n \"lastName\": \"Customer\"\n}" } }, "event": [ @@ -248,8 +248,6 @@ " pm.response.to.have.status(200);", "});", "var jsonData = pm.response.json();", - "if (jsonData.id !== undefined) pm.collectionVariables.set('userId', jsonData.id);", - "if (jsonData.id !== undefined) pm.collectionVariables.set('customerId', jsonData.id);", "if (jsonData.token) pm.collectionVariables.set('customerToken', jsonData.token);" ] } @@ -583,6 +581,132 @@ } } ] + }, + { + "name": "Forgot Password", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/auth/forgot-password", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"usernameOrEmail\": \"admin\"\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Reset Password", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/auth/reset-password", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"token\": \"{{resetToken}}\",\n \"newPassword\": \"newpassword123\"\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Admin Upload User Avatar", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/users/{{userId}}/avatar", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{adminToken}}" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "avatar", + "type": "file", + "src": "{{avatarFile}}" + } + ] + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Admin Delete User Avatar", + "request": { + "method": "DELETE", + "url": "{{baseUrl}}/api/v1/users/{{userId}}/avatar", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{adminToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] } ] }, @@ -1117,13 +1241,35 @@ " pm.response.to.have.status(200);", "});", "var jsonData = pm.response.json();", - "var items = jsonData.items || [];", - "var productId = Number(pm.collectionVariables.get('productId'));", - "var cartItem = items.find(function (item) { return item.prodId === productId; }) || items[0];", - "pm.test('cart item is returned', function () {", - " pm.expect(cartItem).to.exist;", - "});", - "if (cartItem && cartItem.cartItemId !== undefined) pm.collectionVariables.set('cartItemId', cartItem.cartItemId);" + "pm.test('pet response returned', function () {", + " pm.expect(jsonData.petId).to.exist;", + "});" + ] + } + } + ] + }, + { + "name": "Dropdown: Pet Breeds", + "request": { + "method": "GET", + "url": "{{baseUrl}}/api/v1/dropdowns/pet-breeds?species=Dog", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" ] } } @@ -1756,6 +1902,36 @@ } } ] + }, + { + "name": "Get My Orders", + "request": { + "method": "GET", + "url": "{{baseUrl}}/api/v1/sales/my?page=0&size=10", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] } ] }, @@ -2119,6 +2295,96 @@ } } ] + }, + { + "name": "Apply Loyalty Points", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/cart/apply-points?storeId={{storeId}}&useLoyaltyPoints=true", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Remove Coupon", + "request": { + "method": "DELETE", + "url": "{{baseUrl}}/api/v1/cart/coupon?storeId={{storeId}}", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Cancel Checkout", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/cart/checkout/cancel?storeId={{storeId}}", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 204', function () {", + " pm.response.to.have.status(204);", + "});" + ] + } + } + ] } ] }, @@ -3305,6 +3571,66 @@ } } ] + }, + { + "name": "Cancel Appointment", + "request": { + "method": "PATCH", + "url": "{{baseUrl}}/api/v1/appointments/{{appointmentId}}/cancel", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + }, + { + "name": "Get Customer Pets Dropdown", + "request": { + "method": "GET", + "url": "{{baseUrl}}/api/v1/dropdowns/customers/{{customerId}}/pets", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{adminToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] } ] }, @@ -3553,6 +3879,70 @@ } } ] + }, + { + "name": "Request Adoption", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/adoptions/request", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"petId\": 1,\n \"adoptionDate\": \"2026-05-01\"\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 201', function () {", + " pm.response.to.have.status(201);", + "});" + ] + } + } + ] + }, + { + "name": "Cancel Adoption", + "request": { + "method": "PATCH", + "url": "{{baseUrl}}/api/v1/adoptions/{{adoptionId}}/cancel", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] } ] }, @@ -4733,6 +5123,40 @@ } } ] + }, + { + "name": "Bulk Delete Customers", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/customers/bulk-delete", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{adminToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"ids\": [\n 0\n ]\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 204', function () {", + " pm.response.to.have.status(204);", + "});" + ] + } + } + ] } ] }, @@ -6770,6 +7194,119 @@ ] } ] + }, + { + "name": "Activity Logs", + "item": [ + { + "name": "Get Activity Logs", + "request": { + "method": "GET", + "url": "{{baseUrl}}/api/v1/activity-logs?limit=50", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{adminToken}}" + } + ] + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + } + ] + }, + { + "name": "Contact", + "item": [ + { + "name": "Send Contact Message", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/contact", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"subject\": \"Question about adoption\",\n \"body\": \"I would like to know more about the adoption process.\"\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + } + ] + }, + { + "name": "AI Chat", + "item": [ + { + "name": "Send AI Chat Message", + "request": { + "method": "POST", + "url": "{{baseUrl}}/api/v1/ai-chat/message", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{customerToken}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"message\": \"What services do you offer?\",\n \"history\": []\n}" + } + }, + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test('Status code is 200', function () {", + " pm.response.to.have.status(200);", + "});" + ] + } + } + ] + } + ] } ] -} +} \ No newline at end of file -- 2.49.1 From 1b5bd6825a55a298cc419fb46d02b1d9a5f862a0 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 18 Apr 2026 15:45:00 -0600 Subject: [PATCH 2/2] fix cross-client consistency --- .../java/com/example/petstoremobile/api/CouponApi.java | 7 +++++-- .../example/petstoremobile/dtos/BulkDeleteRequest.java | 8 ++++---- .../petstoremobile/repositories/CouponRepository.java | 3 ++- .../petstoremobile/viewmodels/AdoptionListViewModel.java | 3 ++- .../viewmodels/AppointmentListViewModel.java | 3 ++- .../petstoremobile/viewmodels/InventoryListViewModel.java | 3 ++- .../petstoremobile/viewmodels/PetListViewModel.java | 3 ++- .../viewmodels/ProductSupplierListViewModel.java | 3 ++- .../petstoremobile/viewmodels/ServiceListViewModel.java | 3 ++- .../petstoremobile/viewmodels/SupplierListViewModel.java | 3 ++- .../org/example/petshopdesktop/api/endpoints/AuthApi.java | 7 +++++++ 11 files changed, 32 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/example/petstoremobile/api/CouponApi.java b/android/app/src/main/java/com/example/petstoremobile/api/CouponApi.java index ca12cf48..9ed038c0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/CouponApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/CouponApi.java @@ -6,9 +6,12 @@ import com.example.petstoremobile.dtos.PageResponse; import java.util.List; import retrofit2.Call; +import com.example.petstoremobile.dtos.BulkDeleteRequest; + import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.GET; +import retrofit2.http.HTTP; import retrofit2.http.POST; import retrofit2.http.PUT; import retrofit2.http.Path; @@ -39,6 +42,6 @@ public interface CouponApi { @DELETE("api/v1/coupons/{id}") Call deleteCoupon(@Path("id") Long id); - @DELETE("api/v1/coupons") - Call bulkDeleteCoupons(@Query("ids") List ids); + @HTTP(method = "DELETE", path = "api/v1/coupons", hasBody = true) + Call bulkDeleteCoupons(@Body BulkDeleteRequest request); } diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java b/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java index e53c8369..49f92f06 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java @@ -3,20 +3,20 @@ package com.example.petstoremobile.dtos; import java.util.List; public class BulkDeleteRequest { - private List ids; + private List ids; public BulkDeleteRequest() { } - public BulkDeleteRequest(List ids) { + public BulkDeleteRequest(List ids) { this.ids = ids; } - public List getIds() { + public List getIds() { return ids; } - public void setIds(List ids) { + public void setIds(List ids) { this.ids = ids; } } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java index f97d1ca0..68bdd9c7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java @@ -3,6 +3,7 @@ package com.example.petstoremobile.repositories; import androidx.lifecycle.LiveData; import com.example.petstoremobile.api.CouponApi; +import com.example.petstoremobile.dtos.BulkDeleteRequest; import com.example.petstoremobile.dtos.CouponDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; @@ -47,6 +48,6 @@ public class CouponRepository extends BaseRepository { } public LiveData> bulkDeleteCoupons(List ids) { - return executeCall(couponApi.bulkDeleteCoupons(ids)); + return executeCall(couponApi.bulkDeleteCoupons(new BulkDeleteRequest(ids))); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java index 005198d1..c9b1c91a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java @@ -94,6 +94,7 @@ public class AdoptionListViewModel extends ViewModel { } public LiveData> bulkDeleteAdoptions(List ids) { - return adoptionRepository.bulkDeleteAdoptions(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return adoptionRepository.bulkDeleteAdoptions(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java index 19924349..60ba239d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java @@ -92,6 +92,7 @@ public class AppointmentListViewModel extends ViewModel { } public LiveData> bulkDeleteAppointments(List ids) { - return appointmentRepository.bulkDeleteAppointments(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return appointmentRepository.bulkDeleteAppointments(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java index 66387983..1c53d2cb 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java @@ -90,6 +90,7 @@ public class InventoryListViewModel extends ViewModel { } public LiveData> bulkDeleteInventory(List ids) { - return inventoryRepository.bulkDeleteInventory(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return inventoryRepository.bulkDeleteInventory(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java index 89f56d51..b4e33277 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java @@ -113,6 +113,7 @@ public class PetListViewModel extends ViewModel { } public LiveData> bulkDeletePets(List ids) { - return petRepository.bulkDeletePets(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return petRepository.bulkDeletePets(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java index 930770a4..05b4a2d9 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java @@ -104,6 +104,7 @@ public class ProductSupplierListViewModel extends ViewModel { } public LiveData> bulkDeleteProductSuppliers(List ids) { - return psRepository.bulkDeleteProductSuppliers(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return psRepository.bulkDeleteProductSuppliers(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java index bbdbe270..bdd9a4de 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java @@ -77,6 +77,7 @@ public class ServiceListViewModel extends ViewModel { } public LiveData> bulkDeleteServices(List ids) { - return repository.bulkDeleteServices(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return repository.bulkDeleteServices(new BulkDeleteRequest(longIds)); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java index 33373e90..15d1ca98 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java @@ -78,6 +78,7 @@ public class SupplierListViewModel extends ViewModel { } public LiveData> bulkDeleteSuppliers(List ids) { - return repository.bulkDeleteSuppliers(new BulkDeleteRequest(ids)); + List longIds = ids.stream().map(Long::valueOf).collect(java.util.stream.Collectors.toList()); + return repository.bulkDeleteSuppliers(new BulkDeleteRequest(longIds)); } } diff --git a/desktop/src/main/java/org/example/petshopdesktop/api/endpoints/AuthApi.java b/desktop/src/main/java/org/example/petshopdesktop/api/endpoints/AuthApi.java index 2a8c3417..e45ead94 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/api/endpoints/AuthApi.java +++ b/desktop/src/main/java/org/example/petshopdesktop/api/endpoints/AuthApi.java @@ -41,4 +41,11 @@ public class AuthApi { body.put("usernameOrEmail", usernameOrEmail); apiClient.post("/api/v1/auth/forgot-password", body, Object.class); } + + public void resetPassword(String token, String newPassword) throws Exception { + Map body = new HashMap<>(); + body.put("token", token); + body.put("newPassword", newPassword); + apiClient.post("/api/v1/auth/reset-password", body, Object.class); + } } -- 2.49.1