feat: automated daily leetcode challenges integration#421
Draft
Dejmenek wants to merge 11 commits into
Draft
Conversation
Added AddChallenge method to ChallengeService for inserting new challenges into the database. The method checks for duplicate ExternalId values, returns standardized BaseResponse objects, and logs errors using ILogger. Updated IChallengeService interface and constructor to support these changes.
Introduced new record types in the TCSA.V2026.Data.Models.Responses namespace to represent LeetCode daily challenge data. Added LeetCodeDailyResult, LeetCodeDailyQuestion, LeetCodeTopicTag, and LeetCodeDailyProblem records to provide structured modeling of daily challenge questions, their metadata, and associated topic tags. This enables better handling and integration of LeetCode daily challenge information within the application.
Added the GetDailyChallenge constant to ChallengePlatformConstants. This constant holds a GraphQL query to fetch the active daily coding challenge question, including its date, title, slug, difficulty, paid status, content, and topic tags.
Introduce DailyChallengeJob in TCSA.V2026.Services.Challenges. This BackgroundService uses dependency injection to fetch daily challenges from all IDailyChallengeFetchService implementations and adds them to IChallengeService every 24 hours using a PeriodicTimer.
Introduce IDailyChallengeFetchService interface and implement it with LeetCodeDailyChallengeService. The service fetches the daily challenge from LeetCode's GraphQL API, maps the response to the local Challenge model, and handles paid-only problems. Includes logic for difficulty mapping, XP assignment, and description extraction. Adds error logging and uses dependency injection for HttpClient and logger.
Registered LeetCodeDailyChallengeService as IDailyChallengeFetchService (scoped) and added DailyChallengeJob as a hosted service. These changes enable background processing and fetching of daily challenges, supporting new daily challenge functionality.
Added LeetCodeDailyChallengeServiceTests to verify the behavior of LeetCodeDailyChallengeService. The tests set up HTTP client factory and logger, and include a test to ensure the fetched daily challenge has valid properties, correct platform, release date, level, experience points, and category. This ensures the service correctly retrieves and parses daily challenges from LeetCode.
Cleaned up ChallengeService.cs, CodeWarsService.cs, and DailyChallengeJob.cs by removing unnecessary or unused using statements. This improves code readability and maintainability.
Updated ChallengeServiceTests to pass a NullLogger<ChallengeService> instance to ChallengeService during setup. Added the necessary using directive for Microsoft.Extensions.Logging.Abstractions to support this change. This ensures the service can accept a logger dependency in tests.
Added AddChallenge_ShouldNotAddDuplicate integration test to ChallengeServiceTests. This test ensures that adding a Challenge with a duplicate ExternalId fails with the correct message and does not create multiple entries in the database.
Dejmenek
marked this pull request as draft
May 5, 2026 20:01
Dejmenek
marked this pull request as ready for review
May 6, 2026 12:27
Refactored LeetCodeDailyChallengeServiceTests to use Moq and a custom MockHttpMessageHandler, removing dependencies on real HTTP calls and service containers. Added focused test cases for easy, medium, hard, paid-only, and API failure scenarios. Introduced helper methods for payload generation and service creation. Removed the old generic test. Tests are now deterministic, isolated, and do not rely on external services or the current date. Added MockHttpMessageHandler.cs to support HTTP response mocking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Automates daily addition of new LeetCode coding challenges into the platform.
Related Issue
Closes #416
Type of Change
Implementation Details
IDailyChallengeFetchServiceinterface with a singleFetchDailyChallenge()method. Future platforms (Codewars, HackerRank, etc.) can be added without touchingDailyChallengeJob.LeetCodeDailyChallengeServicewhich calls LeetCode API to get current challenge, maps LeetCode difficulty (Easy/Medium/Hard) to the existingLevelenum and XP values (5/10/15). Skips premium problems. Detects SQL and C# challenges. Strips HTML from the problem content and extracts the first sentence forDescription.DailyChallengeJobis a background service which runs once a day and calls every registeredIDailyChallengeFetchServiceto get daily challenges. Later usesChallengeServiceto save them to the database. Scoped services are resolved safely by usingIServiceScopeFactory.ChallengeService.AddChallenge- checks for an existing record byExternalIdbefore inserting to prevent duplicates. Returns aBaseResponsewith success/fail status.GetDailyChallengegraphql query toChallengePlatformConstants.LeetCodeDailyResponsestrongly-typed models forGetDailyChallengequery result.LeetCodeDailyChallengeServiceTests.FetchDailyChallenge_ShouldReturnValidChallengeintegration test that hits real LeetCode GraphQL API and asserts that the returnedChallengehas a non-emptyExternalId,Name, andDescription, the correctPlatform,ReleaseDate, a validLevel, the correct XP value, and a validCategory.ChallengeServiceTestswas extended with an integration test asserting that callingAddChallengetwice with theExternalIdreturns a failure response on the second call, verifying the duplicate-prevention logic.Testing Performed
dotnet test TCSA.V2026.UnitTests/)dotnet test TCSA.2026.IntegrationTests/)dotnet test TCSA.2026.EndToEndTests/)Checklist
Additional Context
To test it locally, you can: change the value of
PeriodicTimer, run the app, wait for the background job to execute, then go to the challenges page.