- commit
- 3ea2fe78e486363d2f7086fda6191d2aaec7cf1c
- parent
- bd3285c8c3e8563f03ecfb990d369ccac3921b72
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2020-10-16 14:25
rm server
Diffstat
| M | .gitignore | 2 | -- |
| M | Makefile | 4 | ---- |
| D | Procfile | 1 | - |
| M | README.md | 22 | +--------------------- |
| D | app.js | 204 | ------------------------------------------------------------ |
| D | bin/manage_db.sh | 33 | --------------------------------- |
| M | package.json | 9 | --------- |
| R | tpl/app.html -> static/index.html | 4 | +--- |
| M | static/src/voterunner.js | 2 | +- |
| D | tpl/markdown.html | 17 | ----------------- |
10 files changed, 3 insertions, 295 deletions
diff --git a/.gitignore b/.gitignore
@@ -1,5 +1,3 @@ 1 1 node_modules2 -1 data3 -1 db.sqlite34 2 static/style.css 5 3 static/voterunner.js
diff --git a/Makefile b/Makefile
@@ -8,7 +8,3 @@ static/style.css: static/scss/*.scss 8 8 9 9 clean: 10 10 rm static/voterunner.js static/style.css11 -112 -1 .PHONY: server13 -1 server: all14 -1 export DATABASE_URL='sqlite3:db.sqlite3' && node app.js
diff --git a/Procfile b/Procfile
@@ -1 +0,0 @@1 -1 web: node app.js
diff --git a/README.md b/README.md
@@ -8,8 +8,7 @@ This app tries to allow for quick and dirty votes and discussions. It is 8 8 basically the core concept behind 9 9 [votorolla](http://zelea.com/project/votorola/home.xht) mixed with the 10 10 interface of [etherpad](http://etherpad.org/). Technically, it is a lot11 -1 of client side code with a bit of [socket.io](http://socket.io) magic on12 -1 the server.-1 11 of client side code using a [via](https://github.com/xi/via) server. 13 12 14 13 The voting mechanism 15 14 -------------------- @@ -60,25 +59,6 @@ the delegation. Now you compete directly with other ideas. Maybe you can 60 59 convince others, but maybe you should delegate your vote again in order 61 60 to agree on a compromise. 62 6163 -1 Install64 -1 -------65 -166 -1 Voterunner is a [node.js](http://nodejs.org/) app using67 -1 [PostgreSQL](http://www.postgresql.org/) as a database so the following68 -1 lines will bring it up:69 -170 -1 $ git clone https://github.com/xi/voterunner71 -1 $ cd voterunner72 -1 $ npm install73 -1 $ bin/manage_db.sh init74 -1 $ bin/manage_db.sh start75 -1 $ export DATABASE_URL="postgresql://:@localhost/voterunner"76 -1 $ node app.js77 -1 ... Listening on localhost:500078 -1 $ open http://localhost:5000/ # introduction79 -1 $ open http://localhost:5000/my-topic/ # discuss on a topic80 -181 -182 62 Development 83 63 ----------- 84 64
diff --git a/app.js b/app.js
@@ -1,204 +0,0 @@1 -1 /*2 -1 * voterunner - quick and dirty votes and discussions3 -1 *4 -1 * copyright: 2013 Tobias Bengfort <tobias.bengfort@gmx.net>5 -1 * license: AGPL-3+6 -1 * url: http://voterunner.herokuapp.com/7 -1 */8 -19 -1 var url = require('url');10 -1 var process = require('process');11 -112 -1 var express = require('express');13 -1 var http = require('http');14 -1 var app = express();15 -1 var server = http.Server(app);16 -1 var io = require('socket.io').listen(server);17 -1 var anyDB = require('any-db');18 -1 var fs = require('fs');19 -1 var log4js = require('log4js');20 -1 var MarkdownIt = require('markdown-it');21 -122 -1 var DATABASE_URL = process.env.DATABASE_URL;23 -1 var SQLITE = DATABASE_URL.match(/^sqlite/);24 -1 var PORT = process.env.PORT || 5000;25 -1 var HOST = process.env.HOST || 'localhost';26 -127 -1 var log = log4js.getLogger();28 -1 var md = new MarkdownIt();29 -130 -1 app.use(express.static('static'));31 -1 server.listen(PORT, HOST, function() {32 -1 log.info('Listening on ' + HOST + ':' + PORT);33 -1 });34 -135 -1 var db = anyDB.createPool(DATABASE_URL, {36 -1 max: SQLITE ? 1 : 10,37 -1 });38 -1 process.on('exit', (code) => {39 -1 db.close();40 -1 });41 -142 -1 var queryDB = function(sql, data) {43 -1 if (SQLITE) {44 -1 sql = sql.replace(/\$/g, '?');45 -1 }46 -147 -1 return new Promise(function(resolve, reject) {48 -1 var q = db.query(sql, data, function(err, res) {49 -1 if (err) {50 -1 reject(err);51 -1 } else {52 -1 resolve(res);53 -1 }54 -1 });55 -1 });56 -1 };57 -158 -1 // setup table59 -1 queryDB('CREATE TABLE IF NOT EXISTS nodes (topic TEXT, id TEXT, name TEXT, comment TEXT, delegate TEXT, UNIQUE (topic, id))');60 -161 -1 var escapeHTML = function(unsafe) {62 -1 return unsafe63 -1 .replace(/&/g, '&')64 -1 .replace(/</g, '<')65 -1 .replace(/>/g, '>')66 -1 .replace(/"/g, '"')67 -1 .replace(/'/g, ''');68 -1 };69 -170 -1 var tpl = function(file, data, res) {71 -1 fs.readFile('tpl/' + file, 'utf8', function(err, html) {72 -1 html = html.replace(/{{{ ([^}]*)\|markdown }}}/g, function(match, key) {73 -1 if (data.hasOwnProperty(key)) {74 -1 return md.render(data[key]);75 -1 } else {76 -1 return '';77 -1 }78 -1 });79 -180 -1 html = html.replace(/{{ ([^}]*)\|json }}/g, function(match, key) {81 -1 if (data.hasOwnProperty(key)) {82 -1 return '<div id="json-' + escapeHTML(key) + '" data-value="' + escapeHTML(JSON.stringify(data[key])) + '"></div>';83 -1 } else {84 -1 return '';85 -1 }86 -1 });87 -188 -1 html = html.replace(/{{ ([^}]*) }}/g, function(match, key) {89 -1 if (data.hasOwnProperty(key)) {90 -1 return escapeHTML(data[key].toString());91 -1 } else {92 -1 return '';93 -1 }94 -1 });95 -196 -1 res.send(html);97 -1 });98 -1 };99 -1100 -1101 -1 // welcome view102 -1 app.get('/', function(req, res) {103 -1 fs.readFile('README.md', 'utf8', function(err, markdown) {104 -1 tpl('markdown.html', {'markdown': markdown}, res);105 -1 });106 -1 });107 -1108 -1 // json state109 -1 app.get('/:topic.json', function(req, res) {110 -1 var topic = req.params.topic;111 -1 var sql = 'SELECT id, name, comment, delegate FROM nodes WHERE topic = $1';112 -1113 -1 queryDB(sql, [topic]).then(function(result) {114 -1 res.json(result.rows);115 -1 }).catch(function(err) {116 -1 res.status(500).send(err.toString());117 -1 });118 -1 });119 -1120 -1 // app view121 -1 app.get('/:topic/:id?', function(req, res) {122 -1 var topic = req.params.topic;123 -1124 -1 var sql = 'SELECT id, name, comment, delegate FROM nodes WHERE topic = $1';125 -1 queryDB(sql, [topic]).then(function(result) {126 -1 tpl('app.html', {'nodes': result.rows, 'topic': topic}, res);127 -1 }).catch(function(err) {128 -1 res.status(500).send(err.toString());129 -1 });130 -1 });131 -1132 -1 // socket.io133 -1 io.sockets.on('connection', function(socket) {134 -1 var topic;135 -1 var id;136 -1137 -1 var handleMsg = function(action, sql, v1, v2) {138 -1 // make sure that node exists, ignore error139 -1 return queryDB('INSERT INTO nodes (topic, id) VALUES ($1, $2)', [topic, id]).catch(function() {140 -1 return;141 -1 }).then(function() {142 -1 log.debug('Handeling:', action, topic, id, v1, v2);143 -1 io.to(topic).emit(action, id, v1, v2);144 -1145 -1 if (typeof(sql) === 'string') {146 -1 sql = [sql];147 -1 }148 -1149 -1 return Promise.all(sql.map(function(s) {150 -1 var params = [topic, id];151 -1 var n = s.match(/\$/g).length;152 -1 if (n >= 3) params.push(v1);153 -1 if (n >= 4) params.push(v2);154 -1155 -1 return queryDB(s, params);156 -1 }));157 -1 });158 -1 };159 -1160 -1 socket.on('register', function(_topic, _id) {161 -1 log.debug('Registration:', _topic, _id);162 -1163 -1 topic = _topic;164 -1 id = _id;165 -1 socket.join(topic, function(err) {166 -1 if (err) {167 -1 log.error(err);168 -1 }169 -1 });170 -1 });171 -1172 -1 socket.on('rmNode', function() {173 -1 var sql = [174 -1 'UPDATE nodes SET delegate = null WHERE topic = $1 AND delegate = $2',175 -1 'DELETE FROM nodes WHERE topic = $1 AND id = $2',176 -1 ];177 -1 handleMsg('rmNode', sql);178 -1 });179 -1 socket.on('setNodeName', function(name) {180 -1 var sql = 'UPDATE nodes SET name = $3 WHERE topic = $1 AND id = $2';181 -1 handleMsg('setNodeName', sql, name);182 -1 });183 -1 socket.on('setNodeComment', function(comment) {184 -1 var sql = 'UPDATE nodes SET comment = $3 WHERE topic = $1 AND id = $2';185 -1 handleMsg('setNodeComment', sql, comment);186 -1 });187 -1 socket.on('setDelegate', function(delegate) {188 -1 var sql = 'UPDATE nodes SET delegate = $3 WHERE topic = $1 AND id = $2';189 -1 handleMsg('setDelegate', sql, delegate);190 -1 });191 -1 socket.on('rmDelegate', function() {192 -1 var sql = 'UPDATE nodes SET delegate = null WHERE topic = $1 AND id = $2';193 -1 handleMsg('rmDelegate', sql);194 -1 });195 -1196 -1 socket.on('testClear', function(done) {197 -1 if (topic.substr(0, 4) === 'test') {198 -1 log.debug('Handeling:', 'testClear', topic);199 -1 queryDB("DELETE FROM nodes WHERE topic = $1", [topic]).then(done);200 -1 } else {201 -1 done();202 -1 }203 -1 });204 -1 });
diff --git a/bin/manage_db.sh b/bin/manage_db.sh
@@ -1,33 +0,0 @@1 -1 #!/bin/sh2 -13 -1 cd "$(dirname "$0")/.."4 -1 DB_DIR="$(pwd)/data/postgres"5 -1 mkdir -p $DB_DIR6 -17 -1 start() {8 -1 pg_ctl start -w -D "$DB_DIR" -o "-h localhost" -o "-k '$DB_DIR'"9 -1 }10 -111 -1 stop() {12 -1 pg_ctl stop -D "$DB_DIR"13 -1 }14 -115 -1 if [ "$1" = 'start' ]; then16 -1 start17 -1 elif [ "$1" = 'stop' ]; then18 -1 stop19 -1 elif [ "$1" = 'init' ]; then20 -1 if test ! -d "$DB_DIR/base"; then21 -1 pg_ctl initdb -D "$DB_DIR"22 -1 start23 -1 createdb -h "$DB_DIR" voterunner24 -1 stop25 -1 else26 -1 echo "skipping"27 -1 fi28 -1 elif [ "$1" = 'clean' ]; then29 -1 rm -r "$DB_DIR"30 -1 else31 -1 echo "invalid command"32 -1 exit 133 -1 fi
diff --git a/package.json b/package.json
@@ -1,15 +1,6 @@ 1 1 { 2 2 "name": "voterunner", 3 3 "version": "0.0.1",4 -1 "dependencies": {5 -1 "any-db": "^2.2.0",6 -1 "any-db-postgres": "^2.1.5",7 -1 "any-db-sqlite3": "^2.1.4",8 -1 "express": "^4.16.2",9 -1 "log4js": "^0.6.38",10 -1 "markdown-it": "^7.0.1",11 -1 "socket.io": "^1.7.4"12 -1 },13 4 "devDependencies": { 14 5 "mfbs": "^3.1.1", 15 6 "preact": "^8.2.6",
diff --git a/tpl/app.html b/static/index.html
@@ -2,7 +2,7 @@ 2 2 <html class="voterunner"> 3 3 <head> 4 4 <meta charset="utf-8">5 -1 <title>voterunner - {{ topic }}</title>-1 5 <title>voterunner</title> 6 6 <meta name="viewport" content="width=device-width" /> 7 7 <meta name="robots" content="noindex" /> 8 8 <link rel="shortcut icon" href="/favicon.ico"/> @@ -36,8 +36,6 @@ 36 36 <div id="tree"></div> 37 37 </div></div> 38 3839 -1 {{ nodes|json }}40 -141 39 <script type="text/javascript" src="/voterunner.js"></script> 42 40 </body> 43 41 </html>
diff --git a/static/src/voterunner.js b/static/src/voterunner.js
@@ -14,7 +14,7 @@ document.addEventListener('DOMContentLoaded', function() {
14 14 socket.emit('register', TOPIC, ID);
15 15
16 16 var state = {
17 -1 nodes: JSON.parse(document.querySelector('#json-nodes').dataset.value),
-1 17 nodes: [],
18 18 id: ID,
19 19 };
20 20
diff --git a/tpl/markdown.html b/tpl/markdown.html
@@ -1,17 +0,0 @@1 -1 <!DOCTYPE html>2 -1 <html xmlns="http://www.w3.org/1999/xhtml">3 -14 -1 <head>5 -1 <meta charset="utf-8">6 -1 <title>voterunner</title>7 -1 <meta name="viewport" content="width=device-width" />8 -1 <link rel="shortcut icon" href="/favicon.ico"/>9 -1 <link rel="stylesheet" type="text/css" href="/style.css" />10 -1 <meta name="description" content="quick and dirty votes and discussions" />11 -1 </head>12 -113 -1 <body>14 -1 {{{ markdown|markdown }}}15 -1 </body>16 -117 -1 </html>