From 02e32f8ab27737189ded296fae527d9ff9cf1cbc Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 8 Jan 2026 12:18:14 +0100 Subject: [PATCH] Move services into their own files --- .../Services/{ => Play}/IPlayDataService.cs | 0 .../Services/{ => Play}/IPlayIdService.cs | 0 .../Implementations/NeverPlayIdServices.cs | 16 ++++++++++ .../Implementations/PlayDataService.cs | 0 .../Play/Implementations/PlayIdService.cs | 13 +++++++++ .../PlayIdSingletonService.cs} | 29 ++----------------- src/Core/Services/Play/README.md | 27 +++++++++++++++++ 7 files changed, 58 insertions(+), 27 deletions(-) rename src/Core/Services/{ => Play}/IPlayDataService.cs (100%) rename src/Core/Services/{ => Play}/IPlayIdService.cs (100%) create mode 100644 src/Core/Services/Play/Implementations/NeverPlayIdServices.cs rename src/Core/Services/{ => Play}/Implementations/PlayDataService.cs (100%) create mode 100644 src/Core/Services/Play/Implementations/PlayIdService.cs rename src/Core/Services/{Implementations/PlayIdService.cs => Play/Implementations/PlayIdSingletonService.cs} (72%) create mode 100644 src/Core/Services/Play/README.md diff --git a/src/Core/Services/IPlayDataService.cs b/src/Core/Services/Play/IPlayDataService.cs similarity index 100% rename from src/Core/Services/IPlayDataService.cs rename to src/Core/Services/Play/IPlayDataService.cs diff --git a/src/Core/Services/IPlayIdService.cs b/src/Core/Services/Play/IPlayIdService.cs similarity index 100% rename from src/Core/Services/IPlayIdService.cs rename to src/Core/Services/Play/IPlayIdService.cs diff --git a/src/Core/Services/Play/Implementations/NeverPlayIdServices.cs b/src/Core/Services/Play/Implementations/NeverPlayIdServices.cs new file mode 100644 index 0000000000..51c2b2af95 --- /dev/null +++ b/src/Core/Services/Play/Implementations/NeverPlayIdServices.cs @@ -0,0 +1,16 @@ +namespace Bit.Core.Services; + +public class NeverPlayIdServices : IPlayIdService +{ + public string? PlayId + { + get => null; + set { } + } + + public bool InPlay(out string playId) + { + playId = string.Empty; + return false; + } +} \ No newline at end of file diff --git a/src/Core/Services/Implementations/PlayDataService.cs b/src/Core/Services/Play/Implementations/PlayDataService.cs similarity index 100% rename from src/Core/Services/Implementations/PlayDataService.cs rename to src/Core/Services/Play/Implementations/PlayDataService.cs diff --git a/src/Core/Services/Play/Implementations/PlayIdService.cs b/src/Core/Services/Play/Implementations/PlayIdService.cs new file mode 100644 index 0000000000..0c64f1dd14 --- /dev/null +++ b/src/Core/Services/Play/Implementations/PlayIdService.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.Hosting; + +namespace Bit.Core.Services; + +public class PlayIdService(IHostEnvironment hostEnvironment) : IPlayIdService +{ + public string? PlayId { get; set; } + public bool InPlay(out string playId) + { + playId = PlayId ?? string.Empty; + return !string.IsNullOrEmpty(PlayId) && hostEnvironment.IsDevelopment(); + } +} diff --git a/src/Core/Services/Implementations/PlayIdService.cs b/src/Core/Services/Play/Implementations/PlayIdSingletonService.cs similarity index 72% rename from src/Core/Services/Implementations/PlayIdService.cs rename to src/Core/Services/Play/Implementations/PlayIdSingletonService.cs index 7a5a046142..86b750442e 100644 --- a/src/Core/Services/Implementations/PlayIdService.cs +++ b/src/Core/Services/Play/Implementations/PlayIdSingletonService.cs @@ -1,34 +1,9 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace Bit.Core.Services; -public class PlayIdService(IHostEnvironment hostEnvironment) : IPlayIdService -{ - public string? PlayId { get; set; } - public bool InPlay(out string playId) - { - playId = PlayId ?? string.Empty; - return !string.IsNullOrEmpty(PlayId) && hostEnvironment.IsDevelopment(); - } -} - -public class NeverPlayIdServices : IPlayIdService -{ - public string? PlayId - { - get => null; - set { } - } - - public bool InPlay(out string playId) - { - playId = string.Empty; - return false; - } -} - /// /// Singleton wrapper service that bridges singleton-scoped service boundaries for PlayId tracking. /// This allows singleton services to access the scoped PlayIdService via HttpContext.RequestServices. @@ -70,4 +45,4 @@ public class PlayIdSingletonService(IHttpContextAccessor httpContextAccessor, IH return false; } } -} +} \ No newline at end of file diff --git a/src/Core/Services/Play/README.md b/src/Core/Services/Play/README.md new file mode 100644 index 0000000000..a0d9ecfac8 --- /dev/null +++ b/src/Core/Services/Play/README.md @@ -0,0 +1,27 @@ +# Play Services + +## Overview + +The Play services provide automated testing infrastructure for tracking and cleaning up test data in development +environments. A "Play" is a test session that groups entities (users, organizations, etc.) created during testing to +enable bulk cleanup via the SeederAPI. + +## How It Works + +1. Test client sends `x-play-id` header with a unique Play identifier +2. `PlayIdMiddleware` extracts the header and sets it on `IPlayIdService` +3. Repositories check `IPlayIdService.InPlay()` when creating entities +4. `IPlayDataService` records PlayData entries for tracked entities +5. SeederAPI uses PlayData records to bulk delete all entities associated with a PlayId + +Play services are **only active in Development environments**. + +## Classes + +- **`IPlayIdService`** - Interface for managing Play identifiers in the current request scope +- **`IPlayDataService`** - Interface for tracking entities created during a Play session +- **`PlayIdService`** - Default scoped implementation for tracking Play sessions per HTTP request +- **`NeverPlayIdServices`** - No-op implementation used as fallback when no HttpContext is available +- **`PlayIdSingletonService`** - Singleton wrapper that allows singleton services to access scoped PlayIdService via +HttpContext +- **`PlayDataService`** - Implementation that records PlayData entries for entities created during Play sessions