diff --git a/.gitignore b/.gitignore index f952f91..7bc0d44 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,7 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot -/BantFlags/wwwroot/flags/* +/BantFlags/wwwroot/flags/*.png # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/BantFlags/BantFlags.csproj b/BantFlags/BantFlags.csproj index 57a4f49..f6ba716 100644 --- a/BantFlags/BantFlags.csproj +++ b/BantFlags/BantFlags.csproj @@ -6,20 +6,18 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - - \ No newline at end of file diff --git a/BantFlags/Controllers/FlagsController.cs b/BantFlags/Controllers/FlagsController.cs index 8aa2308..0e5a170 100644 --- a/BantFlags/Controllers/FlagsController.cs +++ b/BantFlags/Controllers/FlagsController.cs @@ -3,7 +3,6 @@ using BantFlags.Data.Database; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; -using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Threading.Tasks; @@ -16,36 +15,31 @@ namespace BantFlags.Controllers { private DatabaseService Database { get; } - private string FlagList { get; set; } - - private HashSet DatabaseFlags { get; set; } - public FlagsController(DatabaseService db) { Database = db; - - // During initialisation we get the current list of flags for resolving supported flags and preventing duplicate flags from being created - var flags = Database.GetFlags().Result; // If this fails the program should exit anyway. - - FlagList = string.Join("\n", flags); - DatabaseFlags = flags.ToHashSet(); } + /// + /// Retrives flags from the database from the posts sent in post_nrs + /// + /// The comma seperated list of post numbers from the thread. + /// Currently should only be /bant/. Not checked here because we don't need to care what they send. + /// The version of the userscript. [HttpPost] [Route("get")] [Consumes("application/x-www-form-urlencoded")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task Get([FromForm]string post_nrs, [FromForm]string board, [FromForm]string version) - { // TODO: version can be an int?. - // int ver = verson ?? 0 - try + 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 = int.TryParse(version, out int x) ? x : 0; + int ver = version ?? 0; if (ver > 1) { - // Improved flag sending, see Docs/GetPosts + // Improved data structuring, see Docs/GetPosts return Json(await Database.GetPosts_V2(post_nrs)); } else @@ -63,15 +57,16 @@ namespace BantFlags.Controllers /// Posts flags in the database. /// /// The post number to associate the flags to. - /// /bant/. + /// Currently should only be /bant/. /// List of flags to associate with the post. Split by "||" in API V1 and "," in V2. + /// The version of the userscript. [HttpPost] [Route("post")] [Consumes("application/x-www-form-urlencoded")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task Post([FromForm]string post_nr, [FromForm]string board, [FromForm]string regions, [FromForm]int? version) - { // Should we rename regions? It'd be more idomatic for it to be flags or something but then we have to introduce a new variable that does the same thing. + { try // We only care if the post if valid. { string[] flags; @@ -87,7 +82,20 @@ namespace BantFlags.Controllers } // TODO: Currently we skip over invalid flags. Should we error instead? - var validFlags = flags.Where(x => DatabaseFlags.Contains(x)); + // 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) @@ -115,7 +123,7 @@ namespace BantFlags.Controllers [HttpGet] [Route("flags")] [ProducesResponseType(StatusCodes.Status200OK)] - public IActionResult Flags() => Ok(FlagList); + public IActionResult Flags() => Ok(Database.FlagList()); /// /// Creates an error mesage to send in case of 400 bad request, without giving away too much information. @@ -127,7 +135,7 @@ namespace BantFlags.Controllers NullReferenceException _ => "Some data wasn't initialised. Are you sending everything?", DbException _ => "Internal database error.", ArgumentNullException _ => "No regions sent", - ArgumentException e => e.Message, + ArgumentException e => e.Message, // We create all arguement exceptions here, so we can pass the message on. Exception e => e.Message, // Don't do this. _ => "how in the hell" }; // This needs more testing. diff --git a/BantFlags/Data/Database/DatabaseService.cs b/BantFlags/Data/Database/DatabaseService.cs index 627f85c..7d4d435 100644 --- a/BantFlags/Data/Database/DatabaseService.cs +++ b/BantFlags/Data/Database/DatabaseService.cs @@ -1,4 +1,5 @@ -using System.Data; +using System.Collections.Generic; +using System.Data; using System.Linq; using System.Threading.Tasks; @@ -11,9 +12,53 @@ namespace BantFlags.Data.Database { private MySqlConnectionPool ConnectionPool { get; } + private string Flags { get; set; } + + private HashSet FlagsHash { get; 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(); + } + + public string FlagList() => Flags; + + public HashSet KnownFlags() => FlagsHash; + + public async Task UpdateKnownFlags() + { + var flags = await GetFlags(); + + Flags = string.Join("\n", flags); + FlagsHash = flags.ToHashSet(); + } + + public async Task DeleteFlagsAsync(List flags) + { + using var rentedConnection = await ConnectionPool.RentConnectionAsync(); + using var query = rentedConnection.Object.UseStoredProcedure("delete_flag"); + + flags.ForEach(async f => + await query.SetParam("@flag", f.Name) + .ExecuteNonQueryAsync(reuse: true)); + + return; + } + + public async Task RenameFlagsAsync(List flags) + { + using var rentedConnection = await ConnectionPool.RentConnectionAsync(); + using var query = rentedConnection.Object.UseStoredProcedure("rename_flag"); + + flags.ForEach(async flag => + await query.SetParam("@old", flag.Name) + .SetParam("@new", flag.NewName) + .ExecuteNonQueryAsync(reuse: true)); } public async Task InsertPost(FlagModel post) @@ -41,7 +86,7 @@ namespace BantFlags.Data.Database /// /// Returns all of the flags that we support. /// - public async Task> GetFlags() + public async Task> GetFlags() { using var rentedConnected = await ConnectionPool.RentConnectionAsync(); @@ -49,7 +94,20 @@ namespace BantFlags.Data.Database .ExecuteTableAsync(); return table.AsEnumerable() - .Select(x => x.GetValue("flag")); + .Select(x => x.GetValue("flag")) + .ToList(); + } + + public async Task InsertFlagsAsync(List flags) + { + using var rentedConnection = await ConnectionPool.RentConnectionAsync(); + using var query = rentedConnection.Object.UseStoredProcedure("insert_flag"); + + flags.ForEach(async f => + await query.SetParam("@flag", f.Name) + .ExecuteNonQueryAsync(reuse: true)); + + return; } } diff --git a/BantFlags/Data/FlagModel.cs b/BantFlags/Data/FlagModel.cs index 5954099..ad49d4d 100644 --- a/BantFlags/Data/FlagModel.cs +++ b/BantFlags/Data/FlagModel.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace BantFlags.Data { diff --git a/BantFlags/Data/Staging.cs b/BantFlags/Data/Staging.cs new file mode 100644 index 0000000..a731b05 --- /dev/null +++ b/BantFlags/Data/Staging.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace BantFlags.Data +{ + /// + /// Singleton class comprised of objects used in/Upload. + /// It's a fucking mess and I hate it so much. + /// + public class Staging + { + public List RenamedFlags { get; set; } + public List DeletedFlags { get; set; } + public List AddedFlags { get; set; } + + public List Flags { get; set; } + + public string Password { get; } + + public Staging(string password) + { + RenamedFlags = new List(); + DeletedFlags = new List(); + AddedFlags = new List(); + Password = password; + } + + public void Clear() + { + RenamedFlags = new List(); + DeletedFlags = new List(); + AddedFlags = new List(); + } + } + + public class FormFlag + { + public string Name { get; set; } + public bool IsChecked { get; set; } + + public Method FormMethod { get; set; } + } + + public class RenameFlag : FormFlag + { + public string NewName { get; set; } + } + + public enum Method + { + Delete, + + Rename, + + Add + } +} \ No newline at end of file diff --git a/BantFlags/Pages/Index.cshtml b/BantFlags/Pages/Index.cshtml index 438db72..3121bf7 100644 --- a/BantFlags/Pages/Index.cshtml +++ b/BantFlags/Pages/Index.cshtml @@ -6,4 +6,8 @@ }

/bant/ Flags

-

Eメール: boku (at) plum (dot) moe

\ No newline at end of file +

Eメール: boku (at) plum (dot) moe

+ +Install Bantflags +
+Official Thread \ No newline at end of file diff --git a/BantFlags/Pages/Index.cshtml.cs b/BantFlags/Pages/Index.cshtml.cs index 984d628..a01038c 100644 --- a/BantFlags/Pages/Index.cshtml.cs +++ b/BantFlags/Pages/Index.cshtml.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; namespace BantFlags.Pages { @@ -11,7 +6,6 @@ namespace BantFlags.Pages { public void OnGet() { - } } } \ No newline at end of file diff --git a/BantFlags/Pages/Shared/_Layout.cshtml b/BantFlags/Pages/Shared/_Layout.cshtml index fcd2a8c..a82306c 100644 --- a/BantFlags/Pages/Shared/_Layout.cshtml +++ b/BantFlags/Pages/Shared/_Layout.cshtml @@ -8,5 +8,6 @@ @RenderBody() + @RenderSection("Scripts", required: false) \ No newline at end of file diff --git a/BantFlags/Pages/Upload.cshtml b/BantFlags/Pages/Upload.cshtml new file mode 100644 index 0000000..3dd9744 --- /dev/null +++ b/BantFlags/Pages/Upload.cshtml @@ -0,0 +1,131 @@ +@page +@using BantFlags.Data +@model BantFlags.UploadModel +@{ + ViewData["Title"] = "Upload"; + Layout = "~/Pages/Shared/_Layout.cshtml"; +} + +

Upload

+ +@Model.Message + +

Add a Flag

+
+ + @Html.CheckBoxFor(model => model.ShouldGloss)Apply Gloss? +
+
+ +
+ +

Manage Existing Flags

+
+ + + + +
+
+ + +
+ +

Commit Changes

+
+ + +
+
+ +
+ +

Pending Changes

+
+ + + + @if (Model.staging.AddedFlags.Any()) + { +

New Flags

+
+ + @foreach (FormFlag flag in Model.staging.AddedFlags) + { +
+ +
+ @flag.Name + + + +
+ +
+ } +
+ } + + @if (Model.staging.DeletedFlags.Any()) + { +

Deleted Flags

+
+ @foreach (FormFlag flag in Model.staging.DeletedFlags) + { +
+ +
+ @flag.Name + + + +
+ +
+ } +
+ + } + + @if (Model.staging.RenamedFlags.Any()) + { +

Renamed Flags

+
+ @foreach (RenameFlag flag in Model.staging.RenamedFlags) + { +
+ +
+ @flag.NewName + + + + +
+ +
+ + } +
+ } +
+ +@section Scripts { + @* Place flag image inside the