Skip to content
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

Added the features for storing drafts #1642

Merged
merged 6 commits into from
Jan 27, 2025

Conversation

HlibBondarev
Copy link
Contributor

@HlibBondarev HlibBondarev commented Jan 22, 2025

  1. Added the feature to get the time remaining until the end of the draft's life.
  2. Added the feature to set the expiration interval for drafts in appsettings files.

Summary by CodeRabbit

  • New Features

    • Added ability to check time-to-live for draft storage.
    • Introduced Redis configuration for draft management with expiration intervals.
    • New methods for restoring drafts and retrieving draft expiration information in the API.
  • Improvements

    • Enhanced draft storage service with more precise caching controls.
    • Updated response handling for draft restoration in the API.
  • Configuration

    • Updated application settings to support new Redis draft configuration.
    • Added configuration options for absolute expiration intervals.

…raft's life.

2) Added the feature to set the expiration interval for drafts in appsettings files.
Copy link

coderabbitai bot commented Jan 22, 2025

Walkthrough

The pull request introduces enhancements to draft storage functionality across multiple files in the OutOfSchool project. The changes primarily focus on adding time-to-live (TTL) capabilities for draft storage using Redis. A new configuration class RedisForDraftConfig is introduced to manage expiration intervals, and corresponding methods are added to services, interfaces, and controllers to support retrieving and managing draft expiration times. The modifications extend the existing draft storage infrastructure with more granular control over draft lifecycle management.

Changes

File Change Summary
...BusinessLogic/Services/DraftStorage/DraftStorageService.cs - Added redisConfig field
- Updated constructor to accept Redis configuration
- Modified CreateAsync method to use TTL
- Added GetTimeToLiveAsync method
...BusinessLogic/Services/DraftStorage/IDraftStorageService.cs - Added GetTimeToLiveAsync method to interface
...Redis/CacheService.cs - Added GetTimeToLiveAsync method to retrieve TTL for cache entries
- Updated WriteAsync and GetOrAddAsync methods for expiration options
...Redis/IReadWriteCacheService.cs - Added GetTimeToLiveAsync method to interface
...Redis/RedisForDraftConfig.cs - New configuration class with TTL interval properties
...WebApi/Controllers/V1/DraftStorageController.cs - Added GetTimeToLiveOfDraft method
- Refined RestoreDraft method
...WebApi/Startup.cs - Added options configuration for RedisForDraftConfig
appsettings.*.json - Added new RedisForDraft configuration section with expiration intervals
...WebApi.Tests/Controllers/WorkshopDraftStorageControllerTests.cs - Updated tests for draft restoration and added new tests for TTL functionality
...WebApi.Tests/Services/DraftStorage/DraftStorageServiceTests.cs - Updated tests to incorporate Redis configuration options and TTL checks

Sequence Diagram

sequenceDiagram
    participant Client
    participant DraftStorageController
    participant DraftStorageService
    participant CacheService
    participant RedisCache

    Client->>DraftStorageController: Get Draft TTL
    DraftStorageController->>DraftStorageService: GetTimeToLiveAsync(key)
    DraftStorageService->>CacheService: GetTimeToLiveAsync(key)
    CacheService->>RedisCache: Retrieve TTL
    RedisCache-->>CacheService: Return TimeSpan
    CacheService-->>DraftStorageService: Return TimeSpan
    DraftStorageService-->>DraftStorageController: Return TimeSpan
    DraftStorageController-->>Client: Return Draft TTL
Loading

Possibly related PRs

  • [Official] Implement list of all officials (employees) for for the provider #1634: The changes in this PR introduce a new method GetTimeToLiveAsync to the IDraftStorageService<T> interface, which is directly related to the new GetTimeToLiveAsync method added in the DraftStorageService<T> class in the main PR. Both methods serve the purpose of retrieving the time-to-live for drafts, establishing a clear connection between the two PRs.

Suggested reviewers

  • h4wk13
  • VadymLevkovskyi
  • DmyMi

Poem

🐰 In Redis's realm of drafts so bright,
A rabbit hops with config's might
TTL now dances, time takes flight
Expiration's magic, clear and tight
Code leaps forward with pure delight! 🕒✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83b6cae and b01b898.

📒 Files selected for processing (1)
  • OutOfSchool/OutOfSchool.Redis/CacheService.cs (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • OutOfSchool/OutOfSchool.Redis/CacheService.cs
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: test (macOS-latest)
  • GitHub Check: test (windows-latest)
  • GitHub Check: test (ubuntu-latest)
  • GitHub Check: SonarCloud

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@HlibBondarev
Copy link
Contributor Author

@coderabbitai summary

Copy link

coderabbitai bot commented Jan 22, 2025

✅ Actions performed

Summary regeneration triggered.

…ller classes;

2) Added attributes to actions of WorkshopDraftStorageController class;
3) Reordered Using-directives in CacheService class.
@HlibBondarev
Copy link
Contributor Author

@coderabbitai summary

Copy link

coderabbitai bot commented Jan 22, 2025

✅ Actions performed

Summary regeneration triggered.

@HlibBondarev HlibBondarev requested a review from DmyMi January 23, 2025 08:42
…controller to the inherited WorkshopDraftStorageController class.
- used TimeSpan.Zero as value of slidingExpirationInterval parameter in  WriteAsync() method of CacheService class.
2) Added GetRedisConnectionString() method to RedisConfig class.
3) Changed CacheService class:
- added private method GetExpirationIntervalOptions();
- used GetExpirationIntervalOptions() method in methods - GetOrAddAsync<T>() and WriteAsync();
- used GetRedisConnectionString() method of RedisConfig class for getting connection string to  Redis.
4) Removed SlidingExpirationInterval property from RedisForDraftConfig class.
5) Added [Authorize] attribute to all Actions of DraftStorageController<T> class for proper authorization in inheritance classes.
6) Fixed Startup class:
- used GetRedisConnectionString() method of RedisConfig class for getting connection string to  Redis.
7) Fixed tests in DraftStorageServiceTests class.
@HlibBondarev HlibBondarev marked this pull request as ready for review January 24, 2025 14:42
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
OutOfSchool/OutOfSchool.Redis/RedisConfig.cs (1)

31-34: Consider masking or encrypting sensitive data.

Building and returning a Redis connection string that includes the password plainly may inadvertently lead to logging or exposure of credentials. While it is common to pass this string to the Redis client, please ensure that logs or error messages never leak this string. If possible, consider using more secure mechanisms to handle the password (e.g., environment variables, secret managers).

OutOfSchool/OutOfSchool.BusinessLogic/Services/DraftStorage/DraftStorageService.cs (1)

61-67: Support for absolute expiration only.

Here, you set redisConfig.AbsoluteExpirationRelativeToNowInterval but pass TimeSpan.Zero for sliding expiration. Confirm that the business logic requires no sliding expiration. If a sliding expiration is needed, pass a nonzero TimeSpan. Otherwise, this usage is valid.

OutOfSchool/OutOfSchool.WebApi/Controllers/V1/DraftStorageController.cs (1)

8-14: Documentation clarifies security responsibilities.

Stating that inherited controllers must handle permissions is crucial to avoid accidental exposure. Make sure all inheriting classes apply [Authorize] or a custom permission attribute.

OutOfSchool/OutOfSchool.WebApi.Tests/Services/DraftStorage/DraftStorageServiceTests.cs (3)

37-40: Consider making the expiration interval configurable.

The hardcoded 1-minute interval might make tests brittle. Consider extracting it to a constant or test parameter for better flexibility.

+    private const int DEFAULT_EXPIRATION_MINUTES = 1;
     redisConfigMock.Setup(c => c.Value).Returns(new RedisForDraftConfig
     {
-        AbsoluteExpirationRelativeToNowInterval = TimeSpan.FromMinutes(1)
+        AbsoluteExpirationRelativeToNowInterval = TimeSpan.FromMinutes(DEFAULT_EXPIRATION_MINUTES)
     });

133-149: Consider a more descriptive test name.

The current test name could be more specific about what it's verifying. Consider renaming to better reflect that it's testing the retrieval of TTL value.

-    public async Task GetTimeToLiveAsync_WhenDraftExistsInCache_ShouldRestoreAppropriatedEntity()
+    public async Task GetTimeToLiveAsync_WhenDraftExistsInCache_ShouldReturnRemainingTimeToLive()

151-166: Consider a more descriptive test name.

The current test name could be more specific about the expected null result.

-    public async Task GetTimeToLiveAsync_WhenDraftIsAbsentInCache_ShouldRestoreDefaultEntity()
+    public async Task GetTimeToLiveAsync_WhenDraftIsAbsentInCache_ShouldReturnNull()
OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/WorkshopDraftStorageControllerTests.cs (1)

Line range hint 216-238: Extract the magic number.

Consider extracting the hardcoded 1-minute value to a constant for better maintainability.

+    private const int DEFAULT_TTL_MINUTES = 1;
+
     [Test]
     public async Task GetTimeToLiveOfDraft_WhenDraftExistsInCache_ReturnsDraftAtActionResult()
     {
         // Arrange
-        TimeSpan? timeToLive = TimeSpan.FromMinutes(1);
+        TimeSpan? timeToLive = TimeSpan.FromMinutes(DEFAULT_TTL_MINUTES);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b48b08 and 83b6cae.

📒 Files selected for processing (13)
  • OutOfSchool/OutOfSchool.BusinessLogic/Services/DraftStorage/DraftStorageService.cs (4 hunks)
  • OutOfSchool/OutOfSchool.BusinessLogic/Services/DraftStorage/IDraftStorageService.cs (1 hunks)
  • OutOfSchool/OutOfSchool.Redis/CacheService.cs (7 hunks)
  • OutOfSchool/OutOfSchool.Redis/IReadWriteCacheService.cs (1 hunks)
  • OutOfSchool/OutOfSchool.Redis/RedisConfig.cs (2 hunks)
  • OutOfSchool/OutOfSchool.Redis/RedisForDraftConfig.cs (1 hunks)
  • OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/WorkshopDraftStorageControllerTests.cs (4 hunks)
  • OutOfSchool/OutOfSchool.WebApi.Tests/Services/DraftStorage/DraftStorageServiceTests.cs (5 hunks)
  • OutOfSchool/OutOfSchool.WebApi/Controllers/V1/DraftStorageController.cs (3 hunks)
  • OutOfSchool/OutOfSchool.WebApi/Controllers/V1/WorkshopDraftStorageController.cs (1 hunks)
  • OutOfSchool/OutOfSchool.WebApi/Startup.cs (2 hunks)
  • OutOfSchool/OutOfSchool.WebApi/appsettings.Development.json (1 hunks)
  • OutOfSchool/OutOfSchool.WebApi/appsettings.Release.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • OutOfSchool/OutOfSchool.BusinessLogic/Services/DraftStorage/IDraftStorageService.cs
  • OutOfSchool/OutOfSchool.Redis/RedisForDraftConfig.cs
  • OutOfSchool/OutOfSchool.Redis/IReadWriteCacheService.cs
  • OutOfSchool/OutOfSchool.WebApi/Startup.cs
  • OutOfSchool/OutOfSchool.WebApi/appsettings.Development.json
  • OutOfSchool/OutOfSchool.WebApi/appsettings.Release.json
🔇 Additional comments (16)
OutOfSchool/OutOfSchool.WebApi/Controllers/V1/WorkshopDraftStorageController.cs (1)

12-12: Enforce permission checks consistently.

Adding [HasPermission(Permissions.WorkshopAddNew)] ensures that only users with the correct permission can access this controller. Verify that downstream endpoints follow similar permission checks to maintain consistent authorization for all draft-related operations.

OutOfSchool/OutOfSchool.Redis/RedisConfig.cs (1)

14-14: No functional impact.

The added blank line before the Password property does not affect functionality. It is fine to leave it for clarity or remove it to maintain consistency in style.

OutOfSchool/OutOfSchool.BusinessLogic/Services/DraftStorage/DraftStorageService.cs (5)

1-2: New imports look correct.

The addition of using Microsoft.Extensions.Options; properly manages injection of configuration objects. There are no apparent issues.


16-16: Clear naming for config usage.

Declaring RedisForDraftConfig redisConfig clarifies that it contains draft-specific Redis settings, aiding maintainability.


23-25: Constructor injection for draft config.

Injecting IOptions<RedisForDraftConfig> is a standard way to manage strongly typed configs in .NET. This aligns well with best practices.


29-29: Assign only once in a safe context.

Storing redisConfig.Value is correct. Just ensure that no re-initialization is necessary if configuration changes at runtime. If dynamic config reloading is needed, you might rely on IOptionsSnapshot.


90-99: Method to retrieve remaining TTL is well-structured.

GetTimeToLiveAsync provides a clean approach to query a draft’s remaining lifetime. Ensure that calling code handles a null result correctly. If further modifications are needed, consider returning a default TimeSpan.Zero instead of null.

OutOfSchool/OutOfSchool.WebApi/Controllers/V1/DraftStorageController.cs (5)

4-4: Added import is valid.

using System.Net.Mime; is relevant for specifying content types, especially helpful when dealing with JSON or other MIME types in responses.


27-46: Conditional response pattern is appropriate.

The RestoreDraft method returns NoContent if there is no draft, or Ok when a draft is found. This is clear and follows RESTful conventions.


47-66: Time-to-live retrieval integrated cleanly.

The GetTimeToLiveOfDraft method’s conditional NoContent or Ok response matches the approach used in RestoreDraft. This keeps the controller consistent.


Line range hint 67-94: Explicit authorization for storing drafts.

The [Authorize] attribute ensures that only authenticated users can store drafts. This is consistent with the broader security stance described in the class’s XML commentary.


95-106: Draft removal logic is secure and consistent.

The [Authorize] attribute again protects the endpoint. Returning NoContent after removal is standard practice. Everything looks good here.

OutOfSchool/OutOfSchool.WebApi.Tests/Services/DraftStorage/DraftStorageServiceTests.cs (1)

88-89: LGTM!

Good update to use the configured expiration interval from Redis config.

OutOfSchool/OutOfSchool.Redis/CacheService.cs (1)

247-262: LGTM!

Well-structured and clearly documented handling of sliding expiration cases.

OutOfSchool/OutOfSchool.WebApi.Tests/Controllers/WorkshopDraftStorageControllerTests.cs (2)

Line range hint 189-214: LGTM!

Good update to return 204 No Content when draft is not found, following REST best practices.


240-259: LGTM!

Well-structured test that properly verifies the behavior when no TTL is found.

OutOfSchool/OutOfSchool.Redis/CacheService.cs Outdated Show resolved Hide resolved
OutOfSchool/OutOfSchool.Redis/CacheService.cs Show resolved Hide resolved
- code throws exception if redisConfig.AbsoluteExpirationRelativeToNowInterval property is null.
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
52.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@DmyMi DmyMi merged commit bebe22f into develop Jan 27, 2025
5 of 6 checks passed
@DmyMi DmyMi deleted the HlibBondarev/Add_GetTimeToLive_to_DraftStorageService branch January 27, 2025 17:17
This was referenced Jan 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants