123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- const http = require("http");
- const convertFileFormat = require("../src/fileFormatConverter");
- const httpServer = require("../src/httpServer");
- const parseURL = require("../src/parseURL");
- const parseJokes = require("../src/parseJokes");
- const languages = require("../src/languages");
- const tr = require("../src/translate");
- const FilteredJoke = require("../src/classes/FilteredJoke");
- const jsl = require("svjsl");
- const settings = require("../settings");
- jsl.unused(http);
- const meta = {
- "name": "Joke",
- "desc": "Returns a joke from the specified category / categories that is also matching the provided (optional) filters",
- "usage": {
- "method": "GET",
- "url": `${settings.info.docsURL}/joke/{CATEGORY}`,
- "supportedParams": [
- "safe-mode",
- "format",
- "blacklistFlags",
- "type",
- "contains",
- "idRange",
- "lang",
- "amount"
- ]
- }
- };
- /**
- * Calls this endpoint
- * @param {http.IncomingMessage} req The HTTP server request
- * @param {http.ServerResponse} res The HTTP server response
- * @param {Array<String>} url URL path array gotten from the URL parser module
- * @param {Object} params URL query params gotten from the URL parser module
- * @param {String} format The file format to respond with
- */
- const call = (req, res, url, params, format) => {
- jsl.unused([req, url]);
- let filterJoke = new FilteredJoke(parseJokes.allJokes);
- //#SECTION category validation
- let category = (url[settings.httpServer.urlPathOffset + 1]|| "(empty)").toLowerCase() || "";
- let includesSplitChar = false;
- settings.jokes.splitChars.forEach(splC => {
- if(!jsl.isEmpty(category) && category.includes(splC))
- includesSplitChar = true;
- });
- if(includesSplitChar)
- category = category.split(settings.jokes.splitCharRegex);
- // resolve category aliases
- if(Array.isArray(category))
- category = parseJokes.resolveCategoryAliases(category);
- else
- category = parseJokes.resolveCategoryAlias(category);
-
- let categoryValid = false;
- [settings.jokes.possible.anyCategoryName, ...settings.jokes.possible.categories].forEach(cat => {
- if(typeof category == "string")
- {
- if(category.toLowerCase() == cat.toLowerCase())
- categoryValid = true;
- }
- else if(Array.isArray(category))
- {
- if(category.map(c => c.toLowerCase()).includes(cat.toLowerCase()))
- categoryValid = true;
- }
- });
- let fCat = false;
- if(!Array.isArray(category))
- fCat = filterJoke.setAllowedCategories([category]);
- else fCat = filterJoke.setAllowedCategories(category);
- let langCode = settings.languages.defaultLanguage;
- //#SECTION language
- if(params && !jsl.isEmpty(params["lang"]))
- {
- try
- {
- langCode = params["lang"].toString();
- if(languages.isValidLang(langCode) === true)
- filterJoke.setLanguage(langCode);
- else
- return isErrored(res, format, tr(langCode, "invalidLangCode", langCode), langCode);
- }
- catch(err)
- {
- return isErrored(res, format, tr(langCode, "invalidLangCodeNoArg"), langCode);
- }
- }
- //#SECTION safe mode
- if(params && !jsl.isEmpty(params["safe-mode"]) && params["safe-mode"] === true)
- filterJoke.setSafeMode(true);
- if(!fCat || !categoryValid)
- {
- let avlCats = [settings.jokes.possible.anyCategoryName, ...settings.jokes.possible.categories].join(", ");
- let catName = category.length == undefined || typeof category != "object" ? category : category.join(", ");
- return isErrored(res, format, tr(langCode, "invalidCategory", catName, avlCats), langCode);
- }
-
- let jokeAmount = 1;
- if(!jsl.isEmpty(params))
- {
- //#SECTION type
- if(!jsl.isEmpty(params["type"]) && settings.jokes.possible.types.map(t => t.toLowerCase()).includes(params["type"].toLowerCase()))
- {
- if(!filterJoke.setAllowedType(params["type"].toLowerCase()))
- return isErrored(res, format, tr(langCode, "invalidType", params["type"], settings.jokes.possible.types.join(", ")), langCode);
- }
-
- //#SECTION contains
- if(!jsl.isEmpty(params["contains"]))
- {
- if(!filterJoke.setSearchString(params["contains"].toLowerCase()))
- return isErrored(res, format, tr(langCode, "invalidType", params["type"], settings.jokes.possible.types.join(", ")), langCode);
- }
- //#SECTION idRange
- if(!jsl.isEmpty(params["idRange"]))
- {
- try
- {
- if(params["idRange"].match(settings.jokes.splitCharRegex))
- {
- let splitParams = params["idRange"].split(settings.jokes.splitCharRegex);
- if(!splitParams[0] && splitParams[1])
- splitParams[0] = splitParams[1];
-
- if(!splitParams[1] && splitParams[0])
- splitParams[1] = splitParams[0];
- if(!filterJoke.setIdRange(parseInt(splitParams[0]), parseInt(splitParams[1])))
- return isErrored(res, format, tr(langCode, "idRangeInvalid", splitParams[0], splitParams[1], (parseJokes.jokeCountPerLang[langCode] - 1)), langCode);
- }
- else
- {
- let id = parseInt(params["idRange"]);
- if(!filterJoke.setIdRange(id, id, langCode))
- return isErrored(res, format, tr(langCode, "idRangeInvalidSingle", params["idRange"], (parseJokes.jokeCountPerLang[langCode] - 1)), langCode);
- }
- }
- catch(err)
- {
- return isErrored(res, format, tr(langCode, "idRangeInvalidGeneric", err), langCode);
- }
- }
- //#SECTION blacklistFlags
- if(!jsl.isEmpty(params["blacklistFlags"]))
- {
- let flags = params["blacklistFlags"].split(settings.jokes.splitCharRegex) || [];
- let erroredFlags = [];
- flags.forEach(fl => {
- if(!settings.jokes.possible.flags.includes(fl))
- erroredFlags.push(fl);
- });
- if(erroredFlags.length > 0)
- return isErrored(res, format, tr(langCode, "invalidFlags", flags.join(", "), settings.jokes.possible.flags.join(", ")), langCode);
-
- let fFlg = filterJoke.setBlacklistFlags(flags);
- if(!fFlg)
- return isErrored(res, format, tr(langCode, "invalidFlags", flags.join(", "), settings.jokes.possible.flags.join(", ")), langCode);
- }
- //#SECTION amount
- if(!jsl.isEmpty(params["amount"]))
- {
- jokeAmount = parseInt(params["amount"]);
- if(isNaN(jokeAmount) || jokeAmount < 1)
- jokeAmount = 1;
- if(jokeAmount > settings.jokes.maxAmount)
- jokeAmount = settings.jokes.maxAmount;
- let fAmt = filterJoke.setAmount(jokeAmount);
- if(!fAmt)
- return isErrored(res, format, tr(langCode, "amountInternalError", fAmt), langCode);
- }
- }
-
- filterJoke.getJokes(filterJoke.getAmount()).then(jokesArray => {
- let responseText = "";
- if(jokeAmount == 1)
- {
- let singleObj = {
- error: false,
- ...jokesArray[0]
- };
- responseText = convertFileFormat.auto(format, singleObj, langCode);
- }
- else
- {
- let multiObj = {};
- if(format != "xml")
- {
- multiObj = {
- error: false,
- amount: (jokesArray.length || 1),
- jokes: jokesArray
- };
- }
- else
- {
- multiObj = {
- error: false,
- amount: (jokesArray.length || 1),
- jokes: { "joke": jokesArray }
- };
- }
- responseText = convertFileFormat.auto(format, multiObj, langCode);
- }
- if(jokeAmount > settings.jokes.encodeAmount)
- httpServer.tryServeEncoded(req, res, responseText, parseURL.getMimeTypeFromFileFormatString(format));
- else
- httpServer.pipeString(res, responseText, parseURL.getMimeTypeFromFileFormatString(format));
- }).catch(err => {
- return isErrored(res, format, tr(langCode, "errorWhileFinalizing", Array.isArray(err) ? err.join("; ") : err), langCode);
- });
- };
- /**
- * Responds with a preformatted error message
- * @param {http.ServerResponse} res
- * @param {String} format
- * @param {String} msg
- * @param {String} lang 2-char lang code
- * @param {...any} args Arguments to replace numbered %-placeholders with. Only use objects that are strings or convertable to them with `.toString()`!
- */
- const isErrored = (res, format, msg, lang, ...args) => {
- let errFromRegistry = require("." + settings.errors.errorMessagesPath)["106"];
- let errorObj = {};
- let insArgs = (texts, insertions) => {
- if(!Array.isArray(insertions) || insertions.length <= 0)
- return texts;
- insertions.forEach((ins, i) => {
- if(Array.isArray(texts))
- texts = texts.map(tx => tx.replace(`%${i + 1}`, ins));
- else if(typeof texts == "string")
- texts = texts.replace(`%${i + 1}`, ins);
- });
- return texts;
- };
- if(format != "xml")
- {
- errorObj = {
- error: true,
- internalError: false,
- code: 106,
- message: insArgs(errFromRegistry.errorMessage[lang], args) || insArgs(errFromRegistry.errorMessage[settings.languages.defaultLanguage], args),
- causedBy: insArgs(errFromRegistry.causedBy[lang], args) || insArgs(errFromRegistry.causedBy[settings.languages.defaultLanguage], args),
- additionalInfo: msg,
- timestamp: new Date().getTime()
- };
- }
- else if(format == "xml")
- {
- errorObj = {
- error: true,
- internalError: false,
- code: 106,
- message: insArgs(errFromRegistry.errorMessage[lang], args) || insArgs(errFromRegistry.errorMessage[settings.languages.defaultLanguage], args),
- causedBy: {"cause": insArgs(errFromRegistry.causedBy[lang], args) || insArgs(errFromRegistry.causedBy[settings.languages.defaultLanguage], args)},
- additionalInfo: msg,
- timestamp: new Date().getTime()
- };
- }
- let responseText = convertFileFormat.auto(format, errorObj, lang);
- httpServer.pipeString(res, responseText, parseURL.getMimeTypeFromFileFormatString(format), 400);
- };
- module.exports = { meta, call };
|