Class TeamServiceRepositoryBase<TTeamEntity, TMember>
public abstract class TeamServiceRepositoryBase<TTeamEntity, TMember> : TeamServiceBase where TTeamEntity : TeamEntityBase<TMember> where TMember : TeamMemberBase
Type Parameters
TTeamEntityTMember
- Inheritance
-
TeamServiceRepositoryBase<TTeamEntity, TMember>
- Derived
- Inherited Members
Constructors
TeamServiceRepositoryBase(IUserService, ITeamRepository<TTeamEntity, TMember>, IMongoDbServiceFactory, IIconStore, ITeamCache, InvitationOptions)
protected TeamServiceRepositoryBase(IUserService userService, ITeamRepository<TTeamEntity, TMember> teamRepository, IMongoDbServiceFactory mongoDbServiceFactory, IIconStore iconStore = null, ITeamCache cache = null, InvitationOptions invitationOptions = null)
Parameters
userServiceIUserServiceResolves the calling user.
teamRepositoryITeamRepository<TTeamEntity, TMember>The team collection this service reads and writes.
mongoDbServiceFactoryIMongoDbServiceFactoryUsed for the operations that go outside the repository.
iconStoreIIconStoreOptional. Required only for team icons.
cacheITeamCacheOptional. Forward it from your own service's constructor when running more than one instance — left unforwarded, the claims-path lookups fall back to a process-local cache that cannot see another instance's writes. See ITeamCache.
invitationOptionsInvitationOptionsOptional. Forward it from your own service's constructor if you configure an invitation lifetime — left unforwarded, this base receives the defaults and invitations never expire however the host configured them. The same forwarding hazard as
cache.
Properties
SupportsSoftDelete
This store can soft-delete, so TeamDeleteMode.Soft takes effect.
protected override bool SupportsSoftDelete { get; }
Property Value
Methods
AddTeamMemberAsync(string, InviteUserModel)
protected override Task AddTeamMemberAsync(string teamKey, InviteUserModel model)
Parameters
teamKeystringmodelInviteUserModel
Returns
CreateTeam(string, string, IUser, string)
protected abstract Task<TTeamEntity> CreateTeam(string teamKey, string name, IUser user, string displayName)
Parameters
Returns
- Task<TTeamEntity>
CreateTeamAsync(string, string, IUser, string)
protected override Task<ITeam> CreateTeamAsync(string teamKey, string name, IUser user, string displayName)
Parameters
Returns
CreateTeamMember(InviteUserModel)
protected abstract Task<TMember> CreateTeamMember(InviteUserModel model)
Parameters
modelInviteUserModel
Returns
- Task<TMember>
DeleteTeamAsync(string)
Removes the team record, then drops the team's database.
protected override Task DeleteTeamAsync(string teamKey)
Parameters
teamKeystring
Returns
Remarks
The record goes first, and the order is the point. The two writes cannot be made atomic — one is a document delete, the other a database drop — so the only choice is which way a partial failure fails. Dropping first and then failing to delete the record leaves a live team pointing at deleted data: it still lists, still resolves, still authorizes, and every read against it returns empty. Deleting the record first leaves an orphaned database, which is inert and which a sweep can find. Reported by Eplicta FortDocs (Tharga/Team#224), where the drop happened to throw first and nothing was lost.
A drop failure is wrapped as TeamStorageException rather than allowed to surface as a driver exception — see that type for why the message addresses the deployment rather than the caller. The record is already gone at that point, which is the intended outcome: the team is deleted, and what remains is a database to clean up.
GetAllTeamsInternalAsync()
Backs GetAllTeamsAsync(). Virtual rather than abstract so existing derived services keep compiling; the default returns nothing, and storage-backed bases override it.
protected override IAsyncEnumerable<ITeam> GetAllTeamsInternalAsync()
Returns
GetConsentedTeamsInternalAsync(string[])
protected override IAsyncEnumerable<ITeam> GetConsentedTeamsInternalAsync(string[] userRoles)
Parameters
userRolesstring[]
Returns
GetInvitationInternalAsync(string, string)
protected override Task<Invitation> GetInvitationInternalAsync(string teamKey, string inviteKey)
Parameters
Returns
GetInvitedMemberNameAsync(string, string)
Look up the (admin-entered) Name of the member identified by inviteKey
inside the given team. Used to capture the invitation Name before accept clears it,
so it can be promoted to User.Name. Default implementation returns null;
derivatives that have access to the typed team document override it.
protected override Task<string> GetInvitedMemberNameAsync(string teamKey, string inviteKey)
Parameters
Returns
GetTeamAsync(string)
protected override Task<ITeam> GetTeamAsync(string teamKey)
Parameters
teamKeystring
Returns
GetTeamKeyByInviteKeyInternalAsync(string)
The outstanding invitation matching inviteKey on teamKey, or
null. Backs expiry enforcement.
protected override Task<string> GetTeamKeyByInviteKeyInternalAsync(string inviteKey)
Parameters
inviteKeystring
Returns
Remarks
Virtual rather than abstract, like the other members added after the seam was first drawn, so a host with its own store keeps compiling. The default returns null, which reads as "no expiry to enforce".
That default is a hole if a lifetime is configured and this is not overridden — expiry would
silently not apply. It is a startup check rather than a silent default for exactly that reason: see
InvitationExpiryWiringCheck, which fails the boot naming this method when
Lifetime is set and the store cannot answer it. Nothing is asked of a
host that has not opted into expiry.
GetTeamMembersAsync(string, string)
protected override Task<ITeamMember> GetTeamMembersAsync(string teamKey, string userKey)
Parameters
Returns
GetTeamsAsync(IUser)
protected override IAsyncEnumerable<ITeam> GetTeamsAsync(IUser user)
Parameters
userIUser
Returns
GetTeamsForUserWithAccessLevelInternalAsync(string, AccessLevel)
protected override Task<IReadOnlyList<ITeam>> GetTeamsForUserWithAccessLevelInternalAsync(string userKey, AccessLevel accessLevel)
Parameters
userKeystringaccessLevelAccessLevel
Returns
Remarks
Filters the cross-team enumeration rather than adding a repository query. The set is bounded by the number of teams, this runs once per delete confirmation rather than per request, and a dedicated query would be a second place for the membership shape to be interpreted.
IsTeamKeyInUseAsync(string)
A key is in use while any team holds it, deleted or not, so a soft-deleted team keeps its key reserved until it is purged.
protected override Task<bool> IsTeamKeyInUseAsync(string teamKey)
Parameters
teamKeystring
Returns
PurgeTeamAsync(string)
Removes the team record and drops its database. The only path here that needs dropDatabase.
protected override Task PurgeTeamAsync(string teamKey)
Parameters
teamKeystring
Returns
Remarks
Same ordering and same wrapping as DeleteTeamAsync(string) — record first, so a drop failure leaves an orphaned database rather than a live team pointing at nothing.
RemoveTeamMemberAsync(string, string)
protected override Task RemoveTeamMemberAsync(string teamKey, string userKey)
Parameters
Returns
RemoveUserFromAllTeamsInternalAsync(string)
protected override Task<int> RemoveUserFromAllTeamsInternalAsync(string userKey)
Parameters
userKeystring
Returns
RestoreTeamAsync(string)
Clears the deleted mark, returning the team to normal use.
protected override Task RestoreTeamAsync(string teamKey)
Parameters
teamKeystring
Returns
Remarks
Unreachable unless SupportsSoftDelete is true — there is nothing to restore in a
store that deletes outright — so the default throws rather than pretending to succeed.
SetTeamConsentInternalAsync(string, string[], AccessLevel?)
protected override Task SetTeamConsentInternalAsync(string teamKey, string[] consentedRoles, AccessLevel? accessLevel)
Parameters
teamKeystringconsentedRolesstring[]accessLevelAccessLevel?
Returns
SetTeamCustomRolesInternalAsync(string, IReadOnlyList<TenantRoleDefinition>)
protected override Task SetTeamCustomRolesInternalAsync(string teamKey, IReadOnlyList<TenantRoleDefinition> customRoles)
Parameters
teamKeystringcustomRolesIReadOnlyList<TenantRoleDefinition>
Returns
SetTeamIconReferenceInternalAsync(string, string)
Backs SetTeamIconAsync(string, byte[], string) / ClearTeamIconAsync(string) — persists the icon reference (or null to clear) on the team document. Virtual-throw so existing derived services keep compiling; storage-backed bases override it.
protected override Task SetTeamIconReferenceInternalAsync(string teamKey, string reference)
Parameters
Returns
SetTeamMemberInvitationExpiryAsync(string, string, DateTime?)
Moves the expiry of the invitation matching inviteKey, leaving its code alone.
protected override Task SetTeamMemberInvitationExpiryAsync(string teamKey, string inviteKey, DateTime? expiresAt)
Parameters
Returns
Remarks
Throws rather than no-opping when unimplemented, unlike GetInvitationInternalAsync(string, string). The difference is what silence would mean: a store that cannot read an expiry has nothing to enforce, but a store that silently discards an extension reports success for an invitation that stays expired, and the operator finds out from the person who could not accept it.
SetTeamMemberInvitationResponseAsync(string, string, string, bool)
protected override Task<ITeam> SetTeamMemberInvitationResponseAsync(string teamKey, string userKey, string inviteKey, bool accept)
Parameters
Returns
SetTeamMemberLastSeenAsync(string, string)
protected override Task SetTeamMemberLastSeenAsync(string teamKey, string userKey)
Parameters
Returns
SetTeamMemberNameAsync(string, string, string)
protected override Task SetTeamMemberNameAsync(string teamKey, string userKey, string name)
Parameters
Returns
SetTeamMemberRoleAsync(string, string, AccessLevel)
protected override Task SetTeamMemberRoleAsync(string teamKey, string userKey, AccessLevel accessLevel)
Parameters
teamKeystringuserKeystringaccessLevelAccessLevel
Returns
SetTeamMemberScopeOverridesAsync(string, string, string[])
protected override Task SetTeamMemberScopeOverridesAsync(string teamKey, string userKey, string[] scopeOverrides)
Parameters
Returns
SetTeamMemberSuspendedAsync(string, string, DateTime?, string)
Persists a member's suspended state. Override to support suspending members.
protected override Task SetTeamMemberSuspendedAsync(string teamKey, string userKey, DateTime? suspendedAt, string suspendedBy)
Parameters
Returns
Remarks
Virtual with a throwing body rather than abstract: adding an abstract member here would break every host that already derives from this class. Throwing rather than no-opping for the same reason the user and key equivalents do — a suspension silently skipped is a containment reported but never applied.
SetTeamMemberTenantRolesAsync(string, string, string[])
protected override Task SetTeamMemberTenantRolesAsync(string teamKey, string userKey, string[] tenantRoles)
Parameters
Returns
SetTeamNameAsync(string, string)
protected override Task SetTeamNameAsync(string teamKey, string name)
Parameters
Returns
SoftDeleteTeamAsync(string, string)
Marks the team deleted without removing it, recording when and by whom.
protected override Task SoftDeleteTeamAsync(string teamKey, string deletedBy)
Parameters
Returns
Remarks
Virtual, never abstract — an abstract member here breaks every derived host at compile time. The default delegates to DeleteTeamAsync(string), so a store that has not implemented soft delete performs the irreversible delete it always did rather than throwing. Paired with SupportsSoftDelete, which tells callers which of the two they will get.