From 7f47fa6753ec1191fde3c51daa8e59542565f582 Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Mon, 12 Oct 2020 22:45:23 +0200 Subject: [PATCH 1/5] Change form and remove unused stuff --- ChaosBot/wwwroot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosBot/wwwroot b/ChaosBot/wwwroot index ae3d8a2..07d2c3d 160000 --- a/ChaosBot/wwwroot +++ b/ChaosBot/wwwroot @@ -1 +1 @@ -Subproject commit ae3d8a2ced41905d0b8fc6ca02df1db62a90906f +Subproject commit 07d2c3dc0e7ba5bfaa8eac94dad814f1a333a6eb From e78c0d8746bb278c693fa013418cd104de948461 Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Tue, 13 Oct 2020 00:04:36 +0200 Subject: [PATCH 2/5] Start refactoring to base api controller --- .../App/ApiControllers/BaseApiController.cs | 145 ++++++++++++++++++ .../ApiControllers/CustomCommandController.cs | 89 +++++++++++ .../WebServer/App/CustomCommandController.cs | 93 ----------- 3 files changed, 234 insertions(+), 93 deletions(-) create mode 100644 ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs create mode 100644 ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs delete mode 100644 ChaosBot/WebServer/App/CustomCommandController.cs diff --git a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs new file mode 100644 index 0000000..38b96ca --- /dev/null +++ b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Threading.Tasks; +using ChaosBot.Models; +using ChaosBot.WebServer.Services; +using FlexLabs.EntityFrameworkCore.Upsert; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; + +namespace ChaosBot.WebServer.App.ApiControllers +{ + public abstract class BaseApiController : Controller where T : class, new() + { + protected readonly AccessTokenCache AccessTokenCache; + + protected BaseApiController( + AccessTokenCache accessTokenCache + ) + { + AccessTokenCache = accessTokenCache; + } + + public async Task Index(ulong guildId) + { + if (!CheckPermissions.GetResult(AccessTokenCache, Request, guildId, out IActionResult result)) + return result; + + await using ChaosbotContext dbContext = new ChaosbotContext(); + + IQueryable query = GetBasicQuery(dbContext); + List list = ApplyFilterForCurrentGuild(query, guildId).ToList(); + + LoggingFacade.Info("Received request"); + List response = list.Select(element => + { + Dictionary responseDict = new Dictionary(); + + foreach (string field in GetIndexFields()) + { + responseDict.Add(field, element.GetType().GetProperty(field)?.GetValue(element, null)); + } + + dynamic dynamicResponseElement = new DynamicResponse(responseDict); + return dynamicResponseElement; + }).ToList(); + + return Content(JsonConvert.SerializeObject(response), new MediaTypeHeaderValue("application/json")); + } + + public async Task Upsert(ulong guildId, dynamic requestBody) + { + if (!CheckPermissions.GetResult(AccessTokenCache, Request, guildId, out IActionResult result)) + return result; + + await using ChaosbotContext dbContext = new ChaosbotContext(); + + T databaseObject = new T(); + + foreach (string key in GetValidationRules().Keys) + { + databaseObject + .GetType() + .GetProperty(key) + ?.SetValue(databaseObject, requestBody.GetType().GetProperty(key)?.GetValue(requestBody, null)); + } + + await ApplyFilterForUpsert(GetBasicQuery(dbContext).Upsert(databaseObject)).RunAsync(); + await dbContext.SaveChangesAsync(); + + return NoContent(); + } + + public async Task Delete(ulong guildId, TDeleteParameter deleteParameter) + { + if (!CheckPermissions.GetResult(AccessTokenCache, Request, guildId, out IActionResult result)) + return result; + + await using ChaosbotContext dbContext = new ChaosbotContext(); + + IQueryable query = GetBasicQuery(dbContext); + List toDelete = FilterQueryMultipleForDeletion(query, guildId, deleteParameter); + toDelete.Add(FilterQueryForDeletion(query, guildId, deleteParameter)); + + if (toDelete.Count == 0) + return NotFound(); + + foreach (T obj in toDelete) + { + GetBasicQuery(dbContext).Remove(obj); + } + await dbContext.SaveChangesAsync(); + + return NoContent(); + } + + protected abstract DbSet GetBasicQuery(ChaosbotContext context); + protected abstract IQueryable ApplyFilterForCurrentGuild(IQueryable query, ulong guildId); + protected abstract List GetIndexFields(); + protected abstract Dictionary> GetValidationRules(); + protected abstract UpsertCommandBuilder ApplyFilterForUpsert(UpsertCommandBuilder builder); + protected abstract T FilterQueryForDeletion(IQueryable query, ulong guildId, TDeleteParameter deleteParameter); + protected abstract List FilterQueryMultipleForDeletion(IQueryable query, ulong guildId, TDeleteParameter deleteParameter); + + private class DynamicResponse : DynamicObject + { + private readonly Dictionary _properties; + + public DynamicResponse(Dictionary properties) + { + _properties = properties; + } + + public override IEnumerable GetDynamicMemberNames() + { + return _properties.Keys; + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + if (_properties.ContainsKey(binder.Name)) + { + result = _properties[binder.Name]; + return true; + } + + result = null; + return false; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + if (_properties.ContainsKey(binder.Name)) + { + _properties[binder.Name] = value; + return true; + } + + return false; + } + } + } +} diff --git a/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs new file mode 100644 index 0000000..14d1a8b --- /dev/null +++ b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using ChaosBot.Models; +using ChaosBot.WebServer.Models; +using ChaosBot.WebServer.Services; +using FlexLabs.EntityFrameworkCore.Upsert; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace ChaosBot.WebServer.App.ApiControllers +{ + [ApiController] + [Route("/api/custom-commands")] + public class CustomCommandController : BaseApiController + { + public CustomCommandController( + AccessTokenCache accessTokenCache + ) : base( + accessTokenCache + ) {} + + [HttpGet] + [Route("{guildId}")] + public async Task IndexAction(ulong guildId) + { + return await Index(guildId); + } + + [HttpPost] + [Route("{guildId}")] + public async Task UpsertAction( + [FromRoute] ulong guildId, + [FromBody] dynamic requestBody) + { + return await Upsert(guildId, requestBody); + } + + [HttpDelete] + [Route("{guildId}/{command}")] + public async Task DeleteAction([FromRoute]ulong guildId, [FromRoute]string command) + { + return await Delete(guildId, command); + } + + protected override DbSet GetBasicQuery(ChaosbotContext context) + { + return context.CustomCommands; + } + + protected override IQueryable ApplyFilterForCurrentGuild(IQueryable query, ulong guildId) + { + return query.Where(e => e.DiscordGuildId == guildId); + } + + protected override List GetIndexFields() { + return new List + { + "Command", + "Type", + "Content" + }; + } + + protected override Dictionary> GetValidationRules() + { + return new Dictionary>(); + } + + protected override UpsertCommandBuilder ApplyFilterForUpsert( + UpsertCommandBuilder builder) + { + return builder.On(cc => new {cc.DiscordGuildId, cc.Command}); + } + + protected override CustomCommand FilterQueryForDeletion(IQueryable query, ulong guildId, string deleteParameter) + { + return query + .Where(cc => cc.DiscordGuildId == guildId) + .First(cc => cc.Command == deleteParameter) + ; + } + + protected override List FilterQueryMultipleForDeletion(IQueryable query, ulong guildId, string deleteParameter) + { + return new List(); + } + } +} diff --git a/ChaosBot/WebServer/App/CustomCommandController.cs b/ChaosBot/WebServer/App/CustomCommandController.cs deleted file mode 100644 index 5e4c638..0000000 --- a/ChaosBot/WebServer/App/CustomCommandController.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ChaosBot.Discord; -using ChaosBot.Models; -using ChaosBot.WebServer.Models; -using ChaosBot.WebServer.Services; -using Discord.WebSocket; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; - -namespace ChaosBot.WebServer.App -{ - [ApiController] - [Route("/api/custom-commands")] - public class CustomCommandController : Controller - { - private readonly AccessTokenCache _accessTokenCache; - - public CustomCommandController( - AccessTokenCache accessTokenCache - ) - { - _accessTokenCache = accessTokenCache; - } - - [HttpGet] - [Route("{guildId}")] - public async Task GetCustomCommands([FromRoute]ulong guildId) - { - if (!CheckPermissions.GetResult(_accessTokenCache, Request, guildId, out IActionResult result)) - return result; - - await using ChaosbotContext dbContext = new ChaosbotContext(); - - IQueryable customCommandsQuery = dbContext.CustomCommands; - List customCommands = customCommandsQuery - .Where(cc => cc.DiscordGuildId == guildId) - .ToList(); - - List response = customCommands.Select(e => new CustomCommandResponse(e)).ToList(); - - return Json(response); - } - - [HttpPost] - [Route("{guildId}")] - public async Task UpsertCustomCommands([FromRoute]ulong guildId, [FromBody]CustomCommandRequest customCommandRequest) - { - if (!CheckPermissions.GetResult(_accessTokenCache, Request, guildId, out IActionResult result)) - return result; - - await using ChaosbotContext dbContext = new ChaosbotContext(); - - CustomCommand customCommand = new CustomCommand - { - DiscordGuildId = guildId, - Command = customCommandRequest.Command, - Type = customCommandRequest.Type, - Content = customCommandRequest.Content - }; - await dbContext.CustomCommands.Upsert(customCommand) - .On(cc => new {cc.DiscordGuildId, cc.Command}).RunAsync(); - await dbContext.SaveChangesAsync(); - - return NoContent(); - } - - [HttpDelete] - [Route("{guildId}/{command}")] - public async Task DeleteCustomCommands([FromRoute]ulong guildId, [FromRoute]string command) - { - if (!CheckPermissions.GetResult(_accessTokenCache, Request, guildId, out IActionResult result)) - return result; - - await using ChaosbotContext dbContext = new ChaosbotContext(); - - IQueryable customCommandQuery = dbContext.CustomCommands; - CustomCommand customCommand = customCommandQuery - .Where(cc => cc.DiscordGuildId == guildId) - .First(cc => cc.Command == command); - - if (customCommand == null) - return NotFound(); - - dbContext.CustomCommands.Remove(customCommand); - await dbContext.SaveChangesAsync(); - - return NoContent(); - } - } -} From 8d072d48ebf6d537b058c68640497c9e208c856b Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Tue, 13 Oct 2020 01:15:40 +0200 Subject: [PATCH 3/5] Implement the dynamic crud endpoint --- .../App/ApiControllers/BaseApiController.cs | 11 +- .../ApiControllers/CustomCommandController.cs | 16 +- .../WebServer/Services/ValidationService.cs | 198 ++++++++++++++++++ ChaosBot/WebServer/Startup.cs | 1 + ChaosBot/wwwroot | 2 +- 5 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 ChaosBot/WebServer/Services/ValidationService.cs diff --git a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs index 38b96ca..cd9b039 100644 --- a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs +++ b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Dynamic; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using ChaosBot.Models; using ChaosBot.WebServer.Services; @@ -15,12 +16,15 @@ namespace ChaosBot.WebServer.App.ApiControllers public abstract class BaseApiController : Controller where T : class, new() { protected readonly AccessTokenCache AccessTokenCache; + protected readonly ValidationService ValidationService; protected BaseApiController( - AccessTokenCache accessTokenCache + AccessTokenCache accessTokenCache, + ValidationService validationService ) { AccessTokenCache = accessTokenCache; + ValidationService = validationService; } public async Task Index(ulong guildId) @@ -50,10 +54,13 @@ namespace ChaosBot.WebServer.App.ApiControllers return Content(JsonConvert.SerializeObject(response), new MediaTypeHeaderValue("application/json")); } - public async Task Upsert(ulong guildId, dynamic requestBody) + public async Task Upsert(ulong guildId, JsonElement requestBody) { if (!CheckPermissions.GetResult(AccessTokenCache, Request, guildId, out IActionResult result)) return result; + + if (!ValidationService.Validate(requestBody, GetValidationRules(), out string errors)) + return BadRequest(errors); await using ChaosbotContext dbContext = new ChaosbotContext(); diff --git a/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs index 14d1a8b..f631bd0 100644 --- a/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs +++ b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using ChaosBot.Models; using ChaosBot.WebServer.Models; @@ -15,9 +16,11 @@ namespace ChaosBot.WebServer.App.ApiControllers public class CustomCommandController : BaseApiController { public CustomCommandController( - AccessTokenCache accessTokenCache + AccessTokenCache accessTokenCache, + ValidationService validationService ) : base( - accessTokenCache + accessTokenCache, + validationService ) {} [HttpGet] @@ -31,7 +34,7 @@ namespace ChaosBot.WebServer.App.ApiControllers [Route("{guildId}")] public async Task UpsertAction( [FromRoute] ulong guildId, - [FromBody] dynamic requestBody) + [FromBody] JsonElement requestBody) { return await Upsert(guildId, requestBody); } @@ -64,7 +67,12 @@ namespace ChaosBot.WebServer.App.ApiControllers protected override Dictionary> GetValidationRules() { - return new Dictionary>(); + return new Dictionary> + { + {"Command", new List{"required", "type:string", "min:1", "max:128"}}, + {"Type", new List{"required", "type:integer", "in:CustomCommandType"}}, + {"Content", new List{"required", "type:string"}}, + }; } protected override UpsertCommandBuilder ApplyFilterForUpsert( diff --git a/ChaosBot/WebServer/Services/ValidationService.cs b/ChaosBot/WebServer/Services/ValidationService.cs new file mode 100644 index 0000000..696e66e --- /dev/null +++ b/ChaosBot/WebServer/Services/ValidationService.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; + +namespace ChaosBot.WebServer.Services +{ + public class ValidationService + { + public bool Validate(JsonElement requestBody, Dictionary> getValidationRules, out string error) + { + StringBuilder errorBuilder = new StringBuilder(); + + foreach (KeyValuePair> validationRule in getValidationRules) + { + string key = validationRule.Key; + dynamic value = GetValueFromRequest(requestBody, key); + + List rules = validationRule.Value; + + foreach (string rule in rules) + { + string[] ruleParts = rule.Split(':'); + string ruleType = ruleParts.First(); + + if (ruleType == null) + continue; + + ValidationResult result = ruleType switch + { + "required" => CheckRequired(key, value), + "type" => CheckType(key, value, ruleParts), + "min" => CheckMin(key, value, ruleParts), + "max" => CheckMax(key, value, ruleParts), + _ => new ValidationResult.Unknown() + }; + + if (result.GetError() != null) + { + errorBuilder.AppendLine($"[{result.GetKey()}] {result.GetError()}"); + break; + } + } + } + + error = errorBuilder.ToString(); + return error.Length == 0; + } + + private static dynamic GetValueFromRequest(JsonElement requestBody, string key) + { + JsonElement prop; + try + { + prop = requestBody.GetProperty(key); + } + catch (KeyNotFoundException) + { + return null; + } + + return prop.ValueKind switch + { + JsonValueKind.String => prop.GetString(), + JsonValueKind.Number => prop.GetInt64(), + JsonValueKind.True => prop.GetBoolean(), + JsonValueKind.False => prop.GetBoolean(), + _ => null + }; + } + + private ValidationResult CheckRequired(string key, dynamic value) + { + if (value != null) + return new ValidationResult.Success(); + return new ValidationResult.Failure(key, $"{key} is required"); + } + + private ValidationResult CheckType(string key, dynamic value, string[] ruleParts) + { + if (ruleParts.Length != 2) return new ValidationResult.Unknown(); + + Type type = ruleParts[1] switch + { + "string" => typeof(string), + "boolean" => typeof(bool), + "short" => typeof(short), + "ushort" => typeof(ushort), + "int" => typeof(int), + "uint" => typeof(uint), + "long" => typeof(long), + "ulong" => typeof(ulong), + _ => null + }; + + if (type == null) + return new ValidationResult.Unknown(); + + dynamic val = Convert.ChangeType(value, type); + if (val != null) + return new ValidationResult.Success(); + return new ValidationResult.Failure(key, $"{key} could not be interpreted as {ruleParts[1]}"); + } + + private ValidationResult CheckMin(string key, dynamic value, string[] ruleParts) + { + if (ruleParts.Length != 2) return new ValidationResult.Unknown(); + + if (value is string stringValue) + { + int minLength = Convert.ToInt32(ruleParts[1]); + if (stringValue.Length < minLength) + return new ValidationResult.Failure(key, $"{key} cannot be shorter than {minLength} characters"); + } else if (value is ulong intValue) + { + ulong minSize = Convert.ToUInt64(ruleParts[1]); + if (intValue < minSize) + return new ValidationResult.Failure(key, $"{key} must be greater than or equal to {minSize}"); + } else if (value is double floatValue) + { + double minSize = Convert.ToDouble(ruleParts[1]); + if (floatValue < minSize) + return new ValidationResult.Failure(key, $"{key} must be greater than or equal to {minSize}"); + } + else + { + return new ValidationResult.Unknown(); + } + + return new ValidationResult.Success(); + } + + private ValidationResult CheckMax(string key, dynamic value, string[] ruleParts) + { + if (ruleParts.Length != 2) return new ValidationResult.Unknown(); + + if (value is string stringValue) + { + int maxLength = Convert.ToInt32(ruleParts[1]); + if (stringValue.Length > maxLength) + return new ValidationResult.Failure(key, $"{key} cannot be longer than {maxLength} characters"); + } else if (value is ulong intValue) + { + ulong maxSize = Convert.ToUInt64(ruleParts[1]); + if (intValue > maxSize) + return new ValidationResult.Failure(key, $"{key} must be less than or equal to {maxSize}"); + } else if (value is double floatValue) + { + double maxSize = Convert.ToDouble(ruleParts[1]); + if (floatValue > maxSize) + return new ValidationResult.Failure(key, $"{key} must be less than or equal to {maxSize}"); + } + else + { + return new ValidationResult.Unknown(); + } + + return new ValidationResult.Success(); + } + } + + internal class ValidationResult + { + private readonly string _errorMessage; + private readonly string _key; + + private ValidationResult() + { + _errorMessage = null; + _key = null; + } + + private ValidationResult(string key, string errorMessage) + { + _errorMessage = errorMessage; + _key = key; + } + + internal class Success : ValidationResult {} + + internal class Failure : ValidationResult + { + public Failure(string key, string message) : base(key, message) {} + } + internal class Unknown : ValidationResult {} + + public string GetError() + { + return this._errorMessage; + } + + public string GetKey() + { + return this._key; + } + } +} diff --git a/ChaosBot/WebServer/Startup.cs b/ChaosBot/WebServer/Startup.cs index 42ac686..90607ff 100644 --- a/ChaosBot/WebServer/Startup.cs +++ b/ChaosBot/WebServer/Startup.cs @@ -33,6 +33,7 @@ namespace ChaosBot.WebServer .AddSingleton(sp => new AccessTokenCache()) .AddSingleton(sp => new DiscordInviteGenerator()) .AddSingleton(sp => new HttpClient()) + .AddSingleton(sp => new ValidationService()) ; } diff --git a/ChaosBot/wwwroot b/ChaosBot/wwwroot index 07d2c3d..56e8caf 160000 --- a/ChaosBot/wwwroot +++ b/ChaosBot/wwwroot @@ -1 +1 @@ -Subproject commit 07d2c3dc0e7ba5bfaa8eac94dad814f1a333a6eb +Subproject commit 56e8caf708d791a2b05b12e82fd407905147fafd From 89175ef9da9f434e6b8d3cc7264399f72436bdec Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Tue, 13 Oct 2020 01:35:48 +0200 Subject: [PATCH 4/5] Fix upsert --- .../App/ApiControllers/BaseApiController.cs | 15 ++++++++-- .../ApiControllers/CustomCommandController.cs | 6 ++++ .../WebServer/Services/JsonElementHelper.cs | 30 +++++++++++++++++++ .../WebServer/Services/ValidationService.cs | 24 +-------------- 4 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 ChaosBot/WebServer/Services/JsonElementHelper.cs diff --git a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs index cd9b039..5e6d513 100644 --- a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs +++ b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -64,14 +65,23 @@ namespace ChaosBot.WebServer.App.ApiControllers await using ChaosbotContext dbContext = new ChaosbotContext(); - T databaseObject = new T(); + T databaseObject = SetDefaultFieldsForUpsert(new T(), guildId); foreach (string key in GetValidationRules().Keys) { + Type type = databaseObject?.GetType()?.GetProperty(key)?.PropertyType; + if (type == null) continue; + + dynamic value; + if (type.IsEnum) + value = Convert.ChangeType(Enum.ToObject(type, JsonElementHelper.GetValueFromRequest(requestBody, key)), type); + else + value = Convert.ChangeType(JsonElementHelper.GetValueFromRequest(requestBody, key), type); + databaseObject .GetType() .GetProperty(key) - ?.SetValue(databaseObject, requestBody.GetType().GetProperty(key)?.GetValue(requestBody, null)); + ?.SetValue(databaseObject, value); } await ApplyFilterForUpsert(GetBasicQuery(dbContext).Upsert(databaseObject)).RunAsync(); @@ -110,6 +120,7 @@ namespace ChaosBot.WebServer.App.ApiControllers protected abstract UpsertCommandBuilder ApplyFilterForUpsert(UpsertCommandBuilder builder); protected abstract T FilterQueryForDeletion(IQueryable query, ulong guildId, TDeleteParameter deleteParameter); protected abstract List FilterQueryMultipleForDeletion(IQueryable query, ulong guildId, TDeleteParameter deleteParameter); + protected abstract T SetDefaultFieldsForUpsert(T obj, ulong guildId); private class DynamicResponse : DynamicObject { diff --git a/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs index f631bd0..9546cad 100644 --- a/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs +++ b/ChaosBot/WebServer/App/ApiControllers/CustomCommandController.cs @@ -93,5 +93,11 @@ namespace ChaosBot.WebServer.App.ApiControllers { return new List(); } + + protected override CustomCommand SetDefaultFieldsForUpsert(CustomCommand obj, ulong guildId) + { + obj.DiscordGuildId = guildId; + return obj; + } } } diff --git a/ChaosBot/WebServer/Services/JsonElementHelper.cs b/ChaosBot/WebServer/Services/JsonElementHelper.cs new file mode 100644 index 0000000..01a805b --- /dev/null +++ b/ChaosBot/WebServer/Services/JsonElementHelper.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Text.Json; + +namespace ChaosBot.WebServer.Services +{ + public static class JsonElementHelper + { + public static dynamic GetValueFromRequest(JsonElement requestBody, string key) + { + JsonElement prop; + try + { + prop = requestBody.GetProperty(key); + } + catch (KeyNotFoundException) + { + return null; + } + + return prop.ValueKind switch + { + JsonValueKind.String => prop.GetString(), + JsonValueKind.Number => prop.GetInt64(), + JsonValueKind.True => prop.GetBoolean(), + JsonValueKind.False => prop.GetBoolean(), + _ => null + }; + } + } +} diff --git a/ChaosBot/WebServer/Services/ValidationService.cs b/ChaosBot/WebServer/Services/ValidationService.cs index 696e66e..c90f040 100644 --- a/ChaosBot/WebServer/Services/ValidationService.cs +++ b/ChaosBot/WebServer/Services/ValidationService.cs @@ -15,7 +15,7 @@ namespace ChaosBot.WebServer.Services foreach (KeyValuePair> validationRule in getValidationRules) { string key = validationRule.Key; - dynamic value = GetValueFromRequest(requestBody, key); + dynamic value = JsonElementHelper.GetValueFromRequest(requestBody, key); List rules = validationRule.Value; @@ -48,28 +48,6 @@ namespace ChaosBot.WebServer.Services return error.Length == 0; } - private static dynamic GetValueFromRequest(JsonElement requestBody, string key) - { - JsonElement prop; - try - { - prop = requestBody.GetProperty(key); - } - catch (KeyNotFoundException) - { - return null; - } - - return prop.ValueKind switch - { - JsonValueKind.String => prop.GetString(), - JsonValueKind.Number => prop.GetInt64(), - JsonValueKind.True => prop.GetBoolean(), - JsonValueKind.False => prop.GetBoolean(), - _ => null - }; - } - private ValidationResult CheckRequired(string key, dynamic value) { if (value != null) From f4d4ff031f97e1482f1f723332695f7abaa456e4 Mon Sep 17 00:00:00 2001 From: Daniel-I-Am Date: Tue, 13 Oct 2020 01:43:49 +0200 Subject: [PATCH 5/5] Fix delete endpoint --- ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs | 5 ++--- ChaosBot/wwwroot | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs index 5e6d513..fe079af 100644 --- a/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs +++ b/ChaosBot/WebServer/App/ApiControllers/BaseApiController.cs @@ -97,9 +97,8 @@ namespace ChaosBot.WebServer.App.ApiControllers await using ChaosbotContext dbContext = new ChaosbotContext(); - IQueryable query = GetBasicQuery(dbContext); - List toDelete = FilterQueryMultipleForDeletion(query, guildId, deleteParameter); - toDelete.Add(FilterQueryForDeletion(query, guildId, deleteParameter)); + List toDelete = FilterQueryMultipleForDeletion(GetBasicQuery(dbContext), guildId, deleteParameter); + toDelete.Add(FilterQueryForDeletion(GetBasicQuery(dbContext), guildId, deleteParameter)); if (toDelete.Count == 0) return NotFound(); diff --git a/ChaosBot/wwwroot b/ChaosBot/wwwroot index 56e8caf..154e88a 160000 --- a/ChaosBot/wwwroot +++ b/ChaosBot/wwwroot @@ -1 +1 @@ -Subproject commit 56e8caf708d791a2b05b12e82fd407905147fafd +Subproject commit 154e88ae2ef4733b97efbe3f6193973723f4d571