using DodoSSH.Client.Api;
using DodoSSH.Client.Auth;
using DodoSSH.Client.Session;
using DodoSSH.Client.Sync;
using DodoSSH.Contracts;
namespace DodoSSH.Client.App.Layout.Tests;
///
/// The least server a TeamsViewModel needs in order to be laid out with something in it.
///
///
///
/// The teams screen is the one screen in this suite whose content cannot come from an unlocked vault,
/// because none of it is vault content: a team, its members, its invitations and who holds a key to a
/// vault are all read from the server on open, and the suite's FakeAccountServer implements
/// and nothing else. Rather than teach that fake five more interfaces for one
/// screen, this serves fixed rows and refuses everything a layout test has no business calling.
///
///
/// The rows are deliberately the long ones. A layout suite that measured "Bob" in a column sized
/// for an email address would certify a shape no real team produces — so the names, addresses and status
/// sentences here are at or near the length the interface can really be handed, which is what makes an
/// overflow show up at the minimum window rather than on somebody's screen.
///
///
internal sealed class StubTeamServer : IVaultServer, ITeamApi, IVaultGrantApi
{
private static readonly Guid OwnerId = Guid.CreateVersion7();
private static readonly Guid ColleagueId = Guid.CreateVersion7();
private static readonly Guid TeamId = Guid.CreateVersion7();
private static readonly Guid VaultId = Guid.CreateVersion7();
///
public Uri ServerUrl { get; } = new("https://dodossh.example");
///
public ITeamApi Teams => this;
///
public IVaultGrantApi Grants => this;
///
public IAccountApi Account => throw new NotSupportedException();
///
public ISyncApi Sync => throw new NotSupportedException();
///
public IDirectoryApi Directory => throw new NotSupportedException();
///
public IKeyBindingAuthorizer KeyBinding => throw new NotSupportedException();
///
public SyncOptions SyncOptions => new();
///
public string? RefreshToken => null;
/// The vault whose key holders are listed, so a test can select it.
internal static Guid TeamVaultId => VaultId;
///
public Task> ListTeamsAsync(CancellationToken cancellationToken) =>
Task.FromResult>(
[
new TeamSummary(
TeamId,
"Platform Engineering",
"platform-engineering",
"Everything that runs the estate.",
TeamMemberRole.Owner,
MemberCount: 2,
VaultCount: 1,
DateTimeOffset.UnixEpoch),
]);
///
public Task> ListTeamMembersAsync(
Guid teamId,
CancellationToken cancellationToken) =>
Task.FromResult>(
[
new TeamMemberSummary(
OwnerId,
"alexandra.hollingsworth@dodotech.example",
"Alexandra Hollingsworth",
TeamMemberRole.Owner,
TeamMemberStatus.Active,
IsEnrolled: true,
DateTimeOffset.UnixEpoch,
DateTimeOffset.UnixEpoch),
// The unenrolled case on purpose: its key-state phrase is the longest the column ever
// carries, and it is the row that decides whether that column is wide enough.
new TeamMemberSummary(
ColleagueId,
"bartholomew.fotheringay@dodotech.example",
"Bartholomew Fotheringay",
TeamMemberRole.Member,
TeamMemberStatus.Active,
IsEnrolled: false,
DateTimeOffset.UnixEpoch,
LastActiveAt: null),
]);
///
public Task> ListTeamInvitationsAsync(
Guid teamId,
CancellationToken cancellationToken) =>
Task.FromResult>(
[
// Pending, because its sentence is the long one — it has to carry the whole mechanism,
// since nothing was sent and there is nothing else on the screen that could say so.
new TeamInvitationSummary(
Guid.CreateVersion7(),
"wilhelmina.ashworth-blake@dodotech.example",
TeamMemberRole.Admin,
TeamInvitationState.Pending,
OwnerId,
DateTimeOffset.UnixEpoch,
DateTimeOffset.UnixEpoch.AddDays(14),
AcceptedAt: null),
]);
///
public Task ListVaultGrantsAsync(
Guid vaultId,
CancellationToken cancellationToken) =>
Task.FromResult(new VaultGrantsResponse(
vaultId,
KeyGeneration: 2,
RekeyRequired: true,
Grants:
[
new VaultGrantSummary(
OwnerId,
"alexandra.hollingsworth@dodotech.example",
"Alexandra Hollingsworth",
KeyGeneration: 2,
VaultGrantState.Active,
OwnerId,
DateTimeOffset.UnixEpoch,
RevokedAt: null),
// A generation behind, so the "stale" phrasing is the one being measured rather than
// the two-word happy case.
new VaultGrantSummary(
ColleagueId,
"bartholomew.fotheringay@dodotech.example",
"Bartholomew Fotheringay",
KeyGeneration: 1,
VaultGrantState.Active,
OwnerId,
DateTimeOffset.UnixEpoch,
RevokedAt: null),
]));
///
public Task CreateTeamAsync(
CreateTeamRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task UpdateTeamAsync(
Guid teamId,
UpdateTeamRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task ArchiveTeamAsync(Guid teamId, CancellationToken cancellationToken) =>
throw new NotSupportedException();
///
public Task TransferTeamOwnershipAsync(
Guid teamId,
TransferTeamOwnershipRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task AddTeamMemberAsync(
Guid teamId,
AddTeamMemberRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task ChangeTeamMemberRoleAsync(
Guid teamId,
Guid userId,
ChangeTeamMemberRoleRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task RemoveTeamMemberAsync(
Guid teamId,
Guid userId,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task CreateTeamInvitationAsync(
Guid teamId,
CreateTeamInvitationRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task RevokeTeamInvitationAsync(
Guid teamId,
Guid invitationId,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task CreateTeamVaultAsync(
Guid teamId,
CreateTeamVaultRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task IssueVaultGrantAsync(
Guid vaultId,
IssueVaultGrantRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task RevokeVaultGrantAsync(
Guid vaultId,
Guid userId,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public Task RekeyVaultAsync(
Guid vaultId,
RekeyVaultRequest request,
CancellationToken cancellationToken) => throw new NotSupportedException();
///
public void Dispose()
{
// Nothing held.
}
}