diff --git a/BantFlags/Controllers/FlagsController.cs b/BantFlags/Controllers/FlagsController.cs index df7a0f5..19a8577 100644 --- a/BantFlags/Controllers/FlagsController.cs +++ b/BantFlags/Controllers/FlagsController.cs @@ -33,23 +33,16 @@ namespace BantFlags.Controllers [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task Get([FromForm]string post_nrs, [FromForm]string board, [FromForm]int? version) { - try // We only care if the post if valid. - { - int ver = version ?? 0; + int ver = version ?? 0; - if (ver > 1) - { - // Improved data structuring, see Docs/GetPosts - return Json(await Database.GetPosts_V2(post_nrs)); - } - else - { - return Json(await Database.GetPosts_V1(post_nrs)); - } + if (ver > 1) + { + // Improved data structuring, see Docs/GetPosts + return Json(await Database.GetPosts_V2(post_nrs)); } - catch (Exception e) + else { - return Problem(ErrorMessage(e), statusCode: StatusCodes.Status400BadRequest); + return Json(await Database.GetPosts_V1(post_nrs)); } } @@ -67,77 +60,23 @@ namespace BantFlags.Controllers [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task Post([FromForm]string post_nr, [FromForm]string board, [FromForm]string regions, [FromForm]int? version) { - try // We only care if the post if valid. - { - string[] flags; - int ver = version ?? 0; - - if (ver > 1) - { - flags = regions.Split(","); - } - else - { - flags = regions.Split("||"); - } - - // TODO: Currently we skip over invalid flags. Should we error instead? - // We can't easily format it like in the current bantflags - we really should continue to - // return "empty, or there were errors. Re-set your flags.", for compatibility, but we'd - // have to store that as a flag in the database and perform an expensive string comparison - // to stop people selecting it. - // Do we care if people select the broken flag? - var validFlags = flags.Where(x => Database.KnownFlags().Contains(x)); - - for (int i = 0; i < flags.Length; i++) - { - if (!Database.KnownFlags().Contains(flags[i])) - { - flags[i] = "empty, or there were errors. Re-set your flags."; - } - } - - var numberOfFlags = validFlags.Count(); - if (numberOfFlags <= 0 || numberOfFlags > 25) - { - throw new ArgumentException("Your post didn't include any flags, or your flags were invalid."); - } - - FlagModel post = new FlagModel - { - PostNumber = int.TryParse(post_nr, out int temp) ? temp : throw new ArgumentException("Invalid post number."), - Board = board == "bant" ? "bant" : throw new ArgumentException("Board parameter wasn't formatted correctly."), - Flags = validFlags - }; + string splitFlag = (version ?? 0) > 1 ? "," : "||"; // comma for v2+, else || for backwards compatibility. - await Database.InsertPost(post); + (bool isValid, FlagModel post, string errorMessage) = FlagModel.Create(post_nr, board, regions, splitFlag, Database.KnownFlags); - return Ok(post); - } - catch (Exception e) + if (!isValid) { - return Problem(detail: ErrorMessage(e), statusCode: StatusCodes.Status400BadRequest); + return Problem(errorMessage, statusCode: StatusCodes.Status400BadRequest); } + + await Database.InsertPost(post); + + return Ok(post); } [HttpGet] [Route("flags")] [ProducesResponseType(StatusCodes.Status200OK)] - public IActionResult Flags() => Ok(Database.FlagList()); - - /// - /// Creates an error mesage to send in case of 400 bad request, without giving away too much information. - /// - /// Raw exception to be filtered. - private string ErrorMessage(Exception exception) => - exception switch - { - NullReferenceException _ => "Some data wasn't initialised. Are you sending everything?", - DbException _ => "Internal database error.", - ArgumentNullException _ => "No regions sent", - ArgumentException e => e.Message, // We create all arguement exceptions here, we can just pass the message on. - Exception e => e.Message, // Don't do this. - _ => "how in the hell" - }; // This needs more testing. + public IActionResult Flags() => Ok(Database.FlagList); } } \ No newline at end of file diff --git a/BantFlags/Data/Database/DatabaseService.cs b/BantFlags/Data/Database/DatabaseService.cs index 7d4d435..4f81503 100644 --- a/BantFlags/Data/Database/DatabaseService.cs +++ b/BantFlags/Data/Database/DatabaseService.cs @@ -12,30 +12,24 @@ namespace BantFlags.Data.Database { private MySqlConnectionPool ConnectionPool { get; } - private string Flags { get; set; } + public string FlagList { get; private set; } - private HashSet FlagsHash { get; set; } + public HashSet KnownFlags { get; private set; } public DatabaseService(DatabaseServiceConfig dbConfig) { ConnectionPool = new MySqlConnectionPool(dbConfig.ConnectionString, dbConfig.PoolSize); - var flags = GetFlags().Result; // It's okay to error here since it's only initialised at startup. - - Flags = string.Join("\n", flags); - FlagsHash = flags.ToHashSet(); + UpdateKnownFlags().Wait(); // It's okay to deadlock here since it's only initialised at startup. } - public string FlagList() => Flags; - - public HashSet KnownFlags() => FlagsHash; - public async Task UpdateKnownFlags() { var flags = await GetFlags(); + flags.Remove("empty, or there were errors. Re-set your flags."); - Flags = string.Join("\n", flags); - FlagsHash = flags.ToHashSet(); + FlagList = string.Join("\n", flags); + KnownFlags = flags.ToHashSet(); } public async Task DeleteFlagsAsync(List flags) @@ -46,8 +40,6 @@ namespace BantFlags.Data.Database flags.ForEach(async f => await query.SetParam("@flag", f.Name) .ExecuteNonQueryAsync(reuse: true)); - - return; } public async Task RenameFlagsAsync(List flags) @@ -79,8 +71,6 @@ namespace BantFlags.Data.Database .ExecuteNonQueryAsync(reuse: true)); } } - - return; } /// @@ -106,8 +96,6 @@ namespace BantFlags.Data.Database flags.ForEach(async f => await query.SetParam("@flag", f.Name) .ExecuteNonQueryAsync(reuse: true)); - - return; } } diff --git a/BantFlags/Data/Database/GetPosts.cs b/BantFlags/Data/Database/GetPosts.cs index 9d05ea0..c523b8b 100644 --- a/BantFlags/Data/Database/GetPosts.cs +++ b/BantFlags/Data/Database/GetPosts.cs @@ -31,7 +31,6 @@ namespace BantFlags.Data.Database List> posts = new List>(); var x = await GetPosts(input); - x.ForEach(x => posts.Add(new Dictionary { {"post_nr", x.Key.ToString() }, diff --git a/BantFlags/Data/FlagModel.cs b/BantFlags/Data/FlagModel.cs index ad49d4d..62fc5c4 100644 --- a/BantFlags/Data/FlagModel.cs +++ b/BantFlags/Data/FlagModel.cs @@ -1,13 +1,52 @@ using System.Collections.Generic; +using System.Linq; namespace BantFlags.Data { public class FlagModel { - public int PostNumber { get; set; } + public int PostNumber { get; private set; } - public string Board { get; set; } + public string Board { get; private set; } - public IEnumerable Flags { get; set; } + public string[] Flags { get; private set; } + + private FlagModel(int post_nr, string board, string[] flags) + { + PostNumber = post_nr; + Board = board; + Flags = flags; + } + + /// + /// A wrapper around post validation so it's all in one place. + /// + public static (bool, FlagModel, string) Create(string post_nr, string board, string regions, string splitFlag, HashSet knownFlags) + { + if (!int.TryParse(post_nr, out int postNumber)) + return (false, default, "Invalid post number."); + + if (board != "bant") + return (false, default, "Invalid board parameter."); + + if (regions == null) + regions = "somebrokenflagstringsothatwegettheemptyflagwhenweshould"; + + var flags = regions.Split(splitFlag); + + if (flags.Count() > 30) + return (false, default, "Too many flags."); + + foreach (string flag in flags) + { + if (!knownFlags.Contains(flag)) // Not ideal but it's better than doing it in the controller / passing the database here. + { + flags = new string[] { "empty, or there were errors. Re-set your flags." }; + break; + } + } + + return (true, new FlagModel(postNumber, board, flags), default); + } } } \ No newline at end of file diff --git a/BantFlags/Data/Staging.cs b/BantFlags/Data/Staging.cs index a731b05..0cb214c 100644 --- a/BantFlags/Data/Staging.cs +++ b/BantFlags/Data/Staging.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace BantFlags.Data { @@ -12,8 +13,15 @@ namespace BantFlags.Data public List DeletedFlags { get; set; } public List AddedFlags { get; set; } + /// + /// The current list of resolved flags including changes currently in Staging. + /// Exists here since it's a singleton. + /// public List Flags { get; set; } + /// + /// Used for commiting and unstaging staged flags. + /// public string Password { get; } public Staging(string password) diff --git a/BantFlags/Pages/Index.cshtml b/BantFlags/Pages/Index.cshtml index 3121bf7..9bb9cdb 100644 --- a/BantFlags/Pages/Index.cshtml +++ b/BantFlags/Pages/Index.cshtml @@ -10,4 +10,8 @@ Install Bantflags
-Official Thread \ No newline at end of file +
+Official Thread +
+
+Upload Flags \ No newline at end of file diff --git a/BantFlags/Pages/Upload.cshtml b/BantFlags/Pages/Upload.cshtml index 3dd9744..25b1833 100644 --- a/BantFlags/Pages/Upload.cshtml +++ b/BantFlags/Pages/Upload.cshtml @@ -49,6 +49,8 @@
+
+
@if (Model.staging.AddedFlags.Any()) { @@ -115,17 +117,19 @@ }
+@section Head { + +} + @section Scripts { @* Place flag image inside the