From d681cfcb7ab13bf3e8055ec69c9c1f9361c36023 Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:32:33 +0200
Subject: [PATCH 1/8] try to correlate with Group MS feature branch
---
.github/workflows/user-ms-workflow.yaml | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index 7f2ae48..212c634 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -14,16 +14,11 @@ on:
PACT_BROKER_PASSWORD:
required: true
workflow_dispatch:
-
-# inputs:
-# consumer:
-# required: true
-# consumerVersion:
-# required: true
-# consumerVersionTags:
-# required: false
-# pactUrl:
-# required: true
+ inputs:
+ group-ms-branch:
+ description: 'Branch name in Group Microservice'
+ required: true
+ default: 'main'
jobs:
check-openapi-schema:
@@ -43,10 +38,17 @@ jobs:
name: Verify consumer contract
needs: check-openapi-schema
steps:
+ - name: Extract Group MS branch from PR description
+ id: extract-branch
+ run: |
+ echo "PR_BODY=${{ github.event.pull_request.body }}" >> $GITHUB_ENV
+ GROUP_MS_BRANCH=$(echo "${{ github.event.pull_request.body }}" | grep -oP '(?<=GroupMS: )[^\s]+')
+ echo "group-ms-branch=${GROUP_MS_BRANCH:-main}" >> $GITHUB_ENV
+
- name: Verify consumer contract
uses: ./.github/actions/verify-pact-contract
with:
pact_broker: ${{ secrets.PACT_BROKER }}
pact_broker_username: ${{ secrets.PACT_BROKER_USERNAME }}
pact_broker_password: ${{ secrets.PACT_BROKER_PASSWORD }}
-
\ No newline at end of file
+ consumer_tags: ${{ env.group-ms-branch || inputs.group-ms-branch }}
From 1af301fb62b05dcf0bf73ca49d335454b7e68b4f Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:36:08 +0200
Subject: [PATCH 2/8] skip extracting group ms branch if not a pr
---
.github/workflows/user-ms-workflow.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index 212c634..49f753c 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -39,6 +39,7 @@ jobs:
needs: check-openapi-schema
steps:
- name: Extract Group MS branch from PR description
+ if: ${{ github.event_name == 'pull_request' }}
id: extract-branch
run: |
echo "PR_BODY=${{ github.event.pull_request.body }}" >> $GITHUB_ENV
From cde1b7d9f4410fc1862dbf4acf48d72695eb7325 Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:39:48 +0200
Subject: [PATCH 3/8] explicit code checkout
---
Docs/workflow-diagram.drawio | 155 +++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
create mode 100644 Docs/workflow-diagram.drawio
diff --git a/Docs/workflow-diagram.drawio b/Docs/workflow-diagram.drawio
new file mode 100644
index 0000000..890c340
--- /dev/null
+++ b/Docs/workflow-diagram.drawio
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 8f4001be38f5456b5436bca53e654b2ecda1c0b5 Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:40:29 +0200
Subject: [PATCH 4/8] oops wrong files committed
---
.github/workflows/user-ms-workflow.yaml | 3 +
Docs/check-schema-diagram.drawio | 73 +++++++++++++++++++++++++
2 files changed, 76 insertions(+)
create mode 100644 Docs/check-schema-diagram.drawio
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index 49f753c..1e32123 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -38,6 +38,9 @@ jobs:
name: Verify consumer contract
needs: check-openapi-schema
steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
- name: Extract Group MS branch from PR description
if: ${{ github.event_name == 'pull_request' }}
id: extract-branch
diff --git a/Docs/check-schema-diagram.drawio b/Docs/check-schema-diagram.drawio
new file mode 100644
index 0000000..54f14aa
--- /dev/null
+++ b/Docs/check-schema-diagram.drawio
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 063b53770f5c2981ee7ea24d92c1b27995644b17 Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:43:32 +0200
Subject: [PATCH 5/8] .
---
.github/workflows/group-ms-workflow.yaml | 2 ++
.github/workflows/user-ms-workflow.yaml | 2 ++
UserMicroservice/Presentation/Apis/UserApi.cs | 2 +-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/group-ms-workflow.yaml b/.github/workflows/group-ms-workflow.yaml
index ab61520..68fde6f 100644
--- a/.github/workflows/group-ms-workflow.yaml
+++ b/.github/workflows/group-ms-workflow.yaml
@@ -5,6 +5,8 @@ on:
paths:
- 'GroupMicroservice/**'
- 'GroupMicroservice.Tests/**'
+ - '.github/workflows/**'
+ - '.github/actions/**'
workflow_call:
secrets:
PACT_BROKER:
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index 1e32123..ca8b10e 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -5,6 +5,8 @@ on:
paths:
- 'UserMicroservice/**'
- 'UserMicroservice.Tests/**'
+ - '.github/workflows/**'
+ - '.github/actions/**'
workflow_call:
secrets:
PACT_BROKER:
diff --git a/UserMicroservice/Presentation/Apis/UserApi.cs b/UserMicroservice/Presentation/Apis/UserApi.cs
index 2bb0a16..f9fcfac 100644
--- a/UserMicroservice/Presentation/Apis/UserApi.cs
+++ b/UserMicroservice/Presentation/Apis/UserApi.cs
@@ -25,7 +25,7 @@ public static RouteGroupBuilder AddUserApi(this IEndpointRouteBuilder app)
api.MapGet("/{userId:guid}", GetUserByIdAsync)
.WithName("GetUserById");
-
+
return api;
}
From d0abc75b59f97e88eb76e468633d982b0e63aa0b Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:44:32 +0200
Subject: [PATCH 6/8] .
---
.github/workflows/group-ms-workflow.yaml | 5 +++--
.github/workflows/user-ms-workflow.yaml | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/group-ms-workflow.yaml b/.github/workflows/group-ms-workflow.yaml
index 68fde6f..974032f 100644
--- a/.github/workflows/group-ms-workflow.yaml
+++ b/.github/workflows/group-ms-workflow.yaml
@@ -5,8 +5,9 @@ on:
paths:
- 'GroupMicroservice/**'
- 'GroupMicroservice.Tests/**'
- - '.github/workflows/**'
- - '.github/actions/**'
+ - '.github/workflows/group-ms-workflow.yaml'
+ - '.github/actions/check-schema/**'
+ - '.github/actions/check-consumer-contract/**'
workflow_call:
secrets:
PACT_BROKER:
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index ca8b10e..b5b020e 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -5,8 +5,9 @@ on:
paths:
- 'UserMicroservice/**'
- 'UserMicroservice.Tests/**'
- - '.github/workflows/**'
- - '.github/actions/**'
+ - '.github/workflows/user-ms-workflow.yaml'
+ - '.github/actions/check-schema/**'
+ - '.github/actions/verify-pact-contract/**'
workflow_call:
secrets:
PACT_BROKER:
From 2be332f388add57ad41abb39b2e66780ed5d964b Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 14:45:54 +0200
Subject: [PATCH 7/8] update composite action with correct syntax
---
.github/actions/verify-pact-contract/action.yaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/actions/verify-pact-contract/action.yaml b/.github/actions/verify-pact-contract/action.yaml
index de66113..8ad264a 100644
--- a/.github/actions/verify-pact-contract/action.yaml
+++ b/.github/actions/verify-pact-contract/action.yaml
@@ -10,7 +10,7 @@ inputs:
consumer_tags:
required: false
-verify-contract:
+runs:
using: "composite"
steps:
- name: Checkout code
@@ -22,6 +22,7 @@ verify-contract:
dotnet-version: '9.0.x'
- name: Verify consumer contract against provider
+ shell: bash
run: |
echo "Verifying pact..."
cd UserMicroservice.Tests
From e0f950c0fb65fb9f00ead24a5ea543d2418dc3c6 Mon Sep 17 00:00:00 2001
From: Julia Ilasova <1julka1il@gmail.com>
Date: Sat, 17 May 2025 15:37:49 +0200
Subject: [PATCH 8/8] add batch user retrieval functionality
---
.github/workflows/user-ms-workflow.yaml | 1 +
.../Setup/MockUserRepository.cs | 6 ++
.../Setup/ProviderStateMiddleware.cs | 71 ++++++++++++++-----
UserMicroservice/Application/IUserService.cs | 1 +
UserMicroservice/Application/UserService.cs | 11 +++
.../Infrastructure/IUserRepository.cs | 1 +
.../Infrastructure/UserRepository.cs | 7 ++
UserMicroservice/Presentation/Apis/UserApi.cs | 11 +++
UserMicroservice/openapi-schema.json | 37 ++++++++++
9 files changed, 127 insertions(+), 19 deletions(-)
diff --git a/.github/workflows/user-ms-workflow.yaml b/.github/workflows/user-ms-workflow.yaml
index b5b020e..28565aa 100644
--- a/.github/workflows/user-ms-workflow.yaml
+++ b/.github/workflows/user-ms-workflow.yaml
@@ -51,6 +51,7 @@ jobs:
echo "PR_BODY=${{ github.event.pull_request.body }}" >> $GITHUB_ENV
GROUP_MS_BRANCH=$(echo "${{ github.event.pull_request.body }}" | grep -oP '(?<=GroupMS: )[^\s]+')
echo "group-ms-branch=${GROUP_MS_BRANCH:-main}" >> $GITHUB_ENV
+ echo "The branch name in Group Microservice is: $GROUP_MS_BRANCH"
- name: Verify consumer contract
uses: ./.github/actions/verify-pact-contract
diff --git a/UserMicroservice.Tests/Setup/MockUserRepository.cs b/UserMicroservice.Tests/Setup/MockUserRepository.cs
index f6cbd41..18ca4a7 100644
--- a/UserMicroservice.Tests/Setup/MockUserRepository.cs
+++ b/UserMicroservice.Tests/Setup/MockUserRepository.cs
@@ -48,4 +48,10 @@ public Task DeleteUserAsync(UserEntity user)
}
return Task.CompletedTask;
}
+
+ public Task> GetUsersByIdsAsync(List userIds)
+ {
+ var users = _users.Where(u => userIds.Contains(u.Id)).ToList();
+ return Task.FromResult(users);
+ }
}
\ No newline at end of file
diff --git a/UserMicroservice.Tests/Setup/ProviderStateMiddleware.cs b/UserMicroservice.Tests/Setup/ProviderStateMiddleware.cs
index 6535de3..888aeb3 100644
--- a/UserMicroservice.Tests/Setup/ProviderStateMiddleware.cs
+++ b/UserMicroservice.Tests/Setup/ProviderStateMiddleware.cs
@@ -24,6 +24,7 @@ public class ProviderStateMiddleware
/// Initialises a new instance of the class.
///
/// Next request delegate
+ ///
public ProviderStateMiddleware(RequestDelegate next, IUserRepository userRepository)
{
_next = next;
@@ -31,28 +32,14 @@ public ProviderStateMiddleware(RequestDelegate next, IUserRepository userReposit
_providerStates = new Dictionary, HttpContext, Task>>
{
- ["a user with id {id} exists"] = EnsureEventExistsAsync,
- ["a user with id {id} does not exist"] = async (parameters, httpContext) =>
- {
- var id = parameters["id"].ToString();
- var user = await userRepository.GetUserByIdAsync(Guid.Parse(id));
- if (user == null)
- {
- return;
- }
-
- await userRepository.DeleteUserAsync(user);
- }
+ ["a user with id {id} exists"] = EnsureUserExistsAsync,
+ ["a user with id {id} does not exist"] = EnsureUserDoesNotExistAsync,
+ ["users with the specified IDs exist"] = EnsureValidBatchRequestAsync,
+ ["users with the specified IDs do not exist"] = EnsureInvalidBatchRequestAsync
};
}
- ///
- /// Ensure an event exists
- ///
- /// Event parameters
- ///
- /// Awaitable
- private async Task EnsureEventExistsAsync(IDictionary parameters, HttpContext httpContext)
+ private async Task EnsureUserExistsAsync(IDictionary parameters, HttpContext httpContext)
{
var id = Guid.Parse(parameters["id"].ToString());
var existingUser = await _userRepository.GetUserByIdAsync(id);
@@ -68,6 +55,52 @@ await _userRepository.CreateUserAsync(new UserEntity
});
}
}
+
+ private async Task EnsureUserDoesNotExistAsync(IDictionary parameters, HttpContext httpContext)
+ {
+ var id = Guid.Parse(parameters["id"].ToString());
+ var existingUser = await _userRepository.GetUserByIdAsync(id);
+ if (existingUser != null)
+ {
+ await _userRepository.DeleteUserAsync(existingUser);
+ }
+ }
+
+ private async Task EnsureValidBatchRequestAsync(IDictionary arg1, HttpContext arg2)
+ {
+ var userIds = arg1["ids"].ToString().Split(",");
+ foreach (var user in userIds)
+ {
+ var id = Guid.Parse(user);
+ var existingUser = await _userRepository.GetUserByIdAsync(id);
+ if (existingUser == null)
+ {
+ await _userRepository.CreateUserAsync(new UserEntity
+ {
+ Id = id,
+ Email = $"{id.ToString()}@app.com",
+ Nickname = id.ToString(),
+ CreatedAt = new DateTime(2009, 7, 27, 0, 0, 0),
+ Password = "password"
+ });
+ }
+ }
+ }
+
+ private async Task EnsureInvalidBatchRequestAsync(IDictionary arg1, HttpContext arg2)
+ {
+ var userIds = arg1["ids"].ToString().Split(",");
+
+ foreach (var user in userIds)
+ {
+ var id = Guid.Parse(user);
+ var existingUser = await _userRepository.GetUserByIdAsync(id);
+ if (existingUser != null)
+ {
+ await _userRepository.DeleteUserAsync(existingUser);
+ }
+ }
+ }
///
/// Handle the request
diff --git a/UserMicroservice/Application/IUserService.cs b/UserMicroservice/Application/IUserService.cs
index 2493c8e..e6ec2f9 100644
--- a/UserMicroservice/Application/IUserService.cs
+++ b/UserMicroservice/Application/IUserService.cs
@@ -9,4 +9,5 @@ public interface IUserService
Task CreateUserAsync(CreateUserDto user);
Task UpdateUserAsync(UpdateUserDto user);
Task DeleteUserAsync(Guid userId);
+ Task> GetUsersAsync(List userIds);
}
\ No newline at end of file
diff --git a/UserMicroservice/Application/UserService.cs b/UserMicroservice/Application/UserService.cs
index 282cfc0..495aa27 100644
--- a/UserMicroservice/Application/UserService.cs
+++ b/UserMicroservice/Application/UserService.cs
@@ -56,6 +56,17 @@ public async Task DeleteUserAsync(Guid userId)
await userRepository.DeleteUserAsync(existingUser);
}
+ public async Task> GetUsersAsync(List userIds)
+ {
+ var users = await userRepository.GetUsersByIdsAsync(userIds);
+ if (users == null || users.Count == 0)
+ {
+ throw new NotFoundException("No users found for the provided IDs.");
+ }
+
+ return users.Select(user => user.ToGetUserDto()).ToList();
+ }
+
private async Task GetUserEntityByIdAsync(Guid userId)
{
var user = await userRepository.GetUserByIdAsync(userId);
diff --git a/UserMicroservice/Infrastructure/IUserRepository.cs b/UserMicroservice/Infrastructure/IUserRepository.cs
index 49a3225..830588d 100644
--- a/UserMicroservice/Infrastructure/IUserRepository.cs
+++ b/UserMicroservice/Infrastructure/IUserRepository.cs
@@ -9,4 +9,5 @@ public interface IUserRepository
Task CreateUserAsync(UserEntity user);
Task UpdateUserAsync(UserEntity user);
Task DeleteUserAsync(UserEntity user);
+ Task> GetUsersByIdsAsync(List userIds);
}
\ No newline at end of file
diff --git a/UserMicroservice/Infrastructure/UserRepository.cs b/UserMicroservice/Infrastructure/UserRepository.cs
index cc44e8b..25b2ced 100644
--- a/UserMicroservice/Infrastructure/UserRepository.cs
+++ b/UserMicroservice/Infrastructure/UserRepository.cs
@@ -34,4 +34,11 @@ public async Task DeleteUserAsync(UserEntity user)
context.Users.Remove(user);
await context.SaveChangesAsync();
}
+
+ public async Task> GetUsersByIdsAsync(List userIds)
+ {
+ return await context.Users
+ .Where(u => userIds.Contains(u.Id))
+ .ToListAsync();
+ }
}
\ No newline at end of file
diff --git a/UserMicroservice/Presentation/Apis/UserApi.cs b/UserMicroservice/Presentation/Apis/UserApi.cs
index f9fcfac..48ff635 100644
--- a/UserMicroservice/Presentation/Apis/UserApi.cs
+++ b/UserMicroservice/Presentation/Apis/UserApi.cs
@@ -26,6 +26,9 @@ public static RouteGroupBuilder AddUserApi(this IEndpointRouteBuilder app)
api.MapGet("/{userId:guid}", GetUserByIdAsync)
.WithName("GetUserById");
+ api.MapPost("/batch", GetUsersAsync)
+ .WithName("GetUsers");
+
return api;
}
@@ -60,4 +63,12 @@ private static async Task, ProblemHttpResult>> GetUserByI
var user = await userService.GetUserByIdAsync(userId);
return TypedResults.Ok(user);
}
+
+ private static async Task>, ProblemHttpResult>> GetUsersAsync(
+ [FromBody] List userIds,
+ [FromServices] IUserService userService)
+ {
+ var users = await userService.GetUsersAsync(userIds);
+ return TypedResults.Ok(users);
+ }
}
\ No newline at end of file
diff --git a/UserMicroservice/openapi-schema.json b/UserMicroservice/openapi-schema.json
index a1ac03c..1975cfb 100644
--- a/UserMicroservice/openapi-schema.json
+++ b/UserMicroservice/openapi-schema.json
@@ -115,6 +115,43 @@
}
}
}
+ },
+ "/api/v1/user/batch": {
+ "post": {
+ "tags": [
+ "User"
+ ],
+ "operationId": "GetUsers",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "uuid"
+ }
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/GetUserDto"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
},
"components": {