WIP, who knows man

This commit is contained in:
Jordan Dominion
2025-08-29 11:38:37 -04:00
parent 26ab854270
commit f2e797cad7
28 changed files with 116 additions and 207 deletions
@@ -43,10 +43,10 @@ query ReadCurrentUser {
canSetOnline
}
}
# Needs https://github.com/ChilliCream/graphql-platform/issues/8313
# createdBy {
# id
# name
createdById # Need https://github.com/ChilliCream/graphql-platform/issues/8313 to remove
createdBy {
id
name
}
}
}
@@ -18,7 +18,6 @@ namespace Tgstation.Server.Host.Authority.Core
/// <typeparam name="TResult">The transformed result <see cref="Type"/>.</typeparam>
public sealed class Projectable<TQueried, TResult>
where TQueried : EntityId
where TResult : notnull
{
/// <summary>
/// The underlying <see cref="IQueryable{T}"/>. Should only select one entity.
@@ -195,7 +194,8 @@ namespace Tgstation.Server.Host.Authority.Core
public async ValueTask<AuthorityResponse<TResult>> Resolve(Func<IQueryable<TQueried>, IQueryable<ProjectedPair<TQueried, TResult>>> projection)
{
ArgumentNullException.ThrowIfNull(projection);
var finalQueryable = projection(query)
var projectedQueryable = projection(query);
var finalQueryable = projectedQueryable
.Select(selector);
var selection = await finalQueryable
.FirstOrDefaultAsync(cancellationToken);
@@ -257,7 +257,7 @@ namespace Tgstation.Server.Host.Authority
Logger.LogDebug("User ID {userId}'s password hash needs a refresh, updating database.", user.Id);
var updatedUser = new User
{
Id = user.Id,
Id = user.Require(x => x.Id),
};
DatabaseContext.Users.Attach(updatedUser);
updatedUser.PasswordHash = user.PasswordHash;
@@ -326,7 +326,7 @@ namespace Tgstation.Server.Host.Components.Chat
if (originalChatBot != null)
activeChatBots.Remove(originalChatBot);
activeChatBots.Add(new Models.ChatBot(newSettings.Channels)
activeChatBots.Add(new Models.ChatBot
{
Id = newSettings.Id,
ConnectionString = newSettings.ConnectionString,
@@ -334,6 +334,7 @@ namespace Tgstation.Server.Host.Components.Chat
Name = newSettings.Name,
ReconnectionInterval = newSettings.ReconnectionInterval,
Provider = newSettings.Provider,
Channels = newSettings.Channels,
});
}
@@ -81,7 +81,7 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
#pragma warning disable CA1506
public async ValueTask<MessageContent> Invoke(string arguments, ChatUser user, CancellationToken cancellationToken)
{
IEnumerable<Models.TestMerge> results;
IEnumerable<(int Number, string TargetCommitSha)> results;
var splits = arguments.Split(' ');
var hasRepo = splits.Any(x => x.Equals("--repo", StringComparison.OrdinalIgnoreCase));
var hasStaged = splits.Any(x => x.Equals("--staged", StringComparison.OrdinalIgnoreCase));
@@ -114,17 +114,22 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
results = null!;
await databaseContextFactory.UseContext(
async db => results = await db
.RevisionInformations
.Where(x => x.Instance!.Id == instance.Id && x.CommitSha == head)
.SelectMany(x => x.ActiveTestMerges!)
.Select(x => x.TestMerge)
.Select(x => new Models.TestMerge
{
Number = x.Number,
TargetCommitSha = x.TargetCommitSha,
})
.ToListAsync(cancellationToken));
async db =>
{
var anonResults = await db
.RevisionInformations
.Where(x => x.Instance!.Id == instance.Id && x.CommitSha == head)
.SelectMany(x => x.ActiveTestMerges!)
.Select(x => x.TestMerge)
.Select(x => new
{
x.Number,
TargetCommitSha = x.TargetCommitSha!,
})
.ToListAsync(cancellationToken);
results = anonResults
.Select(anonResult => (anonResult.Number, anonResult.TargetCommitSha));
});
}
else if (watchdog.Status == WatchdogStatus.Offline)
return new MessageContent
@@ -143,7 +148,12 @@ namespace Tgstation.Server.Host.Components.Chat.Commands
compileJobToUse = null;
}
results = compileJobToUse?.RevisionInformation.ActiveTestMerges?.Select(x => x.TestMerge).ToList() ?? Enumerable.Empty<Models.TestMerge>();
results = compileJobToUse
?.RevisionInformation
.ActiveTestMerges
?.Select(x => (x.TestMerge.Number, TargetCommitSha: x.TestMerge.TargetCommitSha!))
.ToList()
?? Enumerable.Empty<(int Number, string TargetCommitSha)>();
}
return new MessageContent
@@ -86,7 +86,7 @@ namespace Tgstation.Server.Host.Components.Deployment
readonly CancellationTokenSource lockLogCts;
/// <summary>
/// Map of <see cref="CompileJob.JobId"/>s to locks on them.
/// Map of <see cref="CompileJob"/>s <see cref="Job"/> <see cref="EntityId.Id"/> to locks on them.
/// </summary>
readonly Dictionary<long, DeploymentLockManager> jobLockManagers;
@@ -315,10 +315,7 @@ namespace Tgstation.Server.Host.Components.Deployment
CommitSha = repoSha,
Timestamp = await repo.TimestampCommit(repoSha, cancellationToken),
OriginCommitSha = repoSha,
Instance = new Models.Instance
{
Id = metadata.Id,
},
InstanceId = metadata.Require(x => x.Id),
ActiveTestMerges = new List<RevInfoTestMerge>(),
};
@@ -335,6 +332,7 @@ namespace Tgstation.Server.Host.Components.Deployment
}
});
var notNullRevInfo = revInfo!;
Models.CompileJob? oldCompileJob;
using (repo)
{
@@ -346,7 +344,7 @@ namespace Tgstation.Server.Host.Components.Deployment
compileJob = await Compile(
job,
oldCompileJob,
revInfo!,
notNullRevInfo,
dreamMakerSettings!,
ddSettings!,
repo!,
@@ -367,7 +365,7 @@ namespace Tgstation.Server.Host.Components.Deployment
var fullRevInfo = compileJob.RevisionInformation;
compileJob.RevisionInformation = new Models.RevisionInformation
{
Id = revInfo!.Id,
Id = notNullRevInfo.Id,
};
databaseContext.Jobs.Attach(compileJob.Job);
@@ -523,8 +521,11 @@ namespace Tgstation.Server.Host.Components.Deployment
repository.RemoteRepositoryName,
localCommitExistsOnRemote);
var compileJob = new Models.CompileJob(job, revisionInformation, engineLock.Version.ToString())
var compileJob = new Models.CompileJob
{
Job = job,
RevisionInformation = revisionInformation,
EngineVersion = engineLock.Version.ToString(),
DirectoryName = Guid.NewGuid(),
DmeName = dreamMakerSettings.ProjectName,
RepositoryOrigin = repository.Origin.ToString(),
@@ -18,9 +18,10 @@ namespace Tgstation.Server.Host.Extensions
/// <typeparam name="TParent">The parent <see cref="Type"/>.</typeparam>
/// <typeparam name="TChild">The child <see cref="Type"/>.</typeparam>
/// <param name="queryContext">The <see cref="QueryContext{TEntity}"/> to transform.</param>
/// <param name="fallback">A <typeparamref name="TChild"/> used in cas the <see cref="QueryContext{TEntity}.Selector"/> conversion does not yield a <typeparamref name="TChild"/>.</param>
/// <returns>A new <see cref="QueryContext{TEntity}"/> for <typeparamref name="TChild"/> that is functionally identical to the original <paramref name="queryContext"/>.</returns>
public static QueryContext<TChild> UpcastFrom<TParent, TChild>(this QueryContext<TParent> queryContext)
where TChild : TParent
public static QueryContext<TChild> UpcastFrom<TParent, TChild>(this QueryContext<TParent> queryContext, Expression<Func<TChild>> fallback)
where TChild : class, TParent
{
ArgumentNullException.ThrowIfNull(queryContext);
@@ -28,13 +29,14 @@ namespace Tgstation.Server.Host.Extensions
Expression<Func<TChild, TChild>>? selector = null;
if (queryContext.Selector != null)
{
Expression<Func<TParent, TChild>> upcast = parent => (TChild)parent!;
Expression<Func<TParent, Func<TChild>, TChild>> upcast = (parent, fallback) => (parent as TChild) ?? fallback();
selector = Expression.Lambda<Func<TChild, TChild>>(
Expression.Invoke(
upcast,
Expression.Invoke(
queryContext.Selector,
parameter)),
parameter),
fallback),
parameter);
}
@@ -25,7 +25,7 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// A user registered in the server.
/// </summary>
[Node]
public sealed class User : UserName
public sealed class User : NamedEntity, IUserName
{
/// <inheritdoc />
[IsProjected(true)]
@@ -133,16 +133,24 @@ namespace Tgstation.Server.Host.GraphQL.Types
ArgumentNullException.ThrowIfNull(userAuthority);
// This one is particular and cannot be data-loaded due to necessitating a different parameter
var user = await userAuthority.InvokeTransformable<Models.User, User, UserTransformer>(
authority => authority.GetId<User>(CreatedById, true, cancellationToken),
queryContext?.UpcastFrom<IUserName, User>());
if (user == null)
throw new InvalidOperationException($"Query for created by of user ID {CreatedById} returned null!");
try
{
var temp = (User)null!;
var user = await userAuthority.InvokeTransformable<Models.User, User, UserTransformer>(
authority => authority.GetId<User>(CreatedById, true, cancellationToken),
queryContext?.UpcastFrom(() => temp));
if (user == null)
throw new InvalidOperationException($"Query for created by of user ID {CreatedById} returned null!");
if (user.CanonicalName == Models.User.CanonicalizeName(Models.User.TgsSystemUserName))
return new UserName(user);
if (user.CanonicalName == Models.User.CanonicalizeName(Models.User.TgsSystemUserName))
return new UserName(user);
return user;
return user;
}
catch
{
throw;
}
}
/// <summary>
+3 -23
View File
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Linq;
using Tgstation.Server.Api.Models.Response;
@@ -23,30 +21,12 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The parent <see cref="Models.Instance"/>.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <summary>
/// See <see cref="Api.Models.Internal.ChatBotApiBase.Channels"/>.
/// </summary>
public ICollection<ChatChannel> Channels { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ChatBot"/> class.
/// </summary>
public ChatBot()
: this(new List<ChatChannel>())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ChatBot"/> class.
/// </summary>
/// <param name="channels">The value of <see cref="Channels"/>.</param>
public ChatBot(ICollection<ChatChannel> channels)
{
Channels = channels ?? throw new ArgumentNullException(nameof(channels));
}
public ICollection<ChatChannel> Channels { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public ChatBotResponse ToApi() => new()
@@ -33,7 +33,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="ChatBot"/>.
/// </summary>
public ChatBot? ChatSettings { get; set; }
public ChatBot ChatSettings { get; set; } = null!; // recommended by EF
/// <summary>
/// Convert to a <see cref="Api.Models.ChatChannel"/>.
+5 -51
View File
@@ -1,7 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Response;
namespace Tgstation.Server.Host.Models
@@ -12,25 +10,22 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// See <see cref="CompileJobResponse.Job"/>.
/// </summary>
[Required]
public Job Job { get; set; }
public required Job Job { get; set; }
/// <summary>
/// The <see cref="EntityId.Id"/> of <see cref="Job"/>.
/// The <see cref="Api.Models.EntityId.Id"/> of <see cref="Job"/>.
/// </summary>
public long JobId { get; set; }
public long JobId { get; set; } // Needed to determine the dependent side of the FK relationship
/// <summary>
/// See <see cref="CompileJobResponse.RevisionInformation"/>.
/// </summary>
[Required]
public RevisionInformation RevisionInformation { get; set; }
public required RevisionInformation RevisionInformation { get; set; }
/// <summary>
/// The <see cref="Version"/> the <see cref="CompileJob"/> was made with in string form.
/// </summary>
[Required]
public string EngineVersion { get; set; }
public required string EngineVersion { get; set; }
/// <summary>
/// Backing field for <see cref="Version.Major"/> of <see cref="DMApiVersion"/>.
@@ -81,47 +76,6 @@ namespace Tgstation.Server.Host.Models
}
}
/// <summary>
/// Initializes a new instance of the <see cref="CompileJob"/> class.
/// </summary>
[Obsolete("For use by EFCore only", true)]
public CompileJob()
: this(null!, null!, null!, false)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CompileJob"/> class.
/// </summary>
/// <param name="job">The value of <see cref="Job"/>.</param>
/// <param name="revisionInformation">The value of <see cref="RevisionInformation"/>.</param>
/// <param name="engineVersion">The value of <see cref="EngineVersion"/>.</param>
public CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion)
: this(job, revisionInformation, engineVersion, true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CompileJob"/> class.
/// </summary>
/// <param name="job">The value of <see cref="Job"/>.</param>
/// <param name="revisionInformation">The value of <see cref="RevisionInformation"/>.</param>
/// <param name="engineVersion">The value of <see cref="EngineVersion"/>.</param>
/// <param name="nullChecks">If <paramref name="job"/>, <paramref name="revisionInformation"/>, and <paramref name="engineVersion"/> should be checked for nulls.</param>
CompileJob(Job job, RevisionInformation revisionInformation, string engineVersion, bool nullChecks)
{
if (nullChecks)
{
ArgumentNullException.ThrowIfNull(job);
ArgumentNullException.ThrowIfNull(revisionInformation);
ArgumentNullException.ThrowIfNull(engineVersion);
}
Job = job;
RevisionInformation = revisionInformation;
EngineVersion = engineVersion;
}
/// <inheritdoc />
public CompileJobResponse ToApi() => new()
{
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
namespace Tgstation.Server.Host.Models
{
/// <inheritdoc />
public sealed class DreamDaemonSettings : Api.Models.Internal.DreamDaemonSettings
@@ -18,7 +16,6 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The parent <see cref="Models.Instance"/>.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
}
}
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Api.Models.Response;
namespace Tgstation.Server.Host.Models
{
@@ -20,8 +18,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The parent <see cref="Models.Instance"/>.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public DreamMakerResponse ToApi() => new()
+7 -18
View File
@@ -17,17 +17,17 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.DreamMakerSettings"/> for the <see cref="Instance"/>.
/// </summary>
public DreamMakerSettings? DreamMakerSettings { get; set; }
public DreamMakerSettings DreamMakerSettings { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Models.DreamDaemonSettings"/> for the <see cref="Instance"/>.
/// </summary>
public DreamDaemonSettings? DreamDaemonSettings { get; set; }
public DreamDaemonSettings DreamDaemonSettings { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Models.RepositorySettings"/> for the <see cref="Instance"/>.
/// </summary>
public RepositorySettings? RepositorySettings { get; set; }
public RepositorySettings RepositorySettings { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Api.Models.Internal.SwarmServer.Identifier"/> of the the server in the swarm this instance belongs to.
@@ -37,33 +37,22 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="InstancePermissionSet"/>s in the <see cref="Instance"/>.
/// </summary>
public ICollection<InstancePermissionSet> InstancePermissionSets { get; set; }
public ICollection<InstancePermissionSet> InstancePermissionSets { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="ChatBot"/>s for the <see cref="Instance"/>.
/// </summary>
public ICollection<ChatBot> ChatSettings { get; set; }
public ICollection<ChatBot> ChatSettings { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="RevisionInformation"/>s in the <see cref="Instance"/>.
/// </summary>
public ICollection<RevisionInformation> RevisionInformations { get; set; }
public ICollection<RevisionInformation> RevisionInformations { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Job"/>s in the <see cref="Instance"/>.
/// </summary>
public ICollection<Job> Jobs { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Instance"/> class.
/// </summary>
public Instance()
{
InstancePermissionSets = new List<InstancePermissionSet>();
ChatSettings = new List<ChatBot>();
RevisionInformations = new List<RevisionInformation>();
Jobs = new List<Job>();
}
public ICollection<Job> Jobs { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public InstanceResponse ToApi() => new()
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Api.Models.Response;
namespace Tgstation.Server.Host.Models
{
@@ -20,14 +18,12 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.Instance"/> the <see cref="InstancePermissionSet"/> belongs to.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Models.PermissionSet"/> the <see cref="InstancePermissionSet"/> belongs to.
/// </summary>
[Required]
public PermissionSet? PermissionSet { get; set; }
public PermissionSet PermissionSet { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public InstancePermissionSetResponse ToApi() => new()
+3 -6
View File
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Tgstation.Server.Api.Models;
@@ -17,8 +16,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// See <see cref="JobResponse.StartedBy"/>.
/// </summary>
[Required]
public User? StartedBy { get; set; }
public User StartedBy { get; set; } = null!; // recommended by EF
/// <summary>
/// See <see cref="JobResponse.CancelledBy"/>.
@@ -28,8 +26,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.Instance"/> the job belongs to if any.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <summary>
/// Creates a new job for registering in the <see cref="Jobs.IJobService"/>.
@@ -91,7 +88,7 @@ namespace Tgstation.Server.Host.Models
/// <param name="cancelRight">The value of <see cref="Api.Models.Internal.Job.CancelRight"/>.</param>
Job(JobCode code, User? startedBy, Api.Models.Instance instance, RightsType? cancelRightsType, ulong? cancelRight)
{
StartedBy = startedBy;
StartedBy = startedBy!; // allowed to be null here, set to TGS user if so later
ArgumentNullException.ThrowIfNull(instance);
Instance = new Instance
{
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
namespace Tgstation.Server.Host.Models
{
/// <inheritdoc cref="Api.Models.OAuthConnection" />
public sealed class OAuthConnection : Api.Models.OAuthConnection,
@@ -19,8 +17,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The owning <see cref="Models.User"/>.
/// </summary>
[Required]
public User? User { get; set; }
public User User { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public Api.Models.OAuthConnection ToApi() => new()
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Models
/// The owning <see cref="Models.User"/>.
/// </summary>
[Required]
public User? User { get; set; }
public User User { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public Api.Models.OidcConnection ToApi() => new()
@@ -28,7 +28,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="InstancePermissionSet"/>s associated with the <see cref="PermissionSet"/>.
/// </summary>
public ICollection<InstancePermissionSet>? InstancePermissionSets { get; set; }
public ICollection<InstancePermissionSet> InstancePermissionSets { get; set; } = null!; // recommended by EF
/// <summary>
/// Convert the <see cref="PermissionSet"/> to it's API form.
@@ -1,5 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
{
@@ -11,8 +10,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.CompileJob"/> for the <see cref="Components.Session.ReattachInformation.Dmb"/>.
/// </summary>
[Required]
public CompileJob? CompileJob { get; set; }
public CompileJob CompileJob { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Api.Models.EntityId.Id"/> of <see cref="CompileJob"/>.
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Models.Response;
using Tgstation.Server.Api.Models.Response;
namespace Tgstation.Server.Host.Models
{
@@ -20,8 +18,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The parent <see cref="Models.Instance"/>.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public RepositoryResponse ToApi() => new()
@@ -1,5 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
{
@@ -16,14 +15,12 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.TestMerge"/>.
/// </summary>
[Required]
public TestMerge TestMerge { get; set; }
public TestMerge TestMerge { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="Models.RevisionInformation"/>.
/// </summary>
[Required]
public RevisionInformation RevisionInformation { get; set; }
public RevisionInformation RevisionInformation { get; set; } = null!; // recommended by EF
/// <summary>
/// Initializes a new instance of the <see cref="RevInfoTestMerge"/> class.
@@ -31,8 +28,6 @@ namespace Tgstation.Server.Host.Models
[Obsolete("For use by EFCore only", true)]
public RevInfoTestMerge()
{
TestMerge = null!;
RevisionInformation = null!;
}
/// <summary>
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Tgstation.Server.Host.Models
@@ -21,8 +20,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.Instance"/> the <see cref="RevisionInformation"/> belongs to.
/// </summary>
[Required]
public Instance? Instance { get; set; }
public Instance Instance { get; set; } = null!; // recommended by EF
/// <summary>
/// See <see cref="Api.Models.RevisionInformation.PrimaryTestMerge"/>.
@@ -32,12 +30,12 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// See <see cref="Api.Models.RevisionInformation.ActiveTestMerges"/>.
/// </summary>
public ICollection<RevInfoTestMerge>? ActiveTestMerges { get; set; }
public ICollection<RevInfoTestMerge> ActiveTestMerges { get; set; } = null!; // recommended by EF
/// <summary>
/// See <see cref="CompileJob"/>s made from this <see cref="RevisionInformation"/>.
/// </summary>
public ICollection<CompileJob>? CompileJobs { get; set; }
public ICollection<CompileJob> CompileJobs { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public Api.Models.RevisionInformation ToApi() => new()
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
{
@@ -10,24 +9,22 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// See <see cref="Api.Models.TestMerge.MergedBy"/>.
/// </summary>
[Required]
public User? MergedBy { get; set; }
public User MergedBy { get; set; } = null!; // recommended by EF
/// <summary>
/// The initial <see cref="RevisionInformation"/> the <see cref="TestMerge"/> was merged with.
/// </summary>
[Required]
public RevisionInformation? PrimaryRevisionInformation { get; set; }
public RevisionInformation PrimaryRevisionInformation { get; set; } = null!; // recommended by EF
/// <summary>
/// Foreign key for <see cref="PrimaryRevisionInformation"/>.
/// </summary>
public long? PrimaryRevisionInformationId { get; set; }
public long PrimaryRevisionInformationId { get; set; }
/// <summary>
/// All the <see cref="RevInfoTestMerge"/> for the <see cref="TestMerge"/>.
/// </summary>
public ICollection<RevInfoTestMerge>? RevisonInformations { get; set; }
public ICollection<RevInfoTestMerge> RevisonInformations { get; set; } = null!; // recommended by EF
/// <inheritdoc />
public Api.Models.TestMerge ToApi() => new()
+5 -6
View File
@@ -48,9 +48,8 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The uppercase invariant of <see cref="UserName.Name"/>.
/// </summary>
[Required]
[StringLength(Limits.MaximumIndexableStringLength, MinimumLength = 1)]
public string? CanonicalName { get; set; }
public string CanonicalName { get; set; } = null!; // recommended by EF
/// <summary>
/// When <see cref="PasswordHash"/> was last changed.
@@ -60,22 +59,22 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// <see cref="User"/>s created by this <see cref="User"/>.
/// </summary>
public ICollection<User>? CreatedUsers { get; set; }
public ICollection<User> CreatedUsers { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="TestMerge"/>s made by the <see cref="User"/>.
/// </summary>
public ICollection<TestMerge>? TestMerges { get; set; }
public ICollection<TestMerge> TestMerges { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="OAuthConnection"/>s for the <see cref="User"/>.
/// </summary>
public ICollection<OAuthConnection>? OAuthConnections { get; set; }
public ICollection<OAuthConnection> OAuthConnections { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="OidcConnection"/>s for the <see cref="User"/>.
/// </summary>
public ICollection<OidcConnection>? OidcConnections { get; set; }
public ICollection<OidcConnection> OidcConnections { get; set; } = null!; // recommended by EF
/// <summary>
/// Change a <see cref="UserName.Name"/> into a <see cref="CanonicalName"/>.
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Tgstation.Server.Api.Models;
@@ -16,13 +15,12 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The <see cref="Models.PermissionSet"/> the <see cref="UserGroup"/> has.
/// </summary>
[Required]
public PermissionSet? PermissionSet { get; set; }
public required PermissionSet PermissionSet { get; set; } = null!; // recommended by EF
/// <summary>
/// The <see cref="User"/>s the <see cref="UserGroup"/> has.
/// </summary>
public required ICollection<User> Users { get; set; }
public required ICollection<User> Users { get; set; } = null!; // recommended by EF
/// <summary>
/// Convert the <see cref="UserGroup"/> to it's API form.
@@ -83,8 +83,7 @@ namespace Tgstation.Server.Tests.Live
&& restResult.Name == gqlUser.Name
&& (restResult.CreatedAt.Value.Ticks / 10000) == (gqlUser.CreatedAt.Ticks / 10000)
&& restResult.SystemIdentifier == gqlUser.SystemIdentifier
// && restResult.CreatedBy.Name == gqlUser.CreatedBy.Name // Needs https://github.com/ChilliCream/graphql-platform/issues/8313
;
&& restResult.CreatedBy.Name == gqlUser.CreatedBy.Name;
},
cancellationToken);
@@ -270,9 +269,8 @@ namespace Tgstation.Server.Tests.Live
// Assert.AreEqual(Math.Min(ApiController.DefaultPageSize, users.TotalCount), users.Nodes.Count);
Assert.IsTrue(Math.Min(ApiController.DefaultPageSize, users.TotalCount) >= users.Nodes.Count);
// Needs https://github.com/ChilliCream/graphql-platform/issues/8313
// var tgsUserResult2 = await client.RunOperation(gql => gql.GetUserById.ExecuteAsync(gqlUser.Swarm.Users.Current.CreatedBy.Id, cancellationToken), cancellationToken);
// Assert.IsTrue(tgsUserResult2.IsErrorResult());
var tgsUserResult2 = await client.RunOperation(gql => gql.GetUserById.ExecuteAsync(gqlUser.Swarm.Users.Current.CreatedBy.Id, cancellationToken), cancellationToken);
Assert.IsTrue(tgsUserResult2.IsErrorResult());
var sampleOAuthConnections = new List<OAuthConnectionInput>
{