Add license to top of each file, bump userscript version

ご主人様
not manx 4 years ago
parent 220e660c84
commit 4214c213e3
Signed by: C-xC-c
GPG Key ID: F52ED472284EF2F4

@ -1,16 +1,16 @@
[Unit] [Unit]
Description=bantflags backend Description=bantflags serb
[Service] [Service]
# Set to the location of the application # Set to the location of the application
WorkingDirectory=/etc/bantflags WorkingDirectory=/var/www/bantflags/src/
ExecStart=/usr/bin/dotnet /etc/bantflags/BantFlags.dll ExecStart=/usr/bin/env sbcl --eval '(progn (push #p"/var/www/bantflags/src" ql:*local-project-directories*) (ql:quickload :bantflags) (main))'
Restart=always Restart=always
# restarts 10 seconds after it goes bang # restarts 10 seconds after it goes bang
RestartSec=10 RestartSec=10
KillSignal=SIGINT KillSignal=SIGINT
SyslogIdentifier=bantflags SyslogIdentifier=bantflags
User=www-data User=nginx
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

@ -11,7 +11,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 1.5.2 // @version 2.0.0
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant GM_getValue // @grant GM_getValue
// @grant GM_setValue // @grant GM_setValue

@ -11,7 +11,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 1.5.2 // @version 2.0.0
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant GM_getValue // @grant GM_getValue
// @grant GM_setValue // @grant GM_setValue
@ -30,7 +30,7 @@
// see the LICENSE file or <https://www.gnu.org/licenses/> // see the LICENSE file or <https://www.gnu.org/licenses/>
// Change this if you want verbose debuging information in the console. // Change this if you want verbose debuging information in the console.
const debugMode = true; const debugMode = false;
const isGM4 = typeof GM_setValue === 'undefined'; const isGM4 = typeof GM_setValue === 'undefined';
const setValue = isGM4 ? GM.setValue : GM_setValue; const setValue = isGM4 ? GM.setValue : GM_setValue;
@ -71,14 +71,14 @@ const software = {
foolfuuka: document.querySelector('div[id="main"] article header .post_data') !== null foolfuuka: document.querySelector('div[id="main"] article header .post_data') !== null
}; };
const createAndAssign = (element, source) => Object.assign(document.createElement(element), source); const makeElement = (tag, options) => Object.assign(document.createElement(tag), options);
const toggleFlagButton = state => document.getElementById('append_flag_button').disabled = state === 'off' ? true : false; const toggleFlagButton = state => document.getElementById('append_flag_button').disabled = state === 'off' ? true : false;
const flagSource = flag => flag_dir + flag + ".png"; const flagSource = flag => flag_dir + flag + ".png";
/** Add styles to the <head> */ /** Add styles to the <head> */
const addGlobalStyle = css => document.head.appendChild(createAndAssign('style', { innerHTML: css })); const addGlobalStyle = css => document.head.appendChild(makeElement('style', { innerHTML: css }));
/** Wrapper around GM_xmlhttpRequest. /** Wrapper around GM_xmlhttpRequest.
* @param {string} method - The HTTP method (GET, POST). * @param {string} method - The HTTP method (GET, POST).
@ -98,7 +98,7 @@ const makeRequest = ((method, url, data, func) => {
/** Itterate over selected flags are store them across browser sessions.*/ /** Itterate over selected flags are store them across browser sessions.*/
function saveFlags() { function saveFlags() {
regions = []; regions = [];
const selectedFlags = document.querySelectorAll("bantflags_flag"); const selectedFlags = document.querySelectorAll(".bantflags_flag");
for (var i = 0; i < selectedFlags.length; i++) { for (var i = 0; i < selectedFlags.length; i++) {
regions[i] = selectedFlags[i].title; regions[i] = selectedFlags[i].title;
@ -114,7 +114,7 @@ function setFlag(flag) {
let flagName = flag ? flag : document.querySelector('#flagSelect input').value; let flagName = flag ? flag : document.querySelector('#flagSelect input').value;
let flagContainer = document.getElementById('bantflags_container'); let flagContainer = document.getElementById('bantflags_container');
flagContainer.appendChild(createAndAssign('img', { flagContainer.appendChild(makeElement('img', {
title: flagName, title: flagName,
src: flagSource(flagName), src: flagSource(flagName),
id: UID, id: UID,
@ -129,13 +129,14 @@ function setFlag(flag) {
toggleFlagButton('on'); toggleFlagButton('on');
saveFlags(); saveFlags();
}); });
if (!flag) // We've added a new flag to our selection if (!flag) // We've added a new flag to our selection
saveFlags(); saveFlags();
} }
function init() { function init() {
let flagsForm = createAndAssign('div', { let flagsForm = makeElement('div', {
className: 'flagsForm', className: 'flagsForm',
innerHTML: '<span id="bantflags_container"></span><button type="button" id="append_flag_button" title="Click to add selected flag to your flags. Click on flags to remove them. Saving happens automatically, you only need to refresh the pages that have an outdated flaglist on the page."><<</button><button id="flagLoad" type="button">Click to load flags.</button><div id="flagSelect" ><ul class="hide"></ul><input type="button" value="(You)" onclick=""></div>' innerHTML: '<span id="bantflags_container"></span><button type="button" id="append_flag_button" title="Click to add selected flag to your flags. Click on flags to remove them. Saving happens automatically, you only need to refresh the pages that have an outdated flaglist on the page."><<</button><button id="flagLoad" type="button">Click to load flags.</button><div id="flagSelect" ><ul class="hide"></ul><input type="button" value="(You)" onclick=""></div>'
}); });
@ -173,7 +174,7 @@ function makeFlagSelect() {
for (var i = 0; i < flags.length; i++) { for (var i = 0; i < flags.length; i++) {
let flag = flags[i]; let flag = flags[i];
flagList.appendChild(createAndAssign('li',{ flagList.appendChild(makeElement('li',{
innerHTML: `<img src="${flagSource(flag)}" title="${flag}"><span>${flag}</span>` innerHTML: `<img src="${flagSource(flag)}" title="${flag}"><span>${flag}</span>`
})); }));
} }
@ -241,7 +242,7 @@ function resolveFlags() {
for (let i = 0; i < flags.length; i++) { for (let i = 0; i < flags.length; i++) {
const flag = flags[i]; const flag = flags[i];
const newFlag = createAndAssign('a', { const newFlag = makeElement('a', {
innerHTML: `<img src="${flagSource(flag)}" title="${flag}">`, innerHTML: `<img src="${flagSource(flag)}" title="${flag}">`,
className: 'bantFlag', className: 'bantFlag',
target: '_blank', target: '_blank',
@ -259,12 +260,7 @@ function resolveFlags() {
} }
function main() { function main() {
if (!regions) { // Should only be called before you set flags for the first time. // See Docs/styles.css
regions = [];
window.confirm('[BantFlags]: No Flags detected.\nIf this is your first time running bantflags, look for the "Click to load flags." button at the bottom right of the thread, then select your flag and press the ">>" button.');
}
// See Docs/styles.css
addGlobalStyle('.bantFlag{padding: 0px 0px 0px 5px; display: inline-block; width: 16px; height: 11px; position: relative;} .bantflags_flag{padding: 1px;} [title^="Romania"]{ position: relative; animation: shakeAnim 0.1s linear infinite;} @keyframes shakeAnim{ 0% {left: 1px;} 25% {top: 2px;} 50% {left: 1px;} 75% {left: 0px;} 100% {left: 2px;}}.flagsForm{float: right; clear: right; margin: 20px 10px;} #flagSelect{display:none;} #flagSelect ul{list-style-type: none;padding: 0;margin-bottom: 0;cursor: pointer;bottom: 100%;height: 200px;overflow: auto;position: absolute;width:200px;background-color:#fff} #flagSelect ul li {display: block;} #flagSelect ul li:hover {background-color: #ddd;}#flagSelect {position: absolute;}#flagSelect input {width: 200px;} #flagSelect .hide {display: none;}#flagSelect img {margin-left: 2px;}') addGlobalStyle('.bantFlag{padding: 0px 0px 0px 5px; display: inline-block; width: 16px; height: 11px; position: relative;} .bantflags_flag{padding: 1px;} [title^="Romania"]{ position: relative; animation: shakeAnim 0.1s linear infinite;} @keyframes shakeAnim{ 0% {left: 1px;} 25% {top: 2px;} 50% {left: 1px;} 75% {left: 0px;} 100% {left: 2px;}}.flagsForm{float: right; clear: right; margin: 20px 10px;} #flagSelect{display:none;} #flagSelect ul{list-style-type: none;padding: 0;margin-bottom: 0;cursor: pointer;bottom: 100%;height: 200px;overflow: auto;position: absolute;width:200px;background-color:#fff} #flagSelect ul li {display: block;} #flagSelect ul li:hover {background-color: #ddd;}#flagSelect {position: absolute;}#flagSelect input {width: 200px;} #flagSelect .hide {display: none;}#flagSelect img {margin-left: 2px;}')
if (software.yotsuba) { if (software.yotsuba) {

@ -1,3 +1,8 @@
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
;; This file is part of bantflags.
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
;; see the LICENSE file or <https://www.gnu.org/licenses/>
(asdf:defsystem #:bantflags (asdf:defsystem #:bantflags
:description "the bantflags server component" :description "the bantflags server component"
:author "Manx (boku@plum.moe)" :author "Manx (boku@plum.moe)"

@ -3,4 +3,8 @@
(staging-password "not implemented") (staging-password "not implemented")
(db-conn "localhost" "bantflags" "flags" "default") (db-conn "localhost" "bantflags" "flags" "default")
(poolsize 3) (poolsize 3)
(www-root #p"/path/to/files/"))) (www-root #p"/path/to/files/")
(port 4242)
;; These can be a file or stream, make them nil to disable logging
(access-log *standard-output*)
(error-log #p"/path/to/error/log/")))

@ -1,7 +1,12 @@
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
;; This file is part of bantflags.
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
;; see the LICENSE file or <https://www.gnu.org/licenses/>
;; Databases in common lisp are the fucking worst. ;; Databases in common lisp are the fucking worst.
;; Don't even bother. ;; Don't even bother.
;; Comparing strings with both ;; We're comparing strings
(defparameter *flags* (make-hash-table :test 'equal)) (defparameter *flags* (make-hash-table :test 'equal))
(defparameter *boards* (make-hash-table :test 'equal)) (defparameter *boards* (make-hash-table :test 'equal))
(defparameter *flags-txt* nil) (defparameter *flags-txt* nil)

@ -1,14 +1,19 @@
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
;; This file is part of bantflags.
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
;; see the LICENSE file or <https://www.gnu.org/licenses/>
(defun init () (defun init ()
(set-db-conn) (setf conn (conf 'db-conn))
(dotimes (_ (cconf 'poolsize)) (loop repeat (cconf 'poolsize) do
(clsql:connect conn :database-type :mysql :pool t :if-exists :new)) (clsql:connect conn :database-type :mysql :pool t :if-exists :new))
(set-boards) (set-boards)
(set-flags) (set-flags)
(defvar +serb+ (make-instance 'hunchentoot:easy-acceptor (defvar +serb+ (make-instance 'hunchentoot:easy-acceptor
:port 4242 :port (cconf 'port)
:document-root (cconf 'www-root) :document-root (cconf 'www-root)
:access-log-destination nil :access-log-destination (cconf 'access-log)
:message-log-destination #p"/var/log/bantflags/erorr.log")) :message-log-destination (cconf 'error-log)))
(hunchentoot:start +serb+)) (hunchentoot:start +serb+))
(defun main () (defun main ()
@ -19,38 +24,23 @@
(loop (sleep 43200) (gc :full t))) (loop (sleep 43200) (gc :full t)))
(defmethod hunchentoot:acceptor-status-message (acceptor (http-status-code (eql 404)) &key) (defmethod hunchentoot:acceptor-status-message (acceptor (http-status-code (eql 404)) &key)
(format nil "")) (format nil "")) ;; Empty 404 page
(defmacro handle (method uri params &body body)
`(hunchentoot:define-easy-handler ,uri ,params
(unless (eq ,method (hunchentoot:request-method*))
(setf (hunchentoot:return-code*) hunchentoot:+http-not-found+)
(hunchentoot:abort-request-handler))
,@body))
(handle :post (api-post :uri "/api/post") (handle :post (api-post :uri "/api/post") @json
(post_nr regions board version) (post_nr regions board version)
(@json tbnl:*reply*) (multiple-value-bind (result msg) (insert-post-p post_nr (cl-ppcre:split "," regions) board)
(setf regions (cl-ppcre:split "," regions))
(multiple-value-bind (result msg) (post-valid-p post_nr regions board)
(cond (cond
(result (result
(insert-post post_nr board msg) (insert-post post_nr board msg)
(format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg)) (format nil "{\"~a\": [~{\"~a\"~^,~}]}~%" post_nr msg)) ;; This makes JSON
(t (format nil "{\"Error\": \"~a\"}~%" msg))))) (t (format nil "{\"Error\": \"~a\"}~%" msg)))))
(handle :post (api-get :uri "/api/get") (handle :post (api-get :uri "/api/get") @json
(post_nrs board version) (post_nrs board version)
(@json tbnl:*reply*) (if (get-posts-p (cl-ppcre:split "," post_nrs) board)
(setf post_nrs (cl-ppcre:split "," post_nrs)) (format nil "~a~%" (get-posts post_nrs board))
(cond (t (format nil "{[\"~a\"]}~%" "bad"))))
((and (not (null post_nrs))
(every #'post-number-p post_nrs)
(boardp board))
(format nil "~a~%" (get-posts post_nrs board)))
(t (format nil "{[\"~a\"]}~%" "bad"))))
(handle :get (api-flags :uri "/api/flags") (handle :get (api-flags :uri "/api/flags") @plain
() ()
(@plain tbnl:*reply*)
(format nil "~a~%" *flags-txt*)) (format nil "~a~%" *flags-txt*))

@ -1,3 +1,8 @@
;; (C) Copyright 2020 C-xC-c <boku@plum.moe>
;; This file is part of bantflags.
;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
;; see the LICENSE file or <https://www.gnu.org/licenses/>
(defvar empty-flag '("empty, or there were errors. Re-set your flags.")) (defvar empty-flag '("empty, or there were errors. Re-set your flags."))
(defun conf (thing) (defun conf (thing)
@ -9,6 +14,7 @@
(defun cconf (thing) (defun cconf (thing)
(car (conf thing))) (car (conf thing)))
;; db
(defun set-boards () (defun set-boards ()
(setf *boards* (make-hash-table :test 'equal)) (setf *boards* (make-hash-table :test 'equal))
(mapc (lambda (board) (setf (gethash board *boards*) t)) (conf 'boards))) (mapc (lambda (board) (setf (gethash board *boards*) t)) (conf 'boards)))
@ -18,13 +24,13 @@
(let ((flags (get-flags))) (let ((flags (get-flags)))
(loop for (id . flag) in flags (loop for (id . flag) in flags
do (setf (gethash (car flag) *flags*) id)) do (setf (gethash (car flag) *flags*) id))
;; We don't want users to select `empty-flag`
(setf *flags-txt* (setf *flags-txt*
(cl-ppcre:regex-replace "empty, or there were errors. Re-set your flags\\.\\n" (cl-ppcre:regex-replace (concatenate 'string empty-flag "\\n") ;; newline
(format nil "~{~a~^~%~}" (mapcan (lambda (x) (cdr x)) flags)) (format nil "~{~a~^~%~}" (mapcan (lambda (x) (cdr x)) flags))
"")))) ""))))
(defun set-db-conn ()
(setq conn (conf 'db-conn)))
;; validation
(defun post-number-p (post_nr) (defun post-number-p (post_nr)
(if (or (null post_nr) (if (or (null post_nr)
(null (parse-integer post_nr :junk-allowed t))) (null (parse-integer post_nr :junk-allowed t)))
@ -34,7 +40,7 @@
(defun boardp (board) (defun boardp (board)
(gethash board *boards*)) (gethash board *boards*))
(defun post-valid-p (post_nr regions board) (defun insert-post-p (post_nr regions board)
(cond (cond
((not (post-number-p post_nr)) ((not (post-number-p post_nr))
(values nil "Invalid post number.")) (values nil "Invalid post number."))
@ -48,18 +54,25 @@
(values t regions)) (values t regions))
(t (values t empty-flag)))) (t (values t empty-flag))))
;; Unused, should be in utils (defun get-posts-p (post_nrs board)
(defun host-dir (uri path) (and (not (null post_nrs))
(push (every #'post-number-p post_nrs)
(hunchentoot:create-folder-dispatcher-and-handler uri path) (boardp board)))
hunchentoot:*dispatch-table*))
;; hunchentoot
(defmacro handle (method uri content-type params &body body)
"Creates an easy handles for a specific HTTP request method. If the
method provided sent from the client isn't correct, return 404 and
stop processing the request.
(handle :get (uri-fun :uri \"/path/to/page\"/) @content-type (args) (body))"
`(hunchentoot:define-easy-handler ,uri ,params
(unless (eq ,method (hunchentoot:request-method*))
(setf (hunchentoot:return-code*) hunchentoot:+http-not-found+)
(hunchentoot:abort-request-handler))
(setf (tbnl:content-type* tbnl:*reply*) ,content-type)
,@body))
;; This is uneccessarily complicated, no I'm not sorry ;; Content types
(defmacro content-type (types) (defvar @json "application/json")
(cons 'progn (defvar @plain "text/plain")
(mapcar (lambda (type) `(defun ,(car type) (reply)
(setf (tbnl:content-type* reply) ,(cadr type))))
types)))
(content-type
((@json "application/json")
(@plain "text/plain")))

Loading…
Cancel
Save