-
Notifications
You must be signed in to change notification settings - Fork 30
feat: Created Badge System Database Schema #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Created Badge System Database Schema #132
Conversation
|
@SurfingBowser @0xGeorgii Please, review and give me your feedback. |
|
@0xGeorgii @SurfingBowser please review and give me your feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a badge awarding system to gamify user engagement by tracking achievements through database models, business logic services, and API endpoints. It also addresses type inconsistencies in user identification and refactors dependency injection for better scope management.
Changes:
- Database schema additions for
BadgeDefinitionModelandUserBadgeModelwith seeded badge data - Service layer implementation with
BadgeAwardServicefor reputation-based and action-specific badge awarding - API endpoints via
BadgeControllerfor retrieving user badges and badge definitions - Refactored dependency injection to use
IServiceScopeFactoryfor proper scoping in hosted services - Downgraded Swashbuckle packages and replaced deprecated security APIs
Reviewed changes
Copilot reviewed 20 out of 22 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Startup.cs | Refactored JWT configuration to use options pattern, added badge services registration, and improved dependency injection |
| SorobanSecurityPortalApi.csproj | Downgraded Swashbuckle packages and added Microsoft.OpenApi reference |
| InstanceSyncHostedService.cs | Refactored to use IServiceScopeFactory for proper dependency scope management |
| BadgeAwardService.cs | New service implementing business logic for badge awarding based on reputation and actions |
| BackgroundWorkingHostedService.cs | Refactored to use IServiceScopeFactory and improved error handling |
| ReportService.cs | Added SupportedOSPlatform attributes to platform-specific methods |
| BadgeViewModel.cs | New view model for badge data transfer |
| BadgeMappingProfile.cs | AutoMapper profile for mapping UserBadgeModel to BadgeViewModel |
| UserBadgeModel.cs | New database model for tracking user-badge associations |
| BadgeDefinitionModel.cs | New database model for badge metadata |
| DbModelSnapshot.cs | Updated EF Core snapshot with badge tables and moderation log |
| UpdateUserBadgeForeignKeys.cs | Migration to fix foreign key from string user_id to int user_profile_id |
| AddBadgeSystem.cs | Initial migration creating badge_definitions and user_badges tables |
| IBadgeProcessor.cs | Interface for badge data access operations |
| BadgeProcessor.cs | Implementation of badge CRUD operations |
| BadgeController.cs | API controller exposing badge endpoints |
| Extensions.cs | Replaced deprecated SHA256Managed with SHA256.Create() |
| ExtendedConfig.cs | Refactored to use IServiceScopeFactory for database access |
| BadgeCategory.cs | New enum defining badge categories |
| Db.cs | Added BadgeDefinitions and UserBadges DbSets with seed data |
Files not reviewed (2)
- Backend/SorobanSecurityPortalApi/Migrations/20260128231425_AddBadgeSystem.Designer.cs: Language not supported
- Backend/SorobanSecurityPortalApi/Migrations/20260129011841_UpdateUserBadgeForeignKeys.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| using (var sp = services.BuildServiceProvider()) | ||
| { | ||
| var ec = sp.GetRequiredService<ExtendedConfig>(); | ||
| var logger = sp.GetRequiredService<ILogger<Startup>>(); | ||
| services.AddHttpClients(ec, logger); | ||
| } | ||
|
|
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Building a service provider mid-configuration is an anti-pattern that can lead to incorrect dependency resolution and service lifetime issues. The built service provider here creates a separate container from the one that will be used at runtime, potentially causing configuration inconsistencies. Consider refactoring AddHttpClients to accept IServiceProvider as a parameter and call it during application startup, or defer this configuration until the Configure method where the final service provider is available.
| using (var sp = services.BuildServiceProvider()) | |
| { | |
| var ec = sp.GetRequiredService<ExtendedConfig>(); | |
| var logger = sp.GetRequiredService<ILogger<Startup>>(); | |
| services.AddHttpClients(ec, logger); | |
| } |
| <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> | ||
| <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.6.2" /> |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Swashbuckle packages are being downgraded from version 7.1.0 to 6.6.2. While this may resolve immediate issues, downgrading packages can introduce security vulnerabilities or miss important bug fixes. Consider investigating and resolving the root cause that necessitated the downgrade, or document the specific issue that requires this older version.
| <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> | |
| <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.6.2" /> | |
| <PackageReference Include="Swashbuckle.AspNetCore" Version="7.1.0" /> | |
| <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="7.1.0" /> |
| return Ok(result); | ||
| } | ||
|
|
||
| [HttpGet("test-definitions")] |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The endpoint name 'test-definitions' suggests this is a temporary testing endpoint. If this is meant for production use, rename it to simply 'definitions' or 'badge-definitions'. If it's truly for testing purposes only, it should be removed before production deployment or guarded with appropriate authorization checks.
| [HttpGet("test-definitions")] | |
| [HttpGet("definitions")] |
|
@Oluwaseyi89 can take a look at the review please |
Note changes will be effected |
|
@0xGeorgii @SurfingBowser please review my latest commit. |
|
@0xGeorgii @SurfingBowser I am awaiting your review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 22 out of 24 changed files in this pull request and generated no new comments.
Files not reviewed (2)
- Backend/SorobanSecurityPortalApi/Migrations/20260128231425_AddBadgeSystem.Designer.cs: Language not supported
- Backend/SorobanSecurityPortalApi/Migrations/20260129011841_UpdateUserBadgeForeignKeys.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@0xGeorgii any feedback on this PR? |
|
|
||
| // Seed Initial Badge Definitions for Issue #91 | ||
| builder.Entity<BadgeDefinitionModel>().HasData( | ||
| new BadgeDefinitionModel { Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), Name = "First Comment", Description = "Posted first comment", Icon = "🎉", Category = BadgeCategory.Participation, Criteria = "first_comment" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not using just int constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0xGeorgii I have refactored the Id type to use int and also all files concerned.
|
@Oluwaseyi89 please resolve merge conflicts |
|
@0xGeorgii please review. |
… int instead of Guid type for Id column
|
@Oluwaseyi89, thank you for your contribution. Since it is a big feature, can you please record a video with a demo of how it works? |
|
@Oluwaseyi89, also fix the build and add more tests, please |
|
@0xGeorgii I have refactored the test to use BadgeDefinitionModel with int type for id instead of Guid [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.0.0+e341b939fe (64-bit .NET 9.0.12)
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.0.0+e341b939fe (64-bit .NET 9.0.12)
[xUnit.net 00:00:00.20] Discovering: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.20] Discovering: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.34] Discovered: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.34] Discovered: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.42] Starting: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.42] Starting: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:01.04] Finished: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:01.04] Finished: SorobanSecurityPortalApi.Tests
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.CheckAndAwardReputationBadges_ShouldHandleInvalidCriteriaGracefully [326 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.CheckAndAward_BoundaryTests(reputation: 399, shouldAward: False) [12 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.CheckAndAward_BoundaryTests(reputation: 400, shouldAward: True) [12 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.CheckAndAward_ShouldAwardMultipleBadges_WhenUserClearsMultipleThresholds [23 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.AwardSpecificBadge_ShouldBeCaseInsensitive [7 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.CheckAndAwardReputationBadges_ShouldAward_WhenReputationThresholdMet [9 ms]
Passed SorobanSecurityPortalApi.Tests.Services.BadgeAwardServiceTests.AwardSpecificBadge_ShouldInvokeProcessor_WhenCriteriaMatches [7 ms]
Test Run Successful.
Total tests: 7
Passed: 7
Total time: 2.5446 Seconds
SorobanSecurityPortalApi.Tests test net9.0 succeeded (4.2s)
Test summary: total: 7, failed: 0, succeeded: 7, skipped: 0, duration: 4.1s[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.0.0+e341b939fe (64-bit .NET 9.0.12)
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.0.0+e341b939fe (64-bit .NET 9.0.12)
[xUnit.net 00:00:00.14] Discovering: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.14] Discovering: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.25] Discovered: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.25] Discovered: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.31] Starting: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.31] Starting: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.61] Finished: SorobanSecurityPortalApi.Tests
[xUnit.net 00:00:00.61] Finished: SorobanSecurityPortalApi.Tests
Passed SorobanSecurityPortalApi.Tests.Controllers.BadgeControllerTests.GetUserBadges_ReturnsOk_WithMappedData [219 ms]
Test Run Successful.
Total tests: 1
Passed: 1
Total time: 1.6807 Seconds
SorobanSecurityPortalApi.Tests test net9.0 succeeded (2.1s)
Test summary: total: 1, failed: 0, succeeded: 1, skipped: 0, duration: 2.1s
Build succeeded in 6.2s
---
---
|
…le BadgeControllerTests.cs
… files to enforce changing badge definition id type from guid to int
|
@0xGeorgii please review. |
|
@0xGeorgii please, review. |
|
@Oluwaseyi89 can you please record a demo video of this feature? |



Description
This PR implements a robust Badge awarding system, including the underlying database schema, business logic services, and API endpoints. It also resolves a critical type-mismatch issue where user identifiers were inconsistently handled between string and int.
Key Changes
Database Schema: * Added BadgeDefinitionModel to store badge metadata (names, descriptions, and criteria).
Added UserBadgeModel as a join table to track earned badges, aligned with UserProfileModel using int foreign keys.
Data Layer (Processors):
Implemented BadgeProcessor for efficient CRUD operations and relationship inclusion (_db.UserBadges.Add(userBadge);).
Service Layer:
Implemented BadgeAwardService to handle business logic for reputation-based and action-specific badge awarding.
API & ViewModels:
Created BadgeController with endpoints for fetching user badges and badge definitions.
Implemented BadgeViewModel and AutoMapper profiles to ensure the API returns flattened, serializable data, preventing circular reference errors in Swagger.
Data Seeding:
Added initial badge definitions (Early Adopter, Reputation milestones) via EF Core HasData seeding.
Technical Notes
Type Safety: Refactored all badge-related methods to use int userProfileId to maintain consistency with the existing UserProfileModel.Id.
Encoding: Confirmed UTF-8 support for emoji-based icons in badge definitions.
Swagger Fix: Replaced raw Entity models with ViewModels in controller responses to resolve schema generation crashes.
How to Test
Run dotnet ef database update to apply the new schema and seed data.
Navigate to
/api/v1/users/{id}/badges.Verify that the response returns an array of badges (or an empty array if none are awarded yet).
Or check all available badge definition Navigate to
/api/v1/users/test-definitionscloses #91