diff --git a/docs/API.dox b/docs/API.dox index 5361caf7db..af9deb1ebe 100644 --- a/docs/API.dox +++ b/docs/API.dox @@ -212,11 +212,15 @@ Some requests return @ref Tgstation.Server.Api.Models.Job objects. These are lon To list all jobs in an Instance use the following request -I GET "/Job" => Array of @ref Tgstation.Server.Api.Models.Job +I GET "/Job/List" => Array of @ref Tgstation.Server.Api.Models.Job Note that the response for this request will only have the @ref Tgstation.Server.Api.Models.Job.Id field populated -To get full details of a job use the following request: +To get full details of _active_ jobs use the following request: + +I GET "/Job" => Array of @ref Tgstation.Server.Api.Models.Job + +To get full details of a specific job use the following request: I GET "/Job/{JobId}" => @ref Tgstation.Server.Api.Models.Job diff --git a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs index 6f546020aa..84c93c4cb3 100644 --- a/src/Tgstation.Server.Api/Rights/AdministrationRights.cs +++ b/src/Tgstation.Server.Api/Rights/AdministrationRights.cs @@ -13,9 +13,9 @@ namespace Tgstation.Server.Api.Rights /// None = 0, /// - /// User can edit themself and other s + /// User can edit themself and other s and also create others /// - EditUsers = 1, + WriteUsers = 1, /// /// User can gracefully restart the host /// @@ -27,6 +27,10 @@ namespace Tgstation.Server.Api.Rights /// /// User can change their password /// - EditPassword = 8, + EditOwnPassword = 8, + /// + /// User can read info and rights of other users + /// + ReadUsers = 16 } } diff --git a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs index 884a42a475..439a13d81c 100644 --- a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs +++ b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs @@ -35,6 +35,6 @@ namespace Tgstation.Server.Api.Rights /// /// User may list and read all s /// - List = 32 + CompileJobs = 32 } } diff --git a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs index c424d4ac95..552af89b45 100644 --- a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs +++ b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs @@ -47,10 +47,6 @@ namespace Tgstation.Server.Api.Rights /// /// User can change /// - SetAutoUpdate = 256, - /// - /// User can cancel move operations - /// - CancelMove = 512, + SetAutoUpdate = 256 } } diff --git a/src/Tgstation.Server.Api/Rights/InstanceUserRights.cs b/src/Tgstation.Server.Api/Rights/InstanceUserRights.cs index 841e39fa64..b3860cc36d 100644 --- a/src/Tgstation.Server.Api/Rights/InstanceUserRights.cs +++ b/src/Tgstation.Server.Api/Rights/InstanceUserRights.cs @@ -17,8 +17,12 @@ namespace Tgstation.Server.Api.Rights /// ReadUsers = 1, /// - /// Allow write access to for the + /// Allow write and delete access to for the /// - WriteUsers = 2 + WriteUsers = 2, + /// + /// Allow adding additional to the + /// + CreateUsers = 4 } } diff --git a/src/Tgstation.Server.Api/Rights/RepositoryRights.cs b/src/Tgstation.Server.Api/Rights/RepositoryRights.cs index 83968e7adb..2729f72ae0 100644 --- a/src/Tgstation.Server.Api/Rights/RepositoryRights.cs +++ b/src/Tgstation.Server.Api/Rights/RepositoryRights.cs @@ -13,6 +13,10 @@ namespace Tgstation.Server.Api.Rights /// None = 0, /// + /// User may cancel synchronize operations + /// + CancelPendingChanges = 1, + /// /// User may create the if it does not exist /// SetOrigin = 2, @@ -59,10 +63,6 @@ namespace Tgstation.Server.Api.Rights /// /// User may cancel clone operations /// - CancelClone = 4096, - /// - /// User may cancel synchronize operations - /// - CancelPendingChanges = 8192 + CancelClone = 4096 } } diff --git a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj index cd29816873..235cd27951 100644 --- a/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj +++ b/src/Tgstation.Server.Api/Tgstation.Server.Api.csproj @@ -17,7 +17,7 @@ 4.0.0.0 json web api tgstation-server tgstation ss13 byond Prototype release - 4.0.0.0-preview3 + 4.0.0.0-preview4 @@ -35,7 +35,10 @@ - + + all + compile; build; native; contentfiles; analyzers + diff --git a/src/Tgstation.Server.Client/AdministrationClient.cs b/src/Tgstation.Server.Client/AdministrationClient.cs index 617a925e4e..1e7b290168 100644 --- a/src/Tgstation.Server.Client/AdministrationClient.cs +++ b/src/Tgstation.Server.Client/AdministrationClient.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; @@ -26,7 +27,7 @@ namespace Tgstation.Server.Client public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.Administration, cancellationToken); /// - public Task Update(Administration administration, CancellationToken cancellationToken) => apiClient.Update(Routes.Administration, administration, cancellationToken); + public Task Update(Administration administration, CancellationToken cancellationToken) => apiClient.Update(Routes.Administration, administration ?? throw new ArgumentNullException(nameof(administration)), cancellationToken); /// public Task Restart(CancellationToken cancellationToken) => apiClient.Delete(Routes.Administration, cancellationToken); diff --git a/src/Tgstation.Server.Client/Components/ByondClient.cs b/src/Tgstation.Server.Client/Components/ByondClient.cs index ec311873c7..e75c47110c 100644 --- a/src/Tgstation.Server.Client/Components/ByondClient.cs +++ b/src/Tgstation.Server.Client/Components/ByondClient.cs @@ -33,6 +33,6 @@ namespace Tgstation.Server.Client.Components public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.Byond, instance.Id, cancellationToken); /// - public Task Update(Byond byond, CancellationToken cancellationToken) => apiClient.Update(Routes.Byond, byond, instance.Id, cancellationToken); + public Task Update(Byond byond, CancellationToken cancellationToken) => apiClient.Update(Routes.Byond, byond ?? throw new ArgumentNullException(nameof(byond)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/ChatBotsClient.cs b/src/Tgstation.Server.Client/Components/ChatBotsClient.cs index b9fc623102..73cdd02680 100644 --- a/src/Tgstation.Server.Client/Components/ChatBotsClient.cs +++ b/src/Tgstation.Server.Client/Components/ChatBotsClient.cs @@ -31,15 +31,15 @@ namespace Tgstation.Server.Client.Components } /// - public Task Create(ChatBot settings, CancellationToken cancellationToken) => apiClient.Create(Routes.Chat, settings, instance.Id, cancellationToken); + public Task Create(ChatBot settings, CancellationToken cancellationToken) => apiClient.Create(Routes.Chat, settings ?? throw new ArgumentNullException(nameof(settings)), instance.Id, cancellationToken); /// - public Task Delete(ChatBot settings, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.Chat, settings.Id), instance.Id, cancellationToken); + public Task Delete(ChatBot settings, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.Chat, settings?.Id ?? throw new ArgumentNullException(nameof(settings))), instance.Id, cancellationToken); /// public Task> List(CancellationToken cancellationToken) => apiClient.Create>(Routes.List(Routes.Chat), instance.Id, cancellationToken); /// - public Task Update(ChatBot settings, CancellationToken cancellationToken) => apiClient.Update(Routes.Chat, settings, instance.Id, cancellationToken); + public Task Update(ChatBot settings, CancellationToken cancellationToken) => apiClient.Update(Routes.Chat, settings ?? throw new ArgumentNullException(nameof(settings)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/ConfigurationClient.cs b/src/Tgstation.Server.Client/Components/ConfigurationClient.cs index 6eac9582bc..4f35d86321 100644 --- a/src/Tgstation.Server.Client/Components/ConfigurationClient.cs +++ b/src/Tgstation.Server.Client/Components/ConfigurationClient.cs @@ -47,6 +47,6 @@ namespace Tgstation.Server.Client.Components } /// - public Task Write(ConfigurationFile file, CancellationToken cancellationToken) => apiClient.Update(Routes.Configuration, file, instance.Id, cancellationToken); + public Task Write(ConfigurationFile file, CancellationToken cancellationToken) => apiClient.Update(Routes.Configuration, file ?? throw new ArgumentNullException(nameof(file)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/DreamDaemonClient.cs b/src/Tgstation.Server.Client/Components/DreamDaemonClient.cs index d776c09f69..e0815a873b 100644 --- a/src/Tgstation.Server.Client/Components/DreamDaemonClient.cs +++ b/src/Tgstation.Server.Client/Components/DreamDaemonClient.cs @@ -39,6 +39,6 @@ namespace Tgstation.Server.Client.Components public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.DreamDaemon, instance.Id, cancellationToken); /// - public Task Update(DreamDaemon dreamDaemon, CancellationToken cancellationToken) => apiClient.Update(Routes.DreamDaemon, dreamDaemon, instance.Id, cancellationToken); + public Task Update(DreamDaemon dreamDaemon, CancellationToken cancellationToken) => apiClient.Update(Routes.DreamDaemon, dreamDaemon ?? throw new ArgumentNullException(nameof(dreamDaemon)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/DreamMakerClient.cs b/src/Tgstation.Server.Client/Components/DreamMakerClient.cs index ae331617e2..5e8d2af1b9 100644 --- a/src/Tgstation.Server.Client/Components/DreamMakerClient.cs +++ b/src/Tgstation.Server.Client/Components/DreamMakerClient.cs @@ -36,6 +36,6 @@ namespace Tgstation.Server.Client.Components public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.DreamMaker, instance.Id, cancellationToken); /// - public Task Update(DreamMaker dreamMaker, CancellationToken cancellationToken) => apiClient.Update(Routes.DreamMaker, dreamMaker, instance.Id, cancellationToken); + public Task Update(DreamMaker dreamMaker, CancellationToken cancellationToken) => apiClient.Update(Routes.DreamMaker, dreamMaker ?? throw new ArgumentNullException(nameof(dreamMaker)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/IInstanceUserClient.cs b/src/Tgstation.Server.Client/Components/IInstanceUserClient.cs index 5d73e4f2ee..3d1d54e8d7 100644 --- a/src/Tgstation.Server.Client/Components/IInstanceUserClient.cs +++ b/src/Tgstation.Server.Client/Components/IInstanceUserClient.cs @@ -17,6 +17,14 @@ namespace Tgstation.Server.Client.Components /// A resulting in the associated with the logged on user Task Read(CancellationToken cancellationToken); + /// + /// Get a specific + /// + /// The to get + /// The for the operation + /// A resulting in the requested + Task GetId(InstanceUser instanceUser, CancellationToken cancellationToken); + /// /// Get the s in the /// diff --git a/src/Tgstation.Server.Client/Components/IJobsClient.cs b/src/Tgstation.Server.Client/Components/IJobsClient.cs index 0b659841e9..c59dc7a8ba 100644 --- a/src/Tgstation.Server.Client/Components/IJobsClient.cs +++ b/src/Tgstation.Server.Client/Components/IJobsClient.cs @@ -18,13 +18,20 @@ namespace Tgstation.Server.Client.Components /// A resulting in a of the s in the Task> List(CancellationToken cancellationToken); + /// + /// List the active s in the + /// + /// The for the operation + /// A resulting in a of the active s in the + Task> ListActive(CancellationToken cancellationToken); + /// /// Get a /// /// The to get /// The for the operation /// A resulting in the - Task Read(Job job, CancellationToken cancellationToken); + Task GetId(Job job, CancellationToken cancellationToken); /// /// Cancels a @@ -40,7 +47,7 @@ namespace Tgstation.Server.Client.Components /// The to create a for /// The rate in to poll the server for results /// A to run with 0-100 progress - /// The which will trigger the cancellation of the + /// The for the operation. This does not cancel the /// A resulting in a complete Task CreateTaskFromJob(Job job, TimeSpan requeryRate, Action progressCallback, CancellationToken cancellationToken); } diff --git a/src/Tgstation.Server.Client/Components/InstanceUserClient.cs b/src/Tgstation.Server.Client/Components/InstanceUserClient.cs index a45453a1fd..c3ceeca108 100644 --- a/src/Tgstation.Server.Client/Components/InstanceUserClient.cs +++ b/src/Tgstation.Server.Client/Components/InstanceUserClient.cs @@ -31,7 +31,7 @@ namespace Tgstation.Server.Client.Components } /// - public Task Create(InstanceUser user, CancellationToken cancellationToken) => apiClient.Create(Routes.InstanceUser, user, instance.Id, cancellationToken); + public Task Create(InstanceUser instanceUser, CancellationToken cancellationToken) => apiClient.Create(Routes.InstanceUser, instanceUser ?? throw new ArgumentNullException(nameof(instanceUser)), instance.Id, cancellationToken); public Task Delete(InstanceUser instanceUser, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.InstanceUser, instanceUser.UserId.Value), instance.Id, cancellationToken); @@ -39,9 +39,12 @@ namespace Tgstation.Server.Client.Components public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.InstanceUser, instance.Id, cancellationToken); /// - public Task Update(InstanceUser user, CancellationToken cancellationToken) => apiClient.Update(Routes.InstanceUser, user, instance.Id, cancellationToken); + public Task Update(InstanceUser instanceUser, CancellationToken cancellationToken) => apiClient.Update(Routes.InstanceUser, instanceUser ?? throw new ArgumentNullException(nameof(instanceUser)), instance.Id, cancellationToken); /// public Task> List(CancellationToken cancellationToken) => apiClient.Read>(Routes.List(Routes.InstanceUser), instance.Id, cancellationToken); + + /// + public Task GetId(InstanceUser instanceUser, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.InstanceUser, instanceUser?.UserId ?? throw new ArgumentNullException(nameof(instanceUser))), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/Components/JobsClient.cs b/src/Tgstation.Server.Client/Components/JobsClient.cs index c4f08dca91..7f9bf1cfa5 100644 --- a/src/Tgstation.Server.Client/Components/JobsClient.cs +++ b/src/Tgstation.Server.Client/Components/JobsClient.cs @@ -31,25 +31,30 @@ namespace Tgstation.Server.Client.Components } /// - public Task Cancel(Job job, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.Jobs, job.Id), instance.Id, cancellationToken); + public Task Cancel(Job job, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.Jobs, job?.Id ?? throw new ArgumentNullException(nameof(job))), instance.Id, cancellationToken); /// public Task> List(CancellationToken cancellationToken) => apiClient.Read>(Routes.List(Routes.Jobs), instance.Id, cancellationToken); /// - public Task Read(Job job, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.Jobs, job.Id), instance.Id, cancellationToken); + public Task> ListActive(CancellationToken cancellationToken) => apiClient.Read>(Routes.Jobs, instance.Id, cancellationToken); + + /// + public Task GetId(Job job, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.Jobs, job?.Id ?? throw new ArgumentNullException(nameof(job))), instance.Id, cancellationToken); /// public async Task CreateTaskFromJob(Job job, TimeSpan requeryRate, Action progressCallback, CancellationToken cancellationToken) { if (job == null) throw new ArgumentNullException(nameof(job)); + if (progressCallback == null) + throw new ArgumentNullException(nameof(progressCallback)); int? lastProgress = null; while (!job.StoppedAt.HasValue) { await Task.Delay(requeryRate, cancellationToken).ConfigureAwait(false); - job = await Read(job, cancellationToken).ConfigureAwait(false); + job = await GetId(job, cancellationToken).ConfigureAwait(false); if (job.Progress.HasValue && job.Progress != lastProgress) { progressCallback(job.Progress.Value); diff --git a/src/Tgstation.Server.Client/Components/RepositoryClient.cs b/src/Tgstation.Server.Client/Components/RepositoryClient.cs index 7b52a0cc1c..9232a323c9 100644 --- a/src/Tgstation.Server.Client/Components/RepositoryClient.cs +++ b/src/Tgstation.Server.Client/Components/RepositoryClient.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; @@ -35,6 +36,6 @@ namespace Tgstation.Server.Client.Components public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.Repository, instance.Id, cancellationToken); /// - public Task Update(Repository repository, CancellationToken cancellationToken) => apiClient.Update(Routes.Repository, repository, instance.Id, cancellationToken); + public Task Update(Repository repository, CancellationToken cancellationToken) => apiClient.Update(Routes.Repository, repository ?? throw new ArgumentNullException(nameof(repository)), instance.Id, cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Client/InstanceManagerClient.cs b/src/Tgstation.Server.Client/InstanceManagerClient.cs index 63b78d47af..f8343c5c91 100644 --- a/src/Tgstation.Server.Client/InstanceManagerClient.cs +++ b/src/Tgstation.Server.Client/InstanceManagerClient.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api; @@ -26,30 +27,30 @@ namespace Tgstation.Server.Client /// public InstanceManagerClient(IApiClient apiClient) { - this.apiClient = apiClient; + this.apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); cachedClients = new Dictionary(); } /// - public Task Create(Instance instance, CancellationToken cancellationToken) => apiClient.Create(Routes.InstanceManager, instance, cancellationToken); + public Task Create(Instance instance, CancellationToken cancellationToken) => apiClient.Create(Routes.InstanceManager, instance ?? throw new ArgumentNullException(nameof(instance)), cancellationToken); /// - public Task Delete(Instance instance, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.InstanceManager, instance.Id), cancellationToken); + public Task Delete(Instance instance, CancellationToken cancellationToken) => apiClient.Delete(Routes.SetID(Routes.InstanceManager, instance?.Id ?? throw new ArgumentNullException(nameof(instance))), cancellationToken); /// public Task> List(CancellationToken cancellationToken) => apiClient.Read>(Routes.List(Routes.InstanceManager), cancellationToken); /// - public Task Update(Instance instance, CancellationToken cancellationToken) => apiClient.Update(Routes.InstanceManager, instance, cancellationToken); + public Task Update(Instance instance, CancellationToken cancellationToken) => apiClient.Update(Routes.InstanceManager, instance ?? throw new ArgumentNullException(nameof(instance)), cancellationToken); /// - public Task GetId(Instance instance, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.InstanceManager, instance.Id), cancellationToken); + public Task GetId(Instance instance, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.InstanceManager, instance?.Id ?? throw new ArgumentNullException(nameof(instance))), cancellationToken); /// public IInstanceClient CreateClient(Instance instance) { - if (!cachedClients.TryGetValue(instance.Id, out var client)) + if (!cachedClients.TryGetValue(instance?.Id ?? throw new ArgumentNullException(nameof(instance)), out var client)) { client = new InstanceClient(apiClient, instance); cachedClients.Add(instance.Id, client); diff --git a/src/Tgstation.Server.Client/ServerClientFactory.cs b/src/Tgstation.Server.Client/ServerClientFactory.cs index 9e7286d1a7..b0a7d3b547 100644 --- a/src/Tgstation.Server.Client/ServerClientFactory.cs +++ b/src/Tgstation.Server.Client/ServerClientFactory.cs @@ -38,8 +38,6 @@ namespace Tgstation.Server.Client throw new ArgumentNullException(nameof(username)); if (password == null) throw new ArgumentNullException(nameof(password)); - if (timeout == null) - throw new ArgumentNullException(nameof(timeout)); Token token; using (var api = apiClientFactory.CreateApiClient(host, new ApiHeaders(productHeaderValue, username, password))) diff --git a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj index 40ffb4c446..3ac3042fca 100644 --- a/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj +++ b/src/Tgstation.Server.Client/Tgstation.Server.Client.csproj @@ -3,7 +3,7 @@ netstandard2.0 Full - 4.0.0.0-preview8 + 4.0.0.0-preview9 true Cyberboss /tg/station 13 @@ -31,6 +31,10 @@ + + all + compile; build; native; contentfiles; analyzers + diff --git a/src/Tgstation.Server.Client/UsersClient.cs b/src/Tgstation.Server.Client/UsersClient.cs index 3578731509..1e6c5fd45e 100644 --- a/src/Tgstation.Server.Client/UsersClient.cs +++ b/src/Tgstation.Server.Client/UsersClient.cs @@ -25,10 +25,10 @@ namespace Tgstation.Server.Client } /// - public Task Create(UserUpdate user, CancellationToken cancellationToken) => apiClient.Create(Routes.User, user, cancellationToken); + public Task Create(UserUpdate user, CancellationToken cancellationToken) => apiClient.Create(Routes.User, user ?? throw new ArgumentNullException(nameof(user)), cancellationToken); /// - public Task GetId(User user, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.User, user.Id), cancellationToken); + public Task GetId(User user, CancellationToken cancellationToken) => apiClient.Read(Routes.SetID(Routes.User, user?.Id ?? throw new ArgumentNullException(nameof(user))), cancellationToken); /// public Task> List(CancellationToken cancellationToken) => apiClient.Read>(Routes.List(Routes.User), cancellationToken); @@ -37,6 +37,6 @@ namespace Tgstation.Server.Client public Task Read(CancellationToken cancellationToken) => apiClient.Read(Routes.User, cancellationToken); /// - public Task Update(UserUpdate user, CancellationToken cancellationToken) => apiClient.Update(Routes.User, user, cancellationToken); + public Task Update(UserUpdate user, CancellationToken cancellationToken) => apiClient.Update(Routes.User, user ?? throw new ArgumentNullException(nameof(user)), cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj index cb7add9153..dbaae93de8 100644 --- a/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj +++ b/src/Tgstation.Server.Host.Console/Tgstation.Server.Host.Console.csproj @@ -4,6 +4,7 @@ Exe netcoreapp2.0 Full + 4.0.0.0 @@ -18,6 +19,10 @@ + + all + compile; build; native; contentfiles; analyzers + diff --git a/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs b/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs index 295c7cb2a0..32e1197c31 100644 --- a/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs +++ b/src/Tgstation.Server.Host.Service/Properties/AssemblyInfo.cs @@ -9,4 +9,3 @@ using System.Runtime.InteropServices; [assembly: AssemblyVersion("4.0.0.0")] [assembly: AssemblyFileVersion("4.0.0.0")] -[assembly: AssemblyInformationalVersion("4.0.0.0")] diff --git a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj index 77dd44b935..b1d14c9e0b 100644 --- a/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj +++ b/src/Tgstation.Server.Host.Service/Tgstation.Server.Host.Service.csproj @@ -94,6 +94,10 @@ 2.2.5 + + all + compile; build; native; contentfiles; analyzers + 2.1.1 diff --git a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj index f6c9dce932..607abe220f 100644 --- a/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj +++ b/src/Tgstation.Server.Host.Watchdog/Tgstation.Server.Host.Watchdog.csproj @@ -4,6 +4,8 @@ netstandard2.0 Full false + 4.0.0.0 + 4.0.0.0 @@ -18,7 +20,10 @@ - + + all + compile; build; native; contentfiles; analyzers + diff --git a/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs b/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs index de9f8c19ce..0aba902d06 100644 --- a/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs +++ b/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs @@ -79,8 +79,12 @@ namespace Tgstation.Server.Host.Components { Models.WatchdogReattachInformation result = null; await databaseContextFactory.UseContext(async (db) => - result = await db.Instances.Where(x => x.Id == metadata.Id).Select(x => x.WatchdogReattachInformation).FirstAsync(cancellationToken).ConfigureAwait(false) + result = await db.Instances.Where(x => x.Id == metadata.Id).Select(x => x.WatchdogReattachInformation).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false) ).ConfigureAwait(false); + + if (result == default) + throw new JobException("Unable to load reattach information!"); + var bravoDmbTask = dmbFactory.FromCompileJob(result.Bravo.CompileJob, cancellationToken); return new WatchdogReattachInformation(result, await dmbFactory.FromCompileJob(result.Alpha.CompileJob, cancellationToken).ConfigureAwait(false), await bravoDmbTask.ConfigureAwait(false)); } diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs index 40c1aa5ec2..7a2d765a54 100644 --- a/src/Tgstation.Server.Host/Controllers/ChatController.cs +++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs @@ -163,7 +163,7 @@ namespace Tgstation.Server.Host.Controllers var results = await query.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); if (results == default) - return NotFound(); + return StatusCode((int)HttpStatusCode.Gone); var connectionStrings = (AuthenticationContext.GetRight(RightsType.ChatBots) & (ulong)ChatBotRights.ReadConnectionString) != 0; diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs index 7f7a8281c6..59dfd9016b 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs @@ -96,7 +96,12 @@ namespace Tgstation.Server.Host.Controllers var revision = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (ulong)DreamDaemonRights.ReadRevision) != 0; if (settings == null) - settings = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false); + { + settings = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + if (settings == default) + return StatusCode((int)HttpStatusCode.Gone); + } + var result = new DreamDaemon(); if (metadata) { @@ -145,7 +150,10 @@ namespace Tgstation.Server.Host.Controllers throw new ArgumentNullException(nameof(model)); //alias for changing DD settings - var current = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false); + var current = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + + if (current == default) + return StatusCode((int)HttpStatusCode.Gone); var userRights = (DreamDaemonRights)AuthenticationContext.GetRight(RightsType.DreamDaemon); diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs index c77d3a458d..9341fd8dd3 100644 --- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs +++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Linq; +using System.Net; using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api; @@ -58,7 +59,7 @@ namespace Tgstation.Server.Host.Controllers } /// - [TgsAuthorize(DreamMakerRights.List)] + [TgsAuthorize(DreamMakerRights.CompileJobs)] public override async Task GetId(long id, CancellationToken cancellationToken) { var compileJob = await DatabaseContext.CompileJobs @@ -73,11 +74,14 @@ namespace Tgstation.Server.Host.Controllers } /// - [TgsAuthorize(DreamMakerRights.List)] + [TgsAuthorize(DreamMakerRights.CompileJobs)] public override async Task List(CancellationToken cancellationToken) { - var compileJobs = await DatabaseContext.CompileJobs.Where(x => x.Job.Instance.Id == Instance.Id).ToListAsync(cancellationToken).ConfigureAwait(false); - return Json(compileJobs.Select(x => x.ToApi())); + var compileJobs = await DatabaseContext.CompileJobs.Where(x => x.Job.Instance.Id == Instance.Id).OrderByDescending(x => x.Job.StartedAt).Select(x => new Api.Models.CompileJob + { + Id = x.Id + }).ToListAsync(cancellationToken).ConfigureAwait(false); + return Json(compileJobs); } /// @@ -100,12 +104,9 @@ namespace Tgstation.Server.Host.Controllers [TgsAuthorize(DreamMakerRights.SetDme | DreamMakerRights.SetApiValidationPort)] public override async Task Update([FromBody] Api.Models.DreamMaker model, CancellationToken cancellationToken) { - var hostModel = new DreamMakerSettings - { - InstanceId = Instance.Id - }; - - DatabaseContext.DreamMakerSettings.Attach(hostModel); + var hostModel = await DatabaseContext.DreamMakerSettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + if (hostModel == null) + return StatusCode((int)HttpStatusCode.Gone); if (model.ProjectName != null) { @@ -145,9 +146,15 @@ namespace Tgstation.Server.Host.Controllers { StartupTimeout = x.StartupTimeout, SecurityLevel = x.SecurityLevel - }).FirstAsync(cancellationToken); + }).FirstOrDefaultAsync(cancellationToken); + + var dreamMakerSettings = await databaseContext.DreamMakerSettings.Where(x => x.InstanceId == instanceModel.Id).FirstAsync(cancellationToken).ConfigureAwait(false); + if (dreamMakerSettings == default) + throw new JobException("Missing DreamMakerSettings in DB!"); var ddSettings = await ddSettingsTask.ConfigureAwait(false); + if (ddSettings == default) + throw new JobException("Missing DreamDaemonSettings in DB!"); var instance = instanceManager.GetInstance(instanceModel); @@ -156,10 +163,8 @@ namespace Tgstation.Server.Host.Controllers using (var repo = await instance.RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false)) { if (repo == null) - { - job.ExceptionDetails = "Missing repository!"; - return; - } + throw new JobException("Missing Repository!"); + var repoSha = repo.Head; revInfo = await databaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha).Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).FirstOrDefaultAsync().ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index 30f111dede..eae5142ff3 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -199,8 +199,8 @@ namespace Tgstation.Server.Host.Controllers .Include(x => x.WatchdogReattachInformation) .Include(x => x.WatchdogReattachInformation.Alpha) .Include(x => x.WatchdogReattachInformation.Bravo) - .FirstAsync(cancellationToken).ConfigureAwait(false); - if (originalModel == default(Models.Instance)) + .FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); + if (originalModel == default) return StatusCode((int)HttpStatusCode.Gone); if (originalModel.WatchdogReattachInformation != null) @@ -324,7 +324,7 @@ namespace Tgstation.Server.Host.Controllers Description = String.Format(CultureInfo.InvariantCulture, "Move instance ID {0} from {1} to {2}", Instance.Id, Instance.Path, rawPath), Instance = Instance, CancelRightsType = RightsType.InstanceManager, - CancelRight = (ulong)InstanceManagerRights.CancelMove, + CancelRight = (ulong)InstanceManagerRights.Relocate, StartedBy = AuthenticationContext.User }; diff --git a/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs b/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs index 26412f7509..aa9a8c8bf7 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs @@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Controllers } /// - [TgsAuthorize(InstanceUserRights.WriteUsers)] + [TgsAuthorize(InstanceUserRights.CreateUsers)] public override async Task Create([FromBody] Api.Models.InstanceUser model, CancellationToken cancellationToken) { var test = StandardModelChecks(model); @@ -114,7 +114,7 @@ namespace Tgstation.Server.Host.Controllers //this functions as userId var user = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); if (user == default) - return NotFound(); + return StatusCode((int)HttpStatusCode.Gone); return Json(user.ToApi()); } diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs index b48033ef4e..07c54687cc 100644 --- a/src/Tgstation.Server.Host/Controllers/JobController.cs +++ b/src/Tgstation.Server.Host/Controllers/JobController.cs @@ -40,10 +40,8 @@ namespace Tgstation.Server.Host.Controllers [TgsAuthorize] public override async Task Read(CancellationToken cancellationToken) { - var result = await DatabaseContext.Jobs.Where(x => x.Instance.Id == Instance.Id).OrderByDescending(x => x.StartedAt).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); - if (result == null) - return StatusCode((int)HttpStatusCode.Gone); - return Json(result); + var result = await DatabaseContext.Jobs.Where(x => x.Instance.Id == Instance.Id && !x.StoppedAt.HasValue).OrderByDescending(x => x.StartedAt).ToListAsync(cancellationToken).ConfigureAwait(false); + return Json(result.Select(x => x.ToApi())); } /// diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index 3cdf397055..735bc19e6d 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -224,8 +224,11 @@ namespace Tgstation.Server.Host.Controllers using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false)) { if (repo != null && await PopulateApi(api, repo, DatabaseContext, Instance, null, null, cancellationToken).ConfigureAwait(false)) + { //user may have fucked with the repo without telling us, do what we can await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); + return StatusCode((int)HttpStatusCode.Created, api); + } return Json(api); } } diff --git a/src/Tgstation.Server.Host/Controllers/UserController.cs b/src/Tgstation.Server.Host/Controllers/UserController.cs index 7a389b3b1d..241b08a02f 100644 --- a/src/Tgstation.Server.Host/Controllers/UserController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserController.cs @@ -62,7 +62,7 @@ namespace Tgstation.Server.Host.Controllers } /// - [TgsAuthorize(AdministrationRights.EditUsers)] + [TgsAuthorize(AdministrationRights.WriteUsers)] public override async Task Create([FromBody] UserUpdate model, CancellationToken cancellationToken) { if (model == null) @@ -122,17 +122,17 @@ namespace Tgstation.Server.Host.Controllers } /// - [TgsAuthorize(AdministrationRights.EditUsers | AdministrationRights.EditPassword)] + [TgsAuthorize(AdministrationRights.WriteUsers | AdministrationRights.EditOwnPassword)] public override async Task Update([FromBody] UserUpdate model, CancellationToken cancellationToken) { if (model == null) throw new ArgumentNullException(nameof(model)); - var passwordEditOnly = !AuthenticationContext.User.AdministrationRights.Value.HasFlag(AdministrationRights.EditUsers); + var passwordEditOnly = !AuthenticationContext.User.AdministrationRights.Value.HasFlag(AdministrationRights.WriteUsers); var originalUser = passwordEditOnly ? AuthenticationContext.User : await DatabaseContext.Users.Where(x => x.Id == model.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); if (originalUser == default) - return StatusCode((int)HttpStatusCode.Gone); + return NotFound(); if (passwordEditOnly && (model.Id != originalUser.Id || model.InstanceManagerRights.HasValue || model.AdministrationRights.HasValue || model.Enabled.HasValue || model.SystemIdentifier != null || model.Name != null)) return Forbid(); @@ -164,7 +164,7 @@ namespace Tgstation.Server.Host.Controllers public override Task Read(CancellationToken cancellationToken) => Task.FromResult(Json(AuthenticationContext.User.ToApi(true))); /// - [TgsAuthorize(AdministrationRights.EditUsers)] + [TgsAuthorize(AdministrationRights.ReadUsers)] public override async Task List(CancellationToken cancellationToken) { var users = await DatabaseContext.Users.ToListAsync(cancellationToken).ConfigureAwait(false); @@ -178,7 +178,7 @@ namespace Tgstation.Server.Host.Controllers if (id == AuthenticationContext.User.Id) return await Read(cancellationToken).ConfigureAwait(false); - if (!((AdministrationRights)AuthenticationContext.GetRight(RightsType.Administration)).HasFlag(AdministrationRights.EditUsers)) + if (!((AdministrationRights)AuthenticationContext.GetRight(RightsType.Administration)).HasFlag(AdministrationRights.ReadUsers)) return Forbid(); var user = await DatabaseContext.Users.Where(x => x.Id == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index fa8a4573ea..68e70510d1 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -4,6 +4,8 @@ netcoreapp2.0 Full 4.0.0.0 + 4.0.0.0 + 1.0.0 @@ -29,6 +31,10 @@ + + all + compile; build; native; contentfiles; analyzers + diff --git a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs index 0c2291bfe1..0208a1bdc1 100644 --- a/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs +++ b/tests/Tgstation.Server.Host.Tests/Security/TestAuthenticationContext.cs @@ -42,7 +42,7 @@ namespace Tgstation.Server.Host.Security.Tests var instanceUser = new InstanceUser(); var authContext = new AuthenticationContext(null, user, instanceUser); - user.AdministrationRights = AdministrationRights.EditUsers; + user.AdministrationRights = AdministrationRights.WriteUsers; instanceUser.ByondRights = ByondRights.ChangeVersion | ByondRights.ReadActive; Assert.AreEqual((ulong)user.AdministrationRights, authContext.GetRight(RightsType.Administration)); Assert.AreEqual((ulong)instanceUser.ByondRights, authContext.GetRight(RightsType.Byond)); diff --git a/v4_prototype_TODO.txt b/v4_prototype_TODO.txt index 9e7ad3777f..4efbf08945 100644 --- a/v4_prototype_TODO.txt +++ b/v4_prototype_TODO.txt @@ -1,3 +1,12 @@ Verify the byond cache folder location on linux Test watchdog -Test chat channel tagging + +UNIT test watchdog + +Test chat channel tagging and full stack + +Test reattachment + +Test auto update + +Test auto start