diff --git a/webapp/.gitignore b/webapp/.gitignore new file mode 100644 index 0000000..6dd754e --- /dev/null +++ b/webapp/.gitignore @@ -0,0 +1,84 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ diff --git a/webapp/README.md b/webapp/README.md index e28ddb9..c9e38d0 100755 --- a/webapp/README.md +++ b/webapp/README.md @@ -1,14 +1,29 @@ # EnlivenMinetest webapp EnlivenMinetest Node.js webapp for web management of minetest -* Must run as same user as minetestserver, and neither as root +* Must run as same user as minetestserver, and neither should be root! + +## Install +* Using Terminal, cd to your EnlivenMinetest/webapp diretory, then: +```bash +npm install +``` + +## Usage +* start like: + `node server.js` +* then it will listen on port 3000 +* change skin at localhost:3000/skin-form +* for security, no overwrite is allowed -Uses passport -see -Replaces the "write" (stdout) method of the minetest process: -see +## Planned Features +* Replace the "write" (stdout) method of the minetestserver process (see + ) + ## Developer Notes +* Uses passport (see + ### Things webapp should deprecate * mtanalyze/web * /home/owner/GitHub/EnlivenMinetest/etc/change_hardcoded_world_name_first/eauth @@ -48,8 +63,8 @@ fi cd "$target_dir" npm init #except changed jade to pug -npm install express static-favicon morgan cookie-parser body-parser debug pug passport passport-local mongoose - +npm install express static-favicon morgan cookie-parser body-parser debug pug passport passport-local mongoose formidable +#NOTE: multiparty has streaming like busboy, but is non-trivial to implement ``` ### Old (Unused) diff --git a/webapp/install-mts.sh b/webapp/install-mts.sh index bf6da6a..f9df137 100755 --- a/webapp/install-mts.sh +++ b/webapp/install-mts.sh @@ -43,12 +43,12 @@ if [ ! -f "$flag_file" ]; then echo "ERROR: Build did not complete--missing '$flag_file'" exit 1 fi -flag_file="$HOME/minetest/bin/minetestserver" -if [ -f "$flag_file" ]; then - mv -f "$flag_file" "$flag_file.bak" +dest_flag_file="$HOME/$flag_file" +if [ -f "$dest_flag_file" ]; then + mv -f "$dest_flag_file" "$dest_flag_file.bak" fi -if [ -f "$flag_file" ]; then - echo "ERROR: not complete since can't move old '$flag_file'" +if [ -f "$dest_flag_file" ]; then + echo "ERROR: not complete since can't move old '$dest_flag_file'" exit 1 fi if [ ! -d minetest ]; then @@ -57,8 +57,8 @@ if [ ! -d minetest ]; then fi echo "Installing minetest to '$HOME'..." rsync -rt minetest $HOME -if [ ! -f "$flag_file" ]; then - echo "ERROR: not complete--couldn't create '$flag_file'" +if [ ! -f "$dest_flag_file" ]; then + echo "ERROR: not complete--couldn't create '$dest_flag_file'" exit 1 fi flag_dir="$HOME/minetest/games/Bucket_Game" diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 705d298..9e7fd13 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -9,7 +9,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -24,15 +24,15 @@ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.16" + "type-is": "~1.6.15" } }, "bytes": { @@ -112,36 +112,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", + "proxy-addr": "~2.0.3", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" } }, "finalhandler": { @@ -150,14 +150,19 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" } }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -173,10 +178,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -224,7 +229,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "ms": { @@ -265,7 +270,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.6.0" } }, @@ -303,7 +308,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "setprototypeof": { @@ -324,18 +329,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" } }, "serve-static": { @@ -343,9 +348,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -365,7 +370,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.18" + "mime-types": "~2.1.18" } }, "unpipe": { diff --git a/webapp/package.json b/webapp/package.json index d3fef43..baa1064 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -14,6 +14,7 @@ "body-parser": "^1.18.2", "cookie-parser": "^1.4.3", "express": "^4.7.2", + "formidable": "^1.2.1", "n-readlines": "^0.2.8" } } diff --git a/webapp/server.js b/webapp/server.js index b9d8d59..06fb7dc 100644 --- a/webapp/server.js +++ b/webapp/server.js @@ -1,5 +1,13 @@ 'use strict'; +// Howto: see README.md +//function getUserHome() { + //return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; +//} + + +const profilePath = require('os').homedir(); +var skinDir = profilePath + "/minetest/games/ENLIVEN/mods/codercore/coderskins/textures"; var tz_offset = 240; //subtract this from server time to get local time; 4hrs is 240; 5hrs is 300 //TODO: handle tz_offset not divisible by 60 //var selected_date_s = null; @@ -14,6 +22,10 @@ var express = require('express'), fs = require('fs'), readlines = require('n-readlines'); const os = require('os'); +var formidable = require('formidable') +var querystring = require("querystring"); // built-in +// var util = require('util') + var app = express(); //app.engine('handlebars', exphbs({defaultLayout: 'main'})); //app.set('view engine', 'handlebars'); @@ -267,6 +279,8 @@ function read_log() { } } + + app.get('/get-players', function (req, res) { res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(players)); @@ -286,6 +300,71 @@ app.get('/announce', function (req, res) { res.send(); }); + + +app.get('/skin-form', function (req, res) { + var ret = ""; + ret += ''+"\n"; + ret += '
'+"\n"; + ret += 'User Name (case-sensitive): '+"\n"; + ret += 'Select image to upload:'+"\n"; + ret += ''+"\n"; + ret += ''+"\n"; + ret += '
'+"\n"; + ret += ''; + res.send(ret); + //res.render('home'); +}); + + +//using express & formidable: +app.post('/set-skin', function (req, res){ + var form = new formidable.IncomingForm(); + // from coderskins/readme.txt: + //To install a specific skin for a specific player, name the PNG file + //to be used as follows: + //player_NAME.png + //where NAME is the player's in-game nick. Then copy the PNG file into + //the mod's "textures" directory. + //The PNG file should be a standard Minetest 64x32 or Minecraft 64x64 + //"skin" file. + //Or, if you prefer, create a text file, in the mod's "textures" direc- + //tory with a similar filename: + //player_NAME.skin + //(OldCoder, 2019) + var directPath = ""; + var indirectPath = ""; + var msg = "Uploading..."; + form.parse(req, function(err, fields, files) { + if (err) next(err); + directPath = skinDir + "/player_" + fields.userName + ".png"; + indirectPath = skinDir + "/player_" + fields.userName + ".skin"; + // TODO: make sure my_file and project_id values are present + var originalPath = files.my_file.path; + fs.rename(files.my_file.path, directPath, function(err) { + if (err) { + msg = "Failed to rename " + originalPath + + " to " + directPath + "
\n"; + console.log(msg); + next(err); + } + res.end(); + }); + }); + //form.on('fileBegin', function (name, file){ + ////file.path = __dirname + '/uploads/' + file.name; + //// file.path = skinDir + "/" + file.name; + //// manual_path = "player_" + + //}); + form.on('file', function (name, file){ + msg = 'Uploaded ' + file.name + "
\n"; + console.log(msg); + }); + //res.sendFile(__dirname + '/index.html'); + res.redirect("/?msg=" + querystring.stringify(msg)); +}); + + app.get('/', function (req, res) { var ret = ""; ret += ''; @@ -298,6 +377,11 @@ app.get('/', function (req, res) { // var selected_date_s = null; if (req.query.date) selected_date_s = req.query.date + if (req.query.msg != undefined) { + ret += "
\n"; + ret += "" + querystring.parse(msg) + "
\n"; + ret += "
\n"; + } ret += "assuming minetestserver ran as: " + os.homedir() + "
\n"; ret += "timezone (tz_offset/60*-1): " + (Math.floor(tz_offset/60)*-1) + '
\n'; ret += 'date: ' + selected_date_s + '
'+"\n"; @@ -339,5 +423,5 @@ var server = app.listen(3000, function () { var port = server.address().port; console.log("reading log..."); read_log(); - console.log("EnlivenMinetest webapp listening at http://%s:%s", host, port); + console.log("EnlivenMinetest webapp is listening at http://%s:%s", host, port); });