From e8efcc1f60e3910016631b52ea5b00edfb2ae2f4 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Wed, 15 Aug 2018 14:32:47 -0400 Subject: [PATCH] Handle database conflicts at a higher level with middleware --- .../Controllers/InstanceController.cs | 9 +--- .../Controllers/InstanceUserController.cs | 18 +------- .../Controllers/UserController.cs | 17 +------- src/Tgstation.Server.Host/Core/Application.cs | 4 +- .../Core/ApplicationBuilderExtensions.cs | 36 ++++++++++++++++ .../Models/DatabaseContext.cs | 2 +- .../Properties/launchSettings.json | 19 +-------- tools/TGS.postman_collection.json | 41 ++++++++++++++++++- 8 files changed, 86 insertions(+), 60 deletions(-) create mode 100644 src/Tgstation.Server.Host/Core/ApplicationBuilderExtensions.cs diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs index e285b343e9..7a3f465f90 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs @@ -211,14 +211,7 @@ namespace Tgstation.Server.Host.Controllers var attachFileName = ioManager.ConcatPath(originalModel.Path, InstanceAttachFileName); await ioManager.WriteAllBytes(attachFileName, Array.Empty(), default).ConfigureAwait(false); - try - { - await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); //cascades everything - } - catch (DbUpdateException e) - { - return Conflict(new ErrorMessage { Message = e.Message }); - } + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); //cascades everything return Ok(); } diff --git a/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs b/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs index fc3ef16c87..5a37a37c3f 100644 --- a/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs +++ b/src/Tgstation.Server.Host/Controllers/InstanceUserController.cs @@ -69,14 +69,7 @@ namespace Tgstation.Server.Host.Controllers DatabaseContext.InstanceUsers.Add(dbUser); - try - { - await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); - } - catch (DbUpdateConcurrencyException e) - { - return Conflict(new ErrorMessage { Message = e.Message }); - } + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); return Json(dbUser.ToApi()); } @@ -98,14 +91,7 @@ namespace Tgstation.Server.Host.Controllers 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 ErrorMessage { Message = e.Message }); - } + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); return Json(originalUser.ToApi()); } diff --git a/src/Tgstation.Server.Host/Controllers/UserController.cs b/src/Tgstation.Server.Host/Controllers/UserController.cs index be981aea6b..961e9a99e7 100644 --- a/src/Tgstation.Server.Host/Controllers/UserController.cs +++ b/src/Tgstation.Server.Host/Controllers/UserController.cs @@ -116,22 +116,7 @@ namespace Tgstation.Server.Host.Controllers DatabaseContext.Users.Add(dbUser); - try - { - try - { - await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); - } - catch (Exception e) - { - logger.LogInformation("Error creating user: {0}", e); - throw; - } - } - catch (DbUpdateConcurrencyException e) - { - return Conflict(new { message = e.Message }); - } + await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); return Json(dbUser.ToApi()); } diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index e7b4805557..08e21e2d9d 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -22,7 +22,6 @@ using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Byond; using Tgstation.Server.Host.Components.Chat; using Tgstation.Server.Host.Components.StaticFiles; -using Tgstation.Server.Host.Components.Watchdog; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Controllers; using Tgstation.Server.Host.IO; @@ -249,6 +248,9 @@ namespace Tgstation.Server.Host.Core }); applicationBuilder.UseAuthentication(); + + applicationBuilder.UseDbConflictHandling(); + applicationBuilder.UseMvc(); } diff --git a/src/Tgstation.Server.Host/Core/ApplicationBuilderExtensions.cs b/src/Tgstation.Server.Host/Core/ApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..470920d16d --- /dev/null +++ b/src/Tgstation.Server.Host/Core/ApplicationBuilderExtensions.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System; +using System.Globalization; +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Core +{ + /// + /// Extensions for + /// + static class ApplicationBuilderExtensions + { + /// + /// Return a for s + /// + /// The to configure + public static void UseDbConflictHandling(this IApplicationBuilder applicationBuilder) => applicationBuilder.Use(async (context, next) => + { + if (applicationBuilder == null) + throw new ArgumentNullException(nameof(applicationBuilder)); + try + { + await next().ConfigureAwait(false); + } + catch (DbUpdateException e) + { + await new ConflictObjectResult(new ErrorMessage { Message = String.Format(CultureInfo.InvariantCulture, "A database conflict has occurred: {0}", (e.InnerException ?? e).Message) }).ExecuteResultAsync(new ActionContext + { + HttpContext = context + }).ConfigureAwait(false); + } + }); + } +} diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs index a86f07fee6..c8401f054f 100644 --- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs +++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs @@ -141,7 +141,7 @@ namespace Tgstation.Server.Host.Models Logger.LogInformation("Migrating database..."); var wasEmpty = false; - if (!databaseConfiguration.NoMigrations) + if (databaseConfiguration.NoMigrations) { Logger.LogWarning("Using all or nothing migration strategy!"); await Database.EnsureCreatedAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Tgstation.Server.Host/Properties/launchSettings.json b/src/Tgstation.Server.Host/Properties/launchSettings.json index 16a477455d..62c38915e0 100644 --- a/src/Tgstation.Server.Host/Properties/launchSettings.json +++ b/src/Tgstation.Server.Host/Properties/launchSettings.json @@ -1,27 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:52906/", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "Tgstation.Server.Host": { "commandName": "Project", - "launchBrowser": true, + "launchBrowser": false, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:52907/" + "applicationUrl": "http://localhost:5000/" } } } \ No newline at end of file diff --git a/tools/TGS.postman_collection.json b/tools/TGS.postman_collection.json index 5fae9bbb29..1849b98c57 100644 --- a/tools/TGS.postman_collection.json +++ b/tools/TGS.postman_collection.json @@ -266,6 +266,45 @@ }, "response": [] }, + { + "name": "Create User admin", + "request": { + "method": "PUT", + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "User-Agent", + "value": "Postman/1.0" + }, + { + "key": "Api", + "value": "Tgstation.Server.Api/4.0.0.0" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"password\": \"asdfasdfasdfasdfasdf\",\n \"name\": \"admin\"\n}" + }, + "url": { + "raw": "localhost:5000/User", + "host": [ + "localhost" + ], + "port": "5000", + "path": [ + "User" + ] + } + }, + "response": [] + }, { "name": "Try To Add A SysId To User ID 2", "request": { @@ -544,7 +583,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"systemIdentifier\": \"Cyberboss\"\n}" + "raw": "{\n \"systemIdentifier\": \"TESSONICS\\\\Jordan\"\n}" }, "url": { "raw": "localhost:5000/User",