| | | 1 | | using ArturRios.Data.Relational.Core.Interfaces; |
| | | 2 | | using ArturRios.Heimdall.Domain.Entities; |
| | | 3 | | using ArturRios.Heimdall.Domain.Enums; |
| | | 4 | | using Microsoft.EntityFrameworkCore; |
| | | 5 | | |
| | | 6 | | namespace ArturRios.Heimdall.Shared.Services; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// FR-PE-19: which of another person's scope ownerships a reader may see. A System Admin sees |
| | | 10 | | /// every one; anyone else sees only the ownerships of scopes they own themselves. |
| | | 11 | | /// </summary> |
| | | 12 | | /// <remarks> |
| | | 13 | | /// <para> |
| | | 14 | | /// A Scope Admin can read a co-owner, and the owners of their scopes, because they share a |
| | | 15 | | /// scope with them. That shared scope is what they are entitled to know about. The other |
| | | 16 | | /// scopes the person owns belong to other tenants, so a projection a Scope Admin reads about |
| | | 17 | | /// somebody else reports only the ownerships the two have in common. |
| | | 18 | | /// </para> |
| | | 19 | | /// <para> |
| | | 20 | | /// A person reading their own record sees every scope they own either way, since every |
| | | 21 | | /// scope they own is one of theirs. The callers that short-circuit a self read do so only to |
| | | 22 | | /// save the query. |
| | | 23 | | /// </para> |
| | | 24 | | /// </remarks> |
| | | 25 | | public static class OwnedScopeVisibility |
| | | 26 | | { |
| | | 27 | | /// <summary> |
| | | 28 | | /// The internal ids of the scopes whose ownerships <paramref name="actingPersonId" /> may see |
| | | 29 | | /// on another person, or <c>null</c> when they may see all of them (a System Admin). |
| | | 30 | | /// </summary> |
| | | 31 | | /// <remarks> |
| | | 32 | | /// A logically deleted actor owns nothing, as <see cref="ScopeOwnershipChecker" /> holds: they |
| | | 33 | | /// can no longer authenticate, so a token issued before the deletion reveals nothing. |
| | | 34 | | /// </remarks> |
| | | 35 | | public static async Task<IReadOnlyCollection<long>?> ScopesVisibleToAsync( |
| | | 36 | | IAsyncReadOnlyRepository<Person, long> personReader, int actingRole, Guid actingPersonId) |
| | | 37 | | { |
| | 97 | 38 | | if (actingRole == (int)Roles.SystemAdmin) |
| | | 39 | | { |
| | 76 | 40 | | return null; |
| | | 41 | | } |
| | | 42 | | |
| | 21 | 43 | | return await personReader.Query() |
| | 21 | 44 | | .Where(x => x.PublicId == actingPersonId && !x.IsDeleted) |
| | 21 | 45 | | .SelectMany(x => x.ScopeOwnerships.Select(ownership => ownership.ScopeId)) |
| | 21 | 46 | | .ToListAsync(); |
| | 97 | 47 | | } |
| | | 48 | | } |