Skip to content

Commit

Permalink
Merge pull request #1178 from tgstation/ApiFixups [APIDeploy][NugetDe…
Browse files Browse the repository at this point in the history
…ploy]

Api fixups
  • Loading branch information
Cyberboss committed Dec 30, 2020
2 parents 007c40f + 256e8f2 commit e2095dd
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 3 deletions.
4 changes: 2 additions & 2 deletions build/Version.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<PropertyGroup>
<TgsCoreVersion>4.7.0</TgsCoreVersion>
<TgsConfigVersion>2.2.0</TgsConfigVersion>
<TgsApiVersion>8.0.0</TgsApiVersion>
<TgsClientVersion>9.0.0</TgsClientVersion>
<TgsApiVersion>8.1.0</TgsApiVersion>
<TgsClientVersion>9.1.0</TgsClientVersion>
<TgsDmapiVersion>5.2.10</TgsDmapiVersion>
<TgsHostWatchdogVersion>1.1.0</TgsHostWatchdogVersion>
<TgsContainerScriptVersion>1.2.0</TgsContainerScriptVersion>
Expand Down
12 changes: 12 additions & 0 deletions src/Tgstation.Server.Api/Models/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -608,5 +608,17 @@ public enum ErrorCode : uint
/// </summary>
[Description("Cannot delete the user group as it is not empty!")]
UserGroupNotEmpty,

/// <summary>
/// Attempted to create an <see cref="User"/> but the configured limit has been reached.
/// </summary>
[Description("The user cannot be created because the configured limit has been reached!")]
UserLimitReached,

/// <summary>
/// Attempted to create an <see cref="UserGroup"/> but the configured limit has been reached.
/// </summary>
[Description("The user group cannot be created because the configured limit has been reached!")]
UserGroupLimitReached,
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;

namespace Tgstation.Server.Api.Models.Internal
{
Expand All @@ -22,6 +22,11 @@ public abstract class ServerInformation
/// </summary>
public uint UserLimit { get; set; }

/// <summary>
/// The maximum number of <see cref="Models.UserGroup"/>s allowed.
/// </summary>
public uint UserGroupLimit { get; set; }

/// <summary>
/// Limits the locations instances may be created or attached from.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public sealed class GeneralConfiguration : ServerInformation
/// </summary>
const uint DefaultUserLimit = 100;

/// <summary>
/// The default value for <see cref="ServerInformation.UserGroupLimit"/>.
/// </summary>
const uint DefaultUserGroupLimit = 25;

/// <summary>
/// The default value for <see cref="ByondTopicTimeout"/>
/// </summary>
Expand Down Expand Up @@ -102,6 +107,7 @@ public GeneralConfiguration()
MinimumPasswordLength = DefaultMinimumPasswordLength;
InstanceLimit = DefaultInstanceLimit;
UserLimit = DefaultUserLimit;
UserGroupLimit = DefaultUserGroupLimit;
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Tgstation.Server.Host/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ public async Task<IActionResult> Home(CancellationToken cancellationToken)
MinimumPasswordLength = generalConfiguration.MinimumPasswordLength,
InstanceLimit = generalConfiguration.InstanceLimit,
UserLimit = generalConfiguration.UserLimit,
UserGroupLimit = generalConfiguration.UserGroupLimit,
ValidInstancePaths = generalConfiguration.ValidInstancePaths,
WindowsHost = platformIdentifier.IsWindows,
SwarmServers = swarmService.GetSwarmServers(),
Expand Down
12 changes: 12 additions & 0 deletions src/Tgstation.Server.Host/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ BadRequestObjectResult TrySetPassword(Models.User dbUser, string newPassword, bo
[HttpPut]
[TgsAuthorize(AdministrationRights.WriteUsers)]
[ProducesResponseType(typeof(Api.Models.User), 201)]
#pragma warning disable CA1502, CA1506
public async Task<IActionResult> Create([FromBody] UserUpdate model, CancellationToken cancellationToken)
{
if (model == null)
Expand All @@ -139,6 +140,14 @@ public async Task<IActionResult> Create([FromBody] UserUpdate model, Cancellatio
if (fail != null)
return fail;

var totalUsers = await DatabaseContext
.Users
.AsQueryable()
.CountAsync(cancellationToken)
.ConfigureAwait(false);
if (totalUsers >= generalConfiguration.UserLimit)
return Conflict(new ErrorMessage(ErrorCode.UserLimitReached));

var dbUser = await CreateNewUserFromModel(model, cancellationToken).ConfigureAwait(false);
if (dbUser == null)
return Gone();
Expand Down Expand Up @@ -173,6 +182,7 @@ public async Task<IActionResult> Create([FromBody] UserUpdate model, Cancellatio

return Created(dbUser.ToApi(true));
}
#pragma warning restore CA1502, CA1506

/// <summary>
/// Update a <see cref="Api.Models.User"/>.
Expand All @@ -182,10 +192,12 @@ public async Task<IActionResult> Create([FromBody] UserUpdate model, Cancellatio
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation.</returns>
/// <response code="200"><see cref="Api.Models.User"/> updated successfully.</response>
/// <response code="404">Requested <see cref="Api.Models.Internal.User.Id"/> does not exist.</response>
/// <response code="410">Requested <see cref="Api.Models.User.Group"/> does not exist.</response>
[HttpPost]
[TgsAuthorize(AdministrationRights.WriteUsers | AdministrationRights.EditOwnPassword | AdministrationRights.EditOwnOAuthConnections)]
[ProducesResponseType(typeof(Api.Models.User), 200)]
[ProducesResponseType(typeof(ErrorMessage), 404)]
[ProducesResponseType(typeof(ErrorMessage), 410)]
#pragma warning disable CA1502 // TODO: Decomplexify
#pragma warning disable CA1506
public async Task<IActionResult> Update([FromBody] UserUpdate model, CancellationToken cancellationToken)
Expand Down
18 changes: 18 additions & 0 deletions src/Tgstation.Server.Host/Controllers/UserGroupController.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Security;
using Z.EntityFramework.Plus;
Expand All @@ -20,22 +22,30 @@ namespace Tgstation.Server.Host.Controllers
[Route(Routes.UserGroup)]
public class UserGroupController : ApiController
{
/// <summary>
/// The <see cref="GeneralConfiguration"/> for the <see cref="UserGroupController"/>.
/// </summary>
readonly GeneralConfiguration generalConfiguration;

/// <summary>
/// Initializes a new instance of the <see cref="UserGroupController"/> <see langword="clas"/>.
/// </summary>
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="generalConfiguration"/>.</param>
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="ApiController"/>.</param>
public UserGroupController(
IDatabaseContext databaseContext,
IAuthenticationContextFactory authenticationContextFactory,
IOptions<GeneralConfiguration> generalConfigurationOptions,
ILogger<UserGroupController> logger)
: base(
databaseContext,
authenticationContextFactory,
logger,
true)
{
generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
}

/// <summary>
Expand All @@ -56,6 +66,14 @@ public async Task<IActionResult> Create([FromBody] UserGroup model, Cancellation
if (model.Name == null)
return BadRequest(new ErrorMessage(ErrorCode.ModelValidationFailure));

var totalGroups = await DatabaseContext
.Groups
.AsQueryable()
.CountAsync(cancellationToken)
.ConfigureAwait(false);
if (totalGroups >= generalConfiguration.UserGroupLimit)
return Conflict(new ErrorMessage(ErrorCode.UserGroupLimitReached));

var permissionSet = new Models.PermissionSet
{
AdministrationRights = model.PermissionSet?.AdministrationRights ?? AdministrationRights.None,
Expand Down
1 change: 1 addition & 0 deletions src/Tgstation.Server.Host/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"ApiPort": 5000,
"UseBasicWatchdog": false,
"UserLimit": 100,
"UserGroupLimit": 25,
"InstanceLimit": 10,
"ValidInstancePaths": null,
"HostApiDocumentation": false
Expand Down
1 change: 1 addition & 0 deletions tests/Tgstation.Server.Tests/RootTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ async Task TestServerInformation(IServerClientFactory clientFactory, IServerClie
Assert.AreEqual(10U, serverInfo.MinimumPasswordLength);
Assert.AreEqual(11U, serverInfo.InstanceLimit);
Assert.AreEqual(150U, serverInfo.UserLimit);
Assert.AreEqual(47U, serverInfo.UserGroupLimit);
Assert.AreEqual(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), serverInfo.WindowsHost);

//check that modifying the token even slightly fucks up the auth
Expand Down
1 change: 1 addition & 0 deletions tests/Tgstation.Server.Tests/TestingServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public TestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth, us
String.Format(CultureInfo.InvariantCulture, "General:MinimumPasswordLength={0}", 10),
String.Format(CultureInfo.InvariantCulture, "General:InstanceLimit={0}", 11),
String.Format(CultureInfo.InvariantCulture, "General:UserLimit={0}", 150),
String.Format(CultureInfo.InvariantCulture, "General:UserGroupLimit={0}", 47),
String.Format(CultureInfo.InvariantCulture, "General:HostApiDocumentation={0}", DumpOpenApiSpecpath),
String.Format(CultureInfo.InvariantCulture, "FileLogging:Directory={0}", Path.Combine(Directory, "Logs")),
String.Format(CultureInfo.InvariantCulture, "FileLogging:LogLevel={0}", "Trace"),
Expand Down

0 comments on commit e2095dd

Please sign in to comment.