diff --git a/Environment/bantflags.service b/Environment/bantflags.service
index dfab55a..34d8928 100644
--- a/Environment/bantflags.service
+++ b/Environment/bantflags.service
@@ -1,16 +1,16 @@
[Unit]
-Description=bantflags backend
+Description=bantflags serb
[Service]
# Set to the location of the application
-WorkingDirectory=/etc/bantflags
-ExecStart=/usr/bin/dotnet /etc/bantflags/BantFlags.dll
+WorkingDirectory=/var/www/bantflags/src/
+ExecStart=/usr/bin/env sbcl --eval '(progn (push #p"/var/www/bantflags/src" ql:*local-project-directories*) (ql:quickload :bantflags) (main))'
Restart=always
# restarts 10 seconds after it goes bang
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=bantflags
-User=www-data
+User=nginx
[Install]
WantedBy=multi-user.target
\ No newline at end of file
diff --git a/bantflags.meta.js b/bantflags.meta.js
index d905bed..c88c4fa 100644
--- a/bantflags.meta.js
+++ b/bantflags.meta.js
@@ -11,7 +11,7 @@
// @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/
-// @version 1.5.2
+// @version 2.0.0
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
diff --git a/bantflags.user.js b/bantflags.user.js
index a87a420..4874d99 100644
--- a/bantflags.user.js
+++ b/bantflags.user.js
@@ -11,7 +11,7 @@
// @exclude http*://archive.nyafuu.org/bant/statistics/
// @exclude http*://archived.moe/bant/statistics/
// @exclude http*://thebarchive.com/bant/statistics/
-// @version 1.5.2
+// @version 2.0.0
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
@@ -30,7 +30,7 @@
// see the LICENSE file or
// Change this if you want verbose debuging information in the console.
-const debugMode = true;
+const debugMode = false;
const isGM4 = typeof GM_setValue === 'undefined';
const setValue = isGM4 ? GM.setValue : GM_setValue;
@@ -71,14 +71,14 @@ const software = {
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 flagSource = flag => flag_dir + flag + ".png";
/** Add styles to the
*/
-const addGlobalStyle = css => document.head.appendChild(createAndAssign('style', { innerHTML: css }));
+const addGlobalStyle = css => document.head.appendChild(makeElement('style', { innerHTML: css }));
/** Wrapper around GM_xmlhttpRequest.
* @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.*/
function saveFlags() {
regions = [];
- const selectedFlags = document.querySelectorAll("bantflags_flag");
+ const selectedFlags = document.querySelectorAll(".bantflags_flag");
for (var i = 0; i < selectedFlags.length; i++) {
regions[i] = selectedFlags[i].title;
@@ -114,7 +114,7 @@ function setFlag(flag) {
let flagName = flag ? flag : document.querySelector('#flagSelect input').value;
let flagContainer = document.getElementById('bantflags_container');
- flagContainer.appendChild(createAndAssign('img', {
+ flagContainer.appendChild(makeElement('img', {
title: flagName,
src: flagSource(flagName),
id: UID,
@@ -129,13 +129,14 @@ function setFlag(flag) {
toggleFlagButton('on');
saveFlags();
});
-
+
if (!flag) // We've added a new flag to our selection
- saveFlags();
+ saveFlags();
+
}
function init() {
- let flagsForm = createAndAssign('div', {
+ let flagsForm = makeElement('div', {
className: 'flagsForm',
innerHTML: ''
});
@@ -173,7 +174,7 @@ function makeFlagSelect() {
for (var i = 0; i < flags.length; i++) {
let flag = flags[i];
- flagList.appendChild(createAndAssign('li',{
+ flagList.appendChild(makeElement('li',{
innerHTML: `${flag}`
}));
}
@@ -241,7 +242,7 @@ function resolveFlags() {
for (let i = 0; i < flags.length; i++) {
const flag = flags[i];
- const newFlag = createAndAssign('a', {
+ const newFlag = makeElement('a', {
innerHTML: ``,
className: 'bantFlag',
target: '_blank',
@@ -259,12 +260,7 @@ function resolveFlags() {
}
function main() {
- if (!regions) { // Should only be called before you set flags for the first time.
- 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
+ // 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;}')
if (software.yotsuba) {
diff --git a/src/bantflags.asd b/src/bantflags.asd
index 897eb63..d3011ce 100644
--- a/src/bantflags.asd
+++ b/src/bantflags.asd
@@ -1,3 +1,8 @@
+;; (C) Copyright 2020 C-xC-c
+;; This file is part of bantflags.
+;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
+;; see the LICENSE file or
+
(asdf:defsystem #:bantflags
:description "the bantflags server component"
:author "Manx (boku@plum.moe)"
diff --git a/src/config.example.lisp b/src/config.example.lisp
index c789480..c86bcd1 100644
--- a/src/config.example.lisp
+++ b/src/config.example.lisp
@@ -3,4 +3,8 @@
(staging-password "not implemented")
(db-conn "localhost" "bantflags" "flags" "default")
(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/")))
diff --git a/src/db.lisp b/src/db.lisp
index 8e3627e..9232fb2 100644
--- a/src/db.lisp
+++ b/src/db.lisp
@@ -1,7 +1,12 @@
+;; (C) Copyright 2020 C-xC-c
+;; This file is part of bantflags.
+;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
+;; see the LICENSE file or
+
;; Databases in common lisp are the fucking worst.
;; Don't even bother.
-;; Comparing strings with both
+;; We're comparing strings
(defparameter *flags* (make-hash-table :test 'equal))
(defparameter *boards* (make-hash-table :test 'equal))
(defparameter *flags-txt* nil)
diff --git a/src/main.lisp b/src/main.lisp
index 5ccc794..1c451b1 100644
--- a/src/main.lisp
+++ b/src/main.lisp
@@ -1,14 +1,19 @@
+;; (C) Copyright 2020 C-xC-c
+;; This file is part of bantflags.
+;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
+;; see the LICENSE file or
+
(defun init ()
- (set-db-conn)
- (dotimes (_ (cconf 'poolsize))
+ (setf conn (conf 'db-conn))
+ (loop repeat (cconf 'poolsize) do
(clsql:connect conn :database-type :mysql :pool t :if-exists :new))
(set-boards)
(set-flags)
(defvar +serb+ (make-instance 'hunchentoot:easy-acceptor
- :port 4242
+ :port (cconf 'port)
:document-root (cconf 'www-root)
- :access-log-destination nil
- :message-log-destination #p"/var/log/bantflags/erorr.log"))
+ :access-log-destination (cconf 'access-log)
+ :message-log-destination (cconf 'error-log)))
(hunchentoot:start +serb+))
(defun main ()
@@ -19,38 +24,23 @@
(loop (sleep 43200) (gc :full t)))
(defmethod hunchentoot:acceptor-status-message (acceptor (http-status-code (eql 404)) &key)
- (format nil ""))
-
-(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))
+ (format nil "")) ;; Empty 404 page
-(handle :post (api-post :uri "/api/post")
+(handle :post (api-post :uri "/api/post") @json
(post_nr regions board version)
- (@json tbnl:*reply*)
- (setf regions (cl-ppcre:split "," regions))
- (multiple-value-bind (result msg) (post-valid-p post_nr regions board)
+ (multiple-value-bind (result msg) (insert-post-p post_nr (cl-ppcre:split "," regions) board)
(cond
(result
(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)))))
-(handle :post (api-get :uri "/api/get")
+(handle :post (api-get :uri "/api/get") @json
(post_nrs board version)
- (@json tbnl:*reply*)
- (setf post_nrs (cl-ppcre:split "," post_nrs))
- (cond
- ((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"))))
+ (if (get-posts-p (cl-ppcre:split "," post_nrs) 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*))
diff --git a/src/utils.lisp b/src/utils.lisp
index fccf7aa..e20d9c2 100644
--- a/src/utils.lisp
+++ b/src/utils.lisp
@@ -1,3 +1,8 @@
+;; (C) Copyright 2020 C-xC-c
+;; This file is part of bantflags.
+;; bantflags is licensed under the GNU AGPL Version 3.0 or later.
+;; see the LICENSE file or
+
(defvar empty-flag '("empty, or there were errors. Re-set your flags."))
(defun conf (thing)
@@ -9,6 +14,7 @@
(defun cconf (thing)
(car (conf thing)))
+;; db
(defun set-boards ()
(setf *boards* (make-hash-table :test 'equal))
(mapc (lambda (board) (setf (gethash board *boards*) t)) (conf 'boards)))
@@ -18,13 +24,13 @@
(let ((flags (get-flags)))
(loop for (id . flag) in flags
do (setf (gethash (car flag) *flags*) id))
+ ;; We don't want users to select `empty-flag`
(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))
""))))
-(defun set-db-conn ()
- (setq conn (conf 'db-conn)))
+;; validation
(defun post-number-p (post_nr)
(if (or (null post_nr)
(null (parse-integer post_nr :junk-allowed t)))
@@ -34,7 +40,7 @@
(defun boardp (board)
(gethash board *boards*))
-(defun post-valid-p (post_nr regions board)
+(defun insert-post-p (post_nr regions board)
(cond
((not (post-number-p post_nr))
(values nil "Invalid post number."))
@@ -48,18 +54,25 @@
(values t regions))
(t (values t empty-flag))))
-;; Unused, should be in utils
-(defun host-dir (uri path)
- (push
- (hunchentoot:create-folder-dispatcher-and-handler uri path)
- hunchentoot:*dispatch-table*))
+(defun get-posts-p (post_nrs board)
+ (and (not (null post_nrs))
+ (every #'post-number-p post_nrs)
+ (boardp board)))
+
+;; 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
-(defmacro content-type (types)
- (cons 'progn
- (mapcar (lambda (type) `(defun ,(car type) (reply)
- (setf (tbnl:content-type* reply) ,(cadr type))))
- types)))
-(content-type
- ((@json "application/json")
- (@plain "text/plain")))
+;; Content types
+(defvar @json "application/json")
+(defvar @plain "text/plain")