Add support for /api/get and api/post V2. increase max flags to 24 + 1 and enforce server side.

dotnetflags
C-xC-c 5 years ago
parent 1787fb824c
commit b23261598b

@ -37,7 +37,8 @@ namespace BantFlags.Controllers
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Get([FromForm]string post_nrs, [FromForm]string board, [FromForm]string version) public async Task<IActionResult> Get([FromForm]string post_nrs, [FromForm]string board, [FromForm]string version)
{ { // TODO: version can be an int?.
// int ver = verson ?? 0
try try
{ {
int ver = int.TryParse(version, out int x) ? x : 0; int ver = int.TryParse(version, out int x) ? x : 0;
@ -58,23 +59,47 @@ namespace BantFlags.Controllers
} }
} }
/// <summary>
/// Posts flags in the database.
/// </summary>
/// <param name="post_nr">The post number to associate the flags to.</param>
/// <param name="board">/bant/.</param>
/// <param name="regions">List of flags to associate with the post. Split by "||" in API V1 and "," in V2.</param>
[HttpPost] [HttpPost]
[Route("post")] [Route("post")]
[Consumes("application/x-www-form-urlencoded")] [Consumes("application/x-www-form-urlencoded")]
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Post([FromForm]string post_nr, [FromForm]string board, [FromForm]string regions) public async Task<IActionResult> 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. 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? // 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 FlagModel post = new FlagModel
{ {
PostNumber = int.TryParse(post_nr, out int temp) ? temp : throw new FormatException("Bad post number."), PostNumber = int.TryParse(post_nr, out int temp) ? temp : throw new ArgumentException("Invalid post number."),
Board = board == "bant" ? "bant" : throw new FormatException("Board parameter wasn't formatted correctly."), Board = board == "bant" ? "bant" : throw new ArgumentException("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.") Flags = validFlags
}; };
await Database.InsertPost(post); await Database.InsertPost(post);
@ -99,9 +124,10 @@ namespace BantFlags.Controllers
private string ErrorMessage(Exception exception) => private string ErrorMessage(Exception exception) =>
exception switch exception switch
{ {
FormatException e => e.Message, NullReferenceException _ => "Some data wasn't initialised. Are you sending everything?",
DbException _ => "Internal database error.", DbException _ => "Internal database error.",
ArgumentNullException _ => "No regions sent", ArgumentNullException _ => "No regions sent",
ArgumentException e => e.Message,
Exception e => e.Message, // Don't do this. Exception e => e.Message, // Don't do this.
_ => "how in the hell" _ => "how in the hell"
}; // This needs more testing. }; // This needs more testing.

@ -10,7 +10,7 @@
// @exclude http*://archive.nyafuu.org/bant/statistics/ // @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/ // @exclude http*://archived.moe/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/ // @exclude http*://thebarchive.com/bant/statistics/
// @version 0.8.0 // @version 1.0.0
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant GM_getValue // @grant GM_getValue
// @grant GM_setValue // @grant GM_setValue

@ -10,7 +10,7 @@
// @exclude http*://archive.nyafuu.org/bant/statistics/ // @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/ // @exclude http*://archived.moe/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/ // @exclude http*://thebarchive.com/bant/statistics/
// @version 0.7.2 // @version 1.0.0
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant GM_getValue // @grant GM_getValue
// @grant GM_setValue // @grant GM_setValue
@ -30,17 +30,19 @@ const debugMode = true;
// //
const postRemoveCounter = 60; const postRemoveCounter = 60;
const requestRetryInterval = 5000; // TODO: maybe a max retries counter? 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 regionDivider = "||"; //TODO: We can probably remove this and seperate by ,
const is_archive = window.location.host !== "boards.4chan.org"; const is_archive = window.location.host !== "boards.4chan.org";
const boardID = "bant"; //TODO: Hardcode /bant/ or accept other boards. const boardID = "bant"; //TODO: Hardcode /bant/ or accept other boards.
const version = 1; // Breaking changes. const version = 2; // Breaking changes.
const back_end = 'https://flags.plum.moe/'; const back_end = 'https://localhost:44366/';
const api_flags = 'api/flags'; const api_flags = 'api/flags';
const flag_dir = 'flags/'; const flag_dir = 'flags/';
const api_get = 'api/get'; const api_get = 'api/get';
const api_post = 'api/post'; 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 regions = []; // The flags we have selected.
var postNrs = []; // all post numbers in the thread. 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 // 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 elementsInClass = x => document.getElementsByClassName(x);
let sliceCall = x => Array.prototype.slice.call(x); let sliceCall = x => Array.prototype.slice.call(x);
let firstChildInClass = (parent, className) => parent.getElementsByClassName(className)[0]; let firstChildInClass = (parent, className) => parent.getElementsByClassName(className)[0];
@ -125,10 +122,10 @@ var nsetup = { // not anymore a clone of the original setup
let flagSelect = document.getElementById("flagSelect"); let flagSelect = document.getElementById("flagSelect");
let flagLoad = document.getElementById('flagLoad'); 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++) { for (var i = 0; i < flagsSupported.length; i++) {
let flag = x[i]; let flag = flagsSupported[i];
flagSelect.appendChild(createAndAssign('option', { flagSelect.appendChild(createAndAssign('option', {
value: flag, value: flag,
innerHTML: "<img src=\"" + back_end + flag_dir + flag + ".png\"" + " title=\"" + flag + "\">" + " " + flag innerHTML: "<img src=\"" + back_end + flag_dir + flag + ".png\"" + " title=\"" + flag + "\">" + " " + flag
@ -141,11 +138,10 @@ var nsetup = { // not anymore a clone of the original setup
flagLoad.removeEventListener('click', nsetup.fillHtml); flagLoad.removeEventListener('click', nsetup.fillHtml);
}); });
}, },
save: function (k, v) { save: function (v) {
GM_setValue(nsetup.namespace + k, v); GM_setValue(nsetup.namespace, v);
regions = nsetup.load(regionVariable); 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 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 UID = Math.random().toString(36).substring(7);
let flagName = flag ? flag : document.getElementById("flagSelect").value; 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' className: 'bantflags_flag'
})); }));
let flagsCount = flagContainer.children.length; if (flagContainer.children.length > max_flags) {
if (flagsCount > 8) {// TODO: set to constant and enforce server side. nsetup.ToggleFlagButton('off');
nsetup.gray("on"); }
} // Why does 8 work? What happened to the async issue a moment ago?
document.getElementById(UID).addEventListener("click", function () { document.getElementById(UID).addEventListener("click", function () {
let flagToRemove = document.getElementById(UID); let flagToRemove = document.getElementById(UID);
flagToRemove.parentNode.removeChild(flagToRemove); flagToRemove.parentNode.removeChild(flagToRemove);
nsetup.gray("off"); nsetup.toggleFlagButton('on');
nsetup.save(regionVariable, nsetup.parse()); nsetup.save(nsetup.parse());
}); });
if (!flag) { 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]); nsetup.setFlag(regions[i]);
} }
document.getElementById("append_flag_button").addEventListener("click", (e) => { document.getElementById('append_flag_button').addEventListener('click',
if (nsetup.flagsLoaded) { () => nsetup.flagsLoaded ? nsetup.setFlag() : alert('Load flags before adding them.'));
nsetup.setFlag();
}
else {
alert('Load flags before adding them.');
}
});
document.getElementById('flagLoad').addEventListener('click', nsetup.fillHtml); document.getElementById('flagLoad').addEventListener('click', nsetup.fillHtml);
}, },
parse: function () { parse: function () {
@ -213,13 +203,11 @@ var nsetup = { // not anymore a clone of the original setup
return flagsArray; return flagsArray;
}, },
ToggleFlagButton: state => document.getElementById('append_flag_button').disabled = state === 'off' ? true : false
// TODO: We should pass a bool to this?
gray: state => document.getElementById("append_flag_button").disabled = state === "on" ? true : false
}; };
/** Prompt to set region if regionVariable is empty */ /** Prompt to set region if regions is empty */
regions = nsetup.load(regionVariable); // TODO: move this to other init stuff regions = GM_getValue(nsetup.namespace); // TODO: move this to other init stuff
if (!regions) { if (!regions) {
regions = []; regions = [];
setTimeout(function () { setTimeout(function () {
@ -249,10 +237,12 @@ function parseFoolFuukaPosts() {
function onFlagsLoad(response) { function onFlagsLoad(response) {
// because we only care about the end result, not how we got there. // because we only care about the end result, not how we got there.
// grandparent -> first parent -> first child.
let hopHTML = (post_nr, first, second) => let hopHTML = (post_nr, first, second) =>
firstChildInClass(firstChildInClass(document.getElementById(post_nr), first), second); firstChildInClass(firstChildInClass(document.getElementById(post_nr), first), second);
let MakeFlag = (flag) => createAndAssign('a', { let MakeFlag = (flag) =>
createAndAssign('a', {
innerHTML: "<img src=\"" + back_end + flag_dir + flag + ".png\" title=\"" + flag + "\">", innerHTML: "<img src=\"" + back_end + flag_dir + flag + ".png\" title=\"" + flag + "\">",
className: "bantFlag", className: "bantFlag",
target: "_blank" target: "_blank"
@ -261,24 +251,23 @@ function onFlagsLoad(response) {
debug("JSON: " + response.responseText); debug("JSON: " + response.responseText);
var jsonData = JSON.parse(response.responseText); var jsonData = JSON.parse(response.responseText);
jsonData.forEach(function (post) { Object.keys(jsonData).forEach(function (post) {
debug(post);
let flagContainer = is_archive let flagContainer = is_archive
? hopHTML(post.post_nr, "post_data", "post_type") ? hopHTML(post, "post_data", "post_type")
: hopHTML("pc" + post.post_nr, "postInfo", "nameBlock"); : hopHTML("pc" + post, "postInfo", "nameBlock");
let currentFlag = firstChildInClass(flagContainer, 'flag'); 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 we have a bantflag and the original post has a flag
if (postedRegions.length > 0 && currentFlag !== undefined) { if (flags.length > 0 && currentFlag !== undefined) {
console.log("[BantFlags] Resolving flags for >>" + post.post_nr); console.log("[BantFlags] Resolving flags for >>" + post);
for (var i = 0; i < postedRegions.length; i++) { for (var i = 0; i < flags.length; i++) {
let flag = postedRegions[i]; let flag = flags[i];
let newFlag = MakeFlag(flag); let newFlag = MakeFlag(flag);
if (is_archive) { 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); flagContainer.append(newFlag);
@ -286,33 +275,9 @@ function onFlagsLoad(response) {
console.log("\t -> " + flag); 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? postNrs = [];
// 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);
}
}
});
} }
function resolveRefFlags() { function resolveRefFlags() {
@ -366,7 +331,7 @@ if (!is_archive) {
//setTimeout to support greasemonkey 1.x //setTimeout to support greasemonkey 1.x
setTimeout(function () { setTimeout(function () {
var data = "post_nr=" + encodeURIComponent(e.detail.postID) + "&board=" + encodeURIComponent(e.detail.boardID) + "&regions=" + encodeURIComponent(regions.slice().join(regionDivider)); var data = "post_nr=" + encodeURIComponent(e.detail.postID) + "&board=" + encodeURIComponent(e.detail.boardID) + "&regions=" + encodeURIComponent(regions) + "&version=" + encodeURIComponent(version);
MakeRequest(method, url, data, func); MakeRequest(method, url, data, func);
}, 0); }, 0);
}, false); }, false);
@ -377,7 +342,7 @@ if (!is_archive) {
//setTimeout to support greasemonkey 1.x //setTimeout to support greasemonkey 1.x
setTimeout(function () { setTimeout(function () {
var data = "post_nr=" + encodeURIComponent(evDetail.postId) + "&board=" + encodeURIComponent(boardID) + "&regions=" + encodeURIComponent(regions.slice().join(regionDivider)); var data = "post_nr=" + encodeURIComponent(evDetail.postId) + "&board=" + encodeURIComponent(boardID) + "&regions=" + encodeURIComponent(regions) + "&version=" + encodeURIComponent(version);
MakeRequest(method, url, data, func); MakeRequest(method, url, data, func);
}, 0); }, 0);
}, false); }, false);
Loading…
Cancel
Save