mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
InstanceUserController
This commit is contained in:
@@ -13,13 +13,15 @@ namespace Tgstation.Server.Api.Models
|
||||
/// The <see cref="Internal.User.Id"/> of the <see cref="User"/> the <see cref="InstanceUser"/> belongs to
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public long UserId { get; set; }
|
||||
[Required]
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Instance.Id"/> of the <see cref="Instance"/> the <see cref="InstanceUser"/> belongs to
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public long InstanceId { get; set; }
|
||||
[Required]
|
||||
public long? InstanceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Rights.ByondRights"/> of the <see cref="InstanceUser"/>
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
@@ -63,7 +64,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
DreamMakerSettings = new DreamMakerSettings(),
|
||||
Name = model.Name,
|
||||
Online = false,
|
||||
Path = model.Path,
|
||||
Path = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? model.Path.ToUpperInvariant() : model.Path,
|
||||
RepositorySettings = new RepositorySettings()
|
||||
};
|
||||
|
||||
@@ -91,15 +92,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
return Conflict(new { message = e.Message });
|
||||
}
|
||||
|
||||
model.Online = newInstance.Online;
|
||||
model.Id = newInstance.Id;
|
||||
|
||||
return Json(model);
|
||||
|
||||
return Json(newInstance.ToApi());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Rights;
|
||||
using Tgstation.Server.Host.Models;
|
||||
using Tgstation.Server.Host.Security;
|
||||
using Z.EntityFramework.Plus;
|
||||
|
||||
namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// For managing <see cref="User"/>s
|
||||
/// </summary>
|
||||
[Route("/" + nameof(Models.InstanceUser))]
|
||||
public sealed class InstanceUserController : ModelController<Api.Models.InstanceUser>
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="InstanceUserController"/>
|
||||
/// </summary>
|
||||
readonly ILogger<InstanceUserController> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="UserController"/>
|
||||
/// </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="logger">The value of <see cref="logger"/></param>
|
||||
public InstanceUserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ILogger<InstanceUserController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks a <paramref name="model"/> for errors
|
||||
/// </summary>
|
||||
/// <param name="model">The <see cref="Api.Models.InstanceUser"/> to check</param>
|
||||
/// <returns>A <see cref="BadRequestResult"/> explaining any errors, <see langword="null"/> if none</returns>
|
||||
BadRequestObjectResult StandardModelChecks(Api.Models.InstanceUser model)
|
||||
{
|
||||
if (model == null)
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
|
||||
if (model.InstanceId.HasValue && model.InstanceId != Instance.Id)
|
||||
return BadRequest(new { message = "InstanceId does not match headers!" });
|
||||
|
||||
if (!model.InstanceId.HasValue)
|
||||
return BadRequest(new { message = "Missing UserId!" });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(AdministrationRights.EditUsers)]
|
||||
public override async Task<IActionResult> Create([FromBody] Api.Models.InstanceUser model, CancellationToken cancellationToken)
|
||||
{
|
||||
var test = StandardModelChecks(model);
|
||||
if (test != null)
|
||||
return test;
|
||||
|
||||
var dbUser = new Models.InstanceUser
|
||||
{
|
||||
ByondRights = model.ByondRights ?? ByondRights.None,
|
||||
ChatSettingsRights = model.ChatSettingsRights ?? ChatSettingsRights.None,
|
||||
ConfigurationRights = model.ConfigurationRights ?? ConfigurationRights.None,
|
||||
DreamDaemonRights = model.DreamDaemonRights ?? DreamDaemonRights.None,
|
||||
DreamMakerRights = model.DreamMakerRights ?? DreamMakerRights.None,
|
||||
RepositoryRights = model.RepositoryRights ?? RepositoryRights.None,
|
||||
UserId = model.UserId
|
||||
};
|
||||
|
||||
var ourInstance = new Models.Instance
|
||||
{
|
||||
Id = Instance.Id
|
||||
};
|
||||
|
||||
DatabaseContext.Instances.Attach(ourInstance);
|
||||
|
||||
ourInstance.InstanceUsers.Add(dbUser);
|
||||
|
||||
try
|
||||
{
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
return Conflict(new { message = e.Message });
|
||||
}
|
||||
return Json(dbUser.ToApi());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(AdministrationRights.EditUsers)]
|
||||
public override async Task<IActionResult> Update([FromBody] Api.Models.InstanceUser model, CancellationToken cancellationToken)
|
||||
{
|
||||
var test = StandardModelChecks(model);
|
||||
if (test != null)
|
||||
return test;
|
||||
|
||||
var originalUser = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == model.UserId).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (originalUser == null)
|
||||
return StatusCode((int)HttpStatusCode.Gone);
|
||||
|
||||
originalUser.ByondRights = model.ByondRights ?? originalUser.ByondRights;
|
||||
originalUser.ChatSettingsRights = model.ChatSettingsRights ?? originalUser.ChatSettingsRights;
|
||||
originalUser.ConfigurationRights = model.ConfigurationRights ?? originalUser.ConfigurationRights;
|
||||
originalUser.DreamDaemonRights = model.DreamDaemonRights ?? originalUser.DreamDaemonRights;
|
||||
originalUser.DreamMakerRights = model.DreamMakerRights ?? originalUser.DreamMakerRights;
|
||||
|
||||
try
|
||||
{
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
return Conflict(new { message = e.Message });
|
||||
}
|
||||
return Json(originalUser.ToApi());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize]
|
||||
public override Task<IActionResult> Read(CancellationToken cancellationToken) => Task.FromResult(AuthenticationContext.InstanceUser != null ? (IActionResult)Json(AuthenticationContext.InstanceUser.ToApi()) : NotFound());
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(InstanceUserRights.ReadUsers)]
|
||||
public override async Task<IActionResult> List(CancellationToken cancellationToken)
|
||||
{
|
||||
var users = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Json(users.Select(x => x.ToApi()));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(InstanceUserRights.ReadUsers)]
|
||||
public override async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
|
||||
{
|
||||
//this functions as userId
|
||||
var user = await DatabaseContext.Instances.Where(x => x.Id == id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (user == default)
|
||||
return NotFound();
|
||||
return Json(user.ToApi());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(AdministrationRights.EditUsers)]
|
||||
public override async Task<IActionResult> Delete([FromBody] Api.Models.InstanceUser model, CancellationToken cancellationToken)
|
||||
{
|
||||
var test = StandardModelChecks(model);
|
||||
if (test != null)
|
||||
return test;
|
||||
|
||||
await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).SelectMany(x => x.InstanceUsers).Where(x => x.UserId == model.UserId).DeleteAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
IQueryable<Job> query = DatabaseContext.Jobs;
|
||||
if (Instance != null)
|
||||
{
|
||||
if (!AuthenticationContext.InstanceUser.AnyRights)
|
||||
if (AuthenticationContext.InstanceUser?.AnyRights != true)
|
||||
return Forbid();
|
||||
query = query.Where(x => x.Instance.Id == Instance.Id);
|
||||
}
|
||||
|
||||
+11
-11
@@ -18,32 +18,32 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// For managing <see cref="User"/>s
|
||||
/// </summary>
|
||||
[Route("/" + nameof(Models.User))]
|
||||
public sealed class UsersController : ModelController<UserUpdate>
|
||||
public sealed class UserController : ModelController<UserUpdate>
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ISystemIdentityFactory"/> for the <see cref="UsersController"/>
|
||||
/// The <see cref="ISystemIdentityFactory"/> for the <see cref="UserController"/>
|
||||
/// </summary>
|
||||
readonly ISystemIdentityFactory systemIdentityFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ICryptographySuite"/> for the <see cref="UsersController"/>
|
||||
/// The <see cref="ICryptographySuite"/> for the <see cref="UserController"/>
|
||||
/// </summary>
|
||||
readonly ICryptographySuite cryptographySuite;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="UsersController"/>
|
||||
/// The <see cref="ILogger"/> for the <see cref="UserController"/>
|
||||
/// </summary>
|
||||
readonly ILogger<UsersController> logger;
|
||||
readonly ILogger<UserController> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="UsersController"/>
|
||||
/// Construct a <see cref="UserController"/>
|
||||
/// </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="systemIdentityFactory">The value of <see cref="systemIdentityFactory"/></param>
|
||||
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
|
||||
/// <param name="logger">The value of <see cref="logger"/></param>
|
||||
public UsersController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, ILogger<UsersController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
public UserController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, ISystemIdentityFactory systemIdentityFactory, ICryptographySuite cryptographySuite, ILogger<UserController> logger) : base(databaseContext, authenticationContextFactory)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
|
||||
@@ -110,9 +110,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
return Conflict();
|
||||
return Conflict(new { message = e.Message });
|
||||
}
|
||||
|
||||
return Json(dbUser.ToApi());
|
||||
@@ -160,7 +160,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
public override async Task<IActionResult> List(CancellationToken cancellationToken)
|
||||
{
|
||||
var users = await DatabaseContext.Users.ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Json(users);
|
||||
return Json(users.Select(x => x.ToApi()));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -170,7 +170,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var user = await DatabaseContext.Users.Where(x => x.Id == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (user == default)
|
||||
return NotFound();
|
||||
return Json(user);
|
||||
return Json(user.ToApi());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,13 +106,13 @@ namespace Tgstation.Server.Host.Models
|
||||
// build default model.
|
||||
LogModelBuilderHelper.Build(modelBuilder.Entity<Log>());
|
||||
modelBuilder.Entity<Log>().ToTable(nameof(Logs));
|
||||
|
||||
modelBuilder.Entity<Instance>().HasIndex(x => x.Path).IsUnique();
|
||||
modelBuilder.Entity<RevisionInformation>().HasIndex(x => x.Commit).IsUnique();
|
||||
var user = modelBuilder.Entity<User>();
|
||||
user.HasIndex(x => x.CanonicalName).IsUnique();
|
||||
user.HasOne(x => x.CreatedBy).WithMany(x => x.CreatedUsers).OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<InstanceUser>().HasIndex(x => new { x.UserId, x.Instance }).IsUnique();
|
||||
modelBuilder.Entity<InstanceUser>().HasIndex(x => new { x.UserId, x.InstanceId }).IsUnique();
|
||||
|
||||
var chatChannel = modelBuilder.Entity<ChatChannel>();
|
||||
chatChannel.HasIndex(x => new { x.ChatSettingsId, x.IrcChannel }).IsUnique();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Tgstation.Server.Api.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="Api.Models.Instance"/> in the database
|
||||
/// </summary>
|
||||
public sealed class Instance : Api.Models.Instance
|
||||
public sealed class Instance : Api.Models.Instance, IApiConvertable<Api.Models.Instance>
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="Models.ChatSettings"/> for the <see cref="Instance"/>
|
||||
@@ -51,5 +52,16 @@ namespace Tgstation.Server.Host.Models
|
||||
/// The <see cref="Jobs"/> in the <see cref="Instance"/>
|
||||
/// </summary>
|
||||
public List<Job> Jobs { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Api.Models.Instance ToApi() => new Api.Models.Instance
|
||||
{
|
||||
AutoUpdateInterval = AutoUpdateInterval,
|
||||
ConfigurationAllowed = ConfigurationAllowed,
|
||||
Id = Id,
|
||||
Name = Name,
|
||||
Path = Path,
|
||||
Online = Online
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Tgstation.Server.Api.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public sealed class InstanceUser : Api.Models.InstanceUser
|
||||
public sealed class InstanceUser : Api.Models.InstanceUser, IApiConvertable<Api.Models.InstanceUser>
|
||||
{
|
||||
/// <summary>
|
||||
/// The row Id
|
||||
@@ -24,5 +25,18 @@ namespace Tgstation.Server.Host.Models
|
||||
ConfigurationRights != Api.Rights.ConfigurationRights.None ||
|
||||
DreamDaemonRights != Api.Rights.DreamDaemonRights.None ||
|
||||
DreamMakerRights != Api.Rights.DreamMakerRights.None;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Api.Models.InstanceUser ToApi() => new Api.Models.InstanceUser
|
||||
{
|
||||
ByondRights = ByondRights,
|
||||
ChatSettingsRights = ChatSettingsRights,
|
||||
ConfigurationRights = ConfigurationRights,
|
||||
DreamDaemonRights = DreamDaemonRights,
|
||||
DreamMakerRights = DreamMakerRights,
|
||||
InstanceId = InstanceId,
|
||||
RepositoryRights = RepositoryRights,
|
||||
UserId = UserId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user