From b23261598b0fd081500d92e5bbaf6dae1d2d55ad Mon Sep 17 00:00:00 2001 From: C-xC-c Date: Wed, 11 Dec 2019 14:28:44 +0000 Subject: [PATCH] Add support for /api/get and api/post V2. increase max flags to 24 + 1 and enforce server side. --- BantFlags/Controllers/FlagsController.cs | 42 ++++-- .../bantflags.meta.js => bantflags.meta.js | 2 +- .../bantflags.user.js => bantflags.user.js | 129 +++++++----------- 3 files changed, 82 insertions(+), 91 deletions(-) rename BantFlags/bantflags.meta.js => bantflags.meta.js (95%) rename BantFlags/bantflags.user.js => bantflags.user.js (76%) diff --git a/BantFlags/Controllers/FlagsController.cs b/BantFlags/Controllers/FlagsController.cs index 51cb739..8aa2308 100644 --- a/BantFlags/Controllers/FlagsController.cs +++ b/BantFlags/Controllers/FlagsController.cs @@ -37,7 +37,8 @@ namespace BantFlags.Controllers [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 { int ver = int.TryParse(version, out int x) ? x : 0; @@ -58,23 +59,47 @@ namespace BantFlags.Controllers } } + /// + /// Posts flags in the database. + /// + /// The post number to associate the flags to. + /// /bant/. + /// List of flags to associate with the post. Split by "||" in API V1 and "," in V2. [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) - { + 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; + 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? - var flags = regions.Split("||").Where(x => DatabaseFlags.Contains(x)); + var validFlags = flags.Where(x => DatabaseFlags.Contains(x)); + + 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 FormatException("Bad post number."), - Board = board == "bant" ? "bant" : throw new FormatException("Board parameter wasn't formatted correctly."), - Flags = flags.Count() > 0 ? flags : throw new FormatException("Your post didn't include any flags, or your flags were invalid.") + 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 }; await Database.InsertPost(post); @@ -99,9 +124,10 @@ namespace BantFlags.Controllers private string ErrorMessage(Exception exception) => exception switch { - FormatException e => e.Message, + NullReferenceException _ => "Some data wasn't initialised. Are you sending everything?", DbException _ => "Internal database error.", ArgumentNullException _ => "No regions sent", + ArgumentException e => e.Message, Exception e => e.Message, // Don't do this. _ => "how in the hell" }; // This needs more testing. diff --git a/BantFlags/bantflags.meta.js b/bantflags.meta.js similarity index 95% rename from BantFlags/bantflags.meta.js rename to bantflags.meta.js index 8d66d2b..0a7a0fd 100644 --- a/BantFlags/bantflags.meta.js +++ b/bantflags.meta.js @@ -10,7 +10,7 @@ // @exclude http*://archive.nyafuu.org/bant/statistics/ // @exclude http*://archived.moe/bant/statistics/ // @exclude http*://thebarchive.com/bant/statistics/ -// @version 0.8.0 +// @version 1.0.0 // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue diff --git a/BantFlags/bantflags.user.js b/bantflags.user.js similarity index 76% rename from BantFlags/bantflags.user.js rename to bantflags.user.js index 34d62b3..2da80e2 100644 --- a/BantFlags/bantflags.user.js +++ b/bantflags.user.js @@ -10,7 +10,7 @@ // @exclude http*://archive.nyafuu.org/bant/statistics/ // @exclude http*://archived.moe/bant/statistics/ // @exclude http*://thebarchive.com/bant/statistics/ -// @version 0.7.2 +// @version 1.0.0 // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue @@ -30,17 +30,19 @@ const debugMode = true; // const postRemoveCounter = 60; const requestRetryInterval = 5000; // TODO: maybe a max retries counter? -const regionVariable = 'regionVariableAPI2'; // TODO: This is where GM stores flags permanantly. We could use a better name. const regionDivider = "||"; //TODO: We can probably remove this and seperate by , const is_archive = window.location.host !== "boards.4chan.org"; const boardID = "bant"; //TODO: Hardcode /bant/ or accept other boards. -const version = 1; // Breaking changes. -const back_end = 'https://flags.plum.moe/'; +const version = 2; // Breaking changes. +const back_end = 'https://localhost:44366/'; const api_flags = 'api/flags'; const flag_dir = 'flags/'; const api_get = 'api/get'; const api_post = 'api/post'; +// If you increase this the server will ignore your post. +const max_flags = 24; + var regions = []; // The flags we have selected. var postNrs = []; // all post numbers in the thread. @@ -48,11 +50,6 @@ var postNrs = []; // all post numbers in the thread. // DO NOT EDIT ANYTHING IN THIS SCRIPT DIRECTLY - YOUR FLAGS SHOULD BE CONFIGURED USING THE CONFIGURATION BOXES // -function ToggleFlagButton() { - let flagButton = document.getElementById("append_flag_button").disabled; - flagButton = flagButton === true ? false : true; -} - let elementsInClass = x => document.getElementsByClassName(x); let sliceCall = x => Array.prototype.slice.call(x); let firstChildInClass = (parent, className) => parent.getElementsByClassName(className)[0]; @@ -78,10 +75,10 @@ function debug(text) { } /** Wrapper around GM_xmlhttpRequest - * @param {string} method - The HTTP method (GET, POST) - * @param {string} url - The URL of the request - * @param {string} data - Data sent inn the form body - * @param {Function} func - The function run after onload. Response data is sent directly to it. */ + * @param {string} method - The HTTP method (GET, POST) + * @param {string} url - The URL of the request + * @param {string} data - Data sent inn the form body + * @param {Function} func - The function run after onload. Response data is sent directly to it. */ function MakeRequest(method, url, data, func) { GM_xmlhttpRequest({ method: method, @@ -125,10 +122,10 @@ var nsetup = { // not anymore a clone of the original setup let flagSelect = document.getElementById("flagSelect"); let flagLoad = document.getElementById('flagLoad'); - let x = resp.responseText.split('\n'); + let flagsSupported = resp.responseText.split('\n'); - for (var i = 0; i < x.length; i++) { - let flag = x[i]; + for (var i = 0; i < flagsSupported.length; i++) { + let flag = flagsSupported[i]; flagSelect.appendChild(createAndAssign('option', { value: flag, innerHTML: "" + " " + flag @@ -141,11 +138,10 @@ var nsetup = { // not anymore a clone of the original setup flagLoad.removeEventListener('click', nsetup.fillHtml); }); }, - save: function (k, v) { - GM_setValue(nsetup.namespace + k, v); - regions = nsetup.load(regionVariable); + save: function (v) { + GM_setValue(nsetup.namespace, v); + regions = GM_getValue(nsetup.namespace); }, - load: k => GM_getValue(nsetup.namespace + k), // We can get rid of this and just pass regionVariable to GM_getvalue in the two places we need it. setFlag: function (flag) { // place a flag from the selector to the flags array variable and create an element in the flags_container div let UID = Math.random().toString(36).substring(7); let flagName = flag ? flag : document.getElementById("flagSelect").value; @@ -158,21 +154,20 @@ var nsetup = { // not anymore a clone of the original setup className: 'bantflags_flag' })); - let flagsCount = flagContainer.children.length; - if (flagsCount > 8) {// TODO: set to constant and enforce server side. - nsetup.gray("on"); - } // Why does 8 work? What happened to the async issue a moment ago? + if (flagContainer.children.length > max_flags) { + nsetup.ToggleFlagButton('off'); + } document.getElementById(UID).addEventListener("click", function () { let flagToRemove = document.getElementById(UID); flagToRemove.parentNode.removeChild(flagToRemove); - nsetup.gray("off"); - nsetup.save(regionVariable, nsetup.parse()); + nsetup.toggleFlagButton('on'); + nsetup.save(nsetup.parse()); }); if (!flag) { - nsetup.save(regionVariable, nsetup.parse()); + nsetup.save(nsetup.parse()); } }, @@ -193,14 +188,9 @@ var nsetup = { // not anymore a clone of the original setup nsetup.setFlag(regions[i]); } - document.getElementById("append_flag_button").addEventListener("click", (e) => { - if (nsetup.flagsLoaded) { - nsetup.setFlag(); - } - else { - alert('Load flags before adding them.'); - } - }); + document.getElementById('append_flag_button').addEventListener('click', + () => nsetup.flagsLoaded ? nsetup.setFlag() : alert('Load flags before adding them.')); + document.getElementById('flagLoad').addEventListener('click', nsetup.fillHtml); }, parse: function () { @@ -213,13 +203,11 @@ var nsetup = { // not anymore a clone of the original setup return flagsArray; }, - - // TODO: We should pass a bool to this? - gray: state => document.getElementById("append_flag_button").disabled = state === "on" ? true : false + ToggleFlagButton: state => document.getElementById('append_flag_button').disabled = state === 'off' ? true : false }; -/** Prompt to set region if regionVariable is empty */ -regions = nsetup.load(regionVariable); // TODO: move this to other init stuff +/** Prompt to set region if regions is empty */ +regions = GM_getValue(nsetup.namespace); // TODO: move this to other init stuff if (!regions) { regions = []; setTimeout(function () { @@ -249,36 +237,37 @@ function parseFoolFuukaPosts() { function onFlagsLoad(response) { // because we only care about the end result, not how we got there. + // grandparent -> first parent -> first child. let hopHTML = (post_nr, first, second) => firstChildInClass(firstChildInClass(document.getElementById(post_nr), first), second); - let MakeFlag = (flag) => createAndAssign('a', { - innerHTML: "", - className: "bantFlag", - target: "_blank" - }); + let MakeFlag = (flag) => + createAndAssign('a', { + innerHTML: "", + className: "bantFlag", + target: "_blank" + }); debug("JSON: " + response.responseText); var jsonData = JSON.parse(response.responseText); - jsonData.forEach(function (post) { - debug(post); + Object.keys(jsonData).forEach(function (post) { let flagContainer = is_archive - ? hopHTML(post.post_nr, "post_data", "post_type") - : hopHTML("pc" + post.post_nr, "postInfo", "nameBlock"); + ? hopHTML(post, "post_data", "post_type") + : hopHTML("pc" + post, "postInfo", "nameBlock"); let currentFlag = firstChildInClass(flagContainer, 'flag'); - let postedRegions = post.region.split(regionDivider); + let flags = jsonData[post]; // If we have a bantflag and the original post has a flag - if (postedRegions.length > 0 && currentFlag !== undefined) { - console.log("[BantFlags] Resolving flags for >>" + post.post_nr); + if (flags.length > 0 && currentFlag !== undefined) { + console.log("[BantFlags] Resolving flags for >>" + post); - for (var i = 0; i < postedRegions.length; i++) { - let flag = postedRegions[i]; + for (var i = 0; i < flags.length; i++) { + let flag = flags[i]; let newFlag = MakeFlag(flag); if (is_archive) { - newFlag.style = "padding: 0px 0px 0px " + (3 + 4 * (i > 0)) + "px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;"; + newFlag.style = "padding: 0px 0px 0px " + (3 + 2 * (i > 0)) + "px; vertical-align:;display: inline-block; width: 16px; height: 11px; position: relative;"; } flagContainer.append(newFlag); @@ -286,33 +275,9 @@ function onFlagsLoad(response) { console.log("\t -> " + flag); } } - - // TODO: This can be postNrs.pop()? - // postNrs are resolved and should be removed from this variable - var index = postNrs.indexOf(post.post_nr); - if (index > -1) { - postNrs.splice(index, 1); - } }); - // TODO: do I need this? - // Removing posts older than the time limit (they likely won't resolve) - var timestampMinusPostRemoveCounter = Math.round(+new Date() / 1000) - postRemoveCounter; //should i remove this? - - postNrs.forEach(function (post_nr) { - let dateTime = is_archive - - // lol didn't expect to get to use this again - ? hopHTML(post_nr, 'post_data', 'time_wrap') - : hopHTML("pc" + post_nr, 'postInfo', 'dateTime'); - - if (dateTime.getAttribute("data-utc") < timestampMinusPostRemoveCounter) { - var index = postNrs.indexOf(post_nr); - if (index > -1) { - postNrs.splice(index, 1); - } - } - }); + postNrs = []; } function resolveRefFlags() { @@ -366,7 +331,7 @@ if (!is_archive) { //setTimeout to support greasemonkey 1.x setTimeout(function () { - var data = "post_nr=" + encodeURIComponent(e.detail.postID) + "&board=" + encodeURIComponent(e.detail.boardID) + "®ions=" + encodeURIComponent(regions.slice().join(regionDivider)); + var data = "post_nr=" + encodeURIComponent(e.detail.postID) + "&board=" + encodeURIComponent(e.detail.boardID) + "®ions=" + encodeURIComponent(regions) + "&version=" + encodeURIComponent(version); MakeRequest(method, url, data, func); }, 0); }, false); @@ -377,7 +342,7 @@ if (!is_archive) { //setTimeout to support greasemonkey 1.x setTimeout(function () { - var data = "post_nr=" + encodeURIComponent(evDetail.postId) + "&board=" + encodeURIComponent(boardID) + "®ions=" + encodeURIComponent(regions.slice().join(regionDivider)); + var data = "post_nr=" + encodeURIComponent(evDetail.postId) + "&board=" + encodeURIComponent(boardID) + "®ions=" + encodeURIComponent(regions) + "&version=" + encodeURIComponent(version); MakeRequest(method, url, data, func); }, 0); }, false);