diff --git a/production/arjion/arjion/Dockerfile b/production/arjion/arjion/Dockerfile new file mode 100644 index 0000000..86903eb --- /dev/null +++ b/production/arjion/arjion/Dockerfile @@ -0,0 +1,5 @@ +FROM node:8-slim +RUN mkdir -p /usr/share/man/man1 && mkdir -p /usr/share/man/man5 && mkdir -p /usr/share/man/man8 +RUN apt update && apt -y upgrade && apt -y install python default-jdk build-essential libimage-exiftool-perl && apt clean +USER node +WORKDIR /arjion \ No newline at end of file diff --git a/production/arjion/arjion/config.js b/production/arjion/arjion/config.js new file mode 100644 index 0000000..c865308 --- /dev/null +++ b/production/arjion/arjion/config.js @@ -0,0 +1,17 @@ +module.exports = { + mailserver: 'smtp.hatthieves.es', + mailport: 587, + mailsecure: true, + mailfrom: 'webmaster@hatthieves.es', + mailuser: 'webmaster@hatthieves.es', + mailpass: 'w3bm4st3r.', + mailtext: verify_link => 'Verify your account visiting next link: https://meta.hatthieves.es/verify?link=' + verify_link, + mailhtml: verify_link => 'Verify your account visiting next Verify Link', + indexhost: 'https://elastic.hatthieves.es', + indexuser: 'docker', + indexpass: 'docker', + index: 'arjion', + type: 'user', + port: 3000, + anonymous: 'anonymous' +} \ No newline at end of file diff --git a/production/arjion/arjion/entrypoint.sh b/production/arjion/arjion/entrypoint.sh new file mode 100644 index 0000000..ba16320 --- /dev/null +++ b/production/arjion/arjion/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/bash +yarn && node server \ No newline at end of file diff --git a/production/arjion/arjion/lib/elastic.js b/production/arjion/arjion/lib/elastic.js new file mode 100644 index 0000000..e1fdb89 --- /dev/null +++ b/production/arjion/arjion/lib/elastic.js @@ -0,0 +1,108 @@ +module.exports = (config, client6) => { + (async () => { + const exist = await client6.indices.exists({ + index: config.index + }) + if (!exist.body) { + await client6.indices.create({ + index: config.index, + body: { + settings: { + number_of_shards: 1, + number_of_replicas: 0 + }, + mappings: { + user: { + dynamic_templates: [ + { + metadata_as_keywords: { + path_match: 'documents.metadata.*', + mapping: { + type: 'keyword' + } + } + } + ], + properties: { + date: { + type: 'date', + format: 'dd-MM-yyyy HH:mm:ss||dd-MM-yyyy||epoch_millis' + }, + user: { + type: 'text', + fielddata: true + }, + password: { + type: 'keyword' + }, + email: { + type: 'text' + }, + verified: { + type: 'boolean' + }, + verify_link: { + type: 'text' + }, + locked: { + type: 'boolean' + }, + documents: { + type: 'nested', + properties: { + date: { + type: 'date', + format: 'dd-MM-yyyy HH:mm:ss||dd-MM-yyyy||epoch_millis' + }, + originalname: { + type: 'text' + }, + filename: { + type: 'text' + }, + path: { + type: 'text' + }, + mimetype: { + type: 'text' + }, + size: { + type: 'long' + }, + metadata: { + type: 'object' + }, + language: { + type: 'text' + }, + sha256: { + type: 'text' + }, + deleted: { + type: 'boolean' + } + } + } + } + } + } + } + }).catch(err => console.error) + await client6.index({ + index: config.index, + type: config.type, + body: { + date: Date.now(), + user: config.anonymous, + password: null, + email: null, + verified: true, + verify_link: null, + documents: [], + locked: false + }, + refresh: true + }).catch(err => console.error) + } + })() +} \ No newline at end of file diff --git a/production/arjion/arjion/lib/index.js b/production/arjion/arjion/lib/index.js new file mode 100644 index 0000000..8d8076d --- /dev/null +++ b/production/arjion/arjion/lib/index.js @@ -0,0 +1,210 @@ +module.exports = (router, passport, config, client6, upload, fs, tika, promisify, crypto, transporter) => { + router.get('/', (req, res) => { + return res.render('home', { user: req.user }) + }) + + router.get('/login', (req, res) => { + return res.render('login', { error: req.flash('error') }) + }) + + router.post('/login', passport.authenticate('local', { failWithError: true, successRedirect: '/' }), (err, req, res, next) => { + if (err) { + req.flash('error', err.message) + return res.redirect('/login') + } + }) + + router.get('/logout', (req, res) => { + req.logout() + return res.redirect('/') + }) + + router.get('/register', (req, res) => { + return res.render('register', { error: req.flash('error') }) + }) + + router.post('/register', (req, res, next) => { + if (req.body.email === req.body.email2) { + if (req.body.username.length >= 4) { + client6.search({ + index: config.index, + body: { + query: { + match: { + user: req.body.username + } + } + } + }, (err, user) => { + if (err) { + return next(err) + } + else if (user.body.hits.total === 0) { + if (req.body.password.length > 6) { + if (req.body.email.match(/\S+@\S+\.\S+/)) { + const verify_link = crypto.createHash('sha256').update(Date.now().toString()).digest('hex') + transporter.sendMail({ + from: config.mailfrom, + to: req.body.email, + subject: 'Verify link', + text: config.mailtext(verify_link), + html: config.mailhtml(verify_link) + }, async (error, info) => { + if (error) { + return next(err) + } else { + await client6.index({ + index: config.index, + type: config.type, + body: { + date: Date.now(), + user: req.body.username, + password: crypto.createHash('sha256').update(req.body.password).digest('base64'), + email: req.body.email, + verified: false, + verify_link: verify_link, + documents: [], + locked: false + }, + refresh: true + }).catch(err => { + return next(err) + }) + return res.render('verify', { message: info }) + } + }) + } else { + req.flash('error', 'Email not valid') + return res.redirect('/register') + } + } else { + req.flash('error', 'Password must be more than 6 chars') + return res.redirect('/register') + } + } else { + req.flash('error', 'User exists') + return res.redirect('/register') + } + }) + } else { + req.flash('error', 'Username must be 4 or more chars') + return res.redirect('/register') + } + } else { + req.flash('error', 'Email must be the same and real') + return res.redirect('/register') + } + }) + + router.get('/verify', (req, res, next) => { + if (req.query.link && req.query.link.length === 64 && req.query.link.match(/^[0-9a-f]{64}$/g)) { + client6.search({ + index: config.index, + body: { + query: { + match: { + verify_link: req.query.link + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.verified) { + await client6.update({ + index: config.index, + type: config.type, + id: user.body.hits.hits[0]._id, + body: { + doc: { + verified: true + } + } + }).catch(err => next(err)) + return res.redirect('/login') + } else { + req.flash('error', 'Invalid user') + return res.redirect('/login') + } + }) + } else { + req.flash('error', 'Invalid link') + return res.redirect('/login') + } + }) + + router.get('/upload', (req, res) => { + return res.render('upload') + }) + + router.post('/upload', upload.array('documents', 6), (req, res, next) => { + client6.search({ + index: config.index, + body: { + query: { + match: { + user: config.anonymous + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.locked) { + const files = req.files.map(file => { + return promisify(tika.language)(fs.readFileSync(__dirname + '/../' + file.path).toString()).then((language, reasonablyCertain) => { + return promisify(tika.meta)(__dirname + '/../' + file.path, { contentType: file.mimetype }).then(async meta => { + delete meta['X-Parsed-By'] + delete meta.resourceName + await client6.update({ + index: config.index, + type: config.type, + id: user.body.hits.hits[0]._id, + body: { + script: { + source: 'ctx._source.documents.add(params.document)', + params: { + document: { + date: Date.now(), + originalname: file.originalname, + filename: file.filename, + path: file.path, + mimetype: file.mimetype, + size: file.size, + metadata: meta, + language: !file.mimetype.match(/^image/) ? language : null, + sha256: crypto.createHash('sha256').update(fs.readFileSync(__dirname + '/../' + file.path)).digest('hex'), + deleted: false + } + } + } + }, + refresh: 'wait_for', + retry_on_conflict: 6 + }).catch(err => next(err)) + return { + name: file.originalname, + size: file.size, + mime: file.mimetype, + language: !file.mimetype.match(/^image/) ? language : null, + filename: file.filename, + metadata: meta + } + }).catch(err => next(err)) + }).catch(err => next(err)) + }) + Promise.all(files).then(data => { + return res.render('file', { documents: data }) + }) + } else { + return next(new Error('File trouble')) + } + }) + }) + + router.get('/error', (req, res) => { + return res.render('error') + }) + + return router +} \ No newline at end of file diff --git a/production/arjion/arjion/lib/passport.js b/production/arjion/arjion/lib/passport.js new file mode 100644 index 0000000..5a3b64f --- /dev/null +++ b/production/arjion/arjion/lib/passport.js @@ -0,0 +1,62 @@ +module.exports = (passport, Strategy, crypto, config, client6) => { + passport.use(new Strategy((username, password, cb) => { + if (username && password) { + client6.search({ + index: config.index, + body: { + query: { + match: { + user: username + } + } + } + }, (err, user) => { + if (err) { + return cb(err) + } + if (!user || !user.body) { + return cb(null, false) + } + if (user.body.hits.total === 1 && user.body.hits.hits[0]._source.verified && !user.body.hits.hits[0]._source.locked + && user.body.hits.hits[0]._source.password === crypto.createHash('sha256').update(password).digest('base64')) { + return cb(null, { + id: user.body.hits.hits[0]._id, + user: user.body.hits.hits[0]._source.user, + email: user.body.hits.hits[0]._source.email + }) + } + else { + return cb(null, false) + } + }) + } else { + return cb(null, false) + } + })) + + passport.serializeUser((user, cb) => { + cb(null, user.user) + }) + + passport.deserializeUser(async (username, cb) => { + client6.search({ + index: config.index, + body: { + query: { + match: { + user: username + } + } + } + }, (err, user) => { + if (err) { + return cb(err) + } + return cb(null, { + id: user.body.hits.hits[0]._id, + user: user.body.hits.hits[0]._source.user, + email: user.body.hits.hits[0]._source.email + }) + }) + }) +} \ No newline at end of file diff --git a/production/arjion/arjion/lib/user.js b/production/arjion/arjion/lib/user.js new file mode 100644 index 0000000..cf84527 --- /dev/null +++ b/production/arjion/arjion/lib/user.js @@ -0,0 +1,236 @@ +module.exports = (router, config, client6, upload, fs, tika, promisify, crypto, exiftool) => { + router.get('/profile', (req, res) => { + return res.render('profile', { user: req.user }) + }) + + router.get('/upload', (req, res) => { + return res.render('upload', { user: req.user }) + }) + + router.post('/upload', upload.array('documents', 6), (req, res, next) => { + const files = req.files.map(file => { + return promisify(tika.language)(fs.readFileSync(__dirname + '/../' + file.path).toString()).then((language, reasonablyCertain) => { + return promisify(tika.meta)(__dirname + '/../' + file.path, { contentType: file.mimetype }).then(async meta => { + delete meta['X-Parsed-By'] + delete meta.resourceName + await client6.update({ + index: config.index, + type: config.type, + id: req.user.id, + body: { + script: { + source: 'ctx._source.documents.add(params.document)', + params: { + document: { + date: Date.now(), + originalname: file.originalname, + filename: file.filename, + path: file.path, + mimetype: file.mimetype, + size: file.size, + metadata: meta, + language: !file.mimetype.match(/^image/) ? language : null, + sha256: crypto.createHash('sha256').update(fs.readFileSync(__dirname + '/../' + file.path)).digest('hex'), + deleted: false + } + } + } + }, + refresh: 'wait_for', + retry_on_conflict: 6 + }).catch(err => next(err)) + return { + name: file.originalname, + size: file.size, + mime: file.mimetype, + language: !file.mimetype.match(/^image/) ? language : null, + filename: file.filename, + metadata: meta + } + }).catch(err => next(err)) + }).catch(err => next(err)) + }) + Promise.all(files).then(data => { + return res.render('file', { documents: data, user: req.user }) + }) + }) + + router.get('/download-meta', (req, res, next) => { + if (req.query.file && req.query.file.length === 32 && req.query.file.match(/^[0-9a-f]{32}$/g)) { + client6.search({ + index: config.index, + body: { + query: { + nested: { + path: 'documents', + query: { + match: { + 'documents.filename': req.query.file + } + } + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.locked) { + const document = user.body.hits.hits[0]._source.documents.filter(document => document.filename === req.query.file)[0] + fs.exists(__dirname + '/../' + document.path, exists => { + if (exists) { + const ep = new exiftool.ExiftoolProcess('/usr/bin/exiftool'), + read = fs.createReadStream(__dirname + '/../' + document.path), + write = fs.createWriteStream(`/tmp/${document.filename}`) + res.set('Content-Disposition', `attachment; filename="${document.originalname}"`) + res.set('Content-Type', 'application/octet-stream') + read.on('error', err => next(err)) + write.on('error', err => next(err)) + write.on('finish', () => { + ep + .open() + .then(() => { + ep.writeMetadata(`/tmp/${document.filename}`, { all: '' }, ['overwrite_original']) + }) + .then(console.log, err => next(err)) + .then(() => { + ep.close() + const nometa = fs.createReadStream(`/tmp/${document.filename}`) + nometa.on('error', err => next(err)) + nometa.pipe(res) + }) + .catch(err => next(err)) + }) + read.pipe(write) + } else { + return next(new Error('File not exists')) + } + }) + } else { + return next(new Error('File trouble')) + } + }) + } else { + return next(new Error('Is not a file')) + } + }) + + router.get('/download', (req, res, next) => { + if (req.query.file && req.query.file.length === 32 && req.query.file.match(/^[0-9a-f]{32}$/g)) { + client6.search({ + index: config.index, + body: { + query: { + nested: { + path: 'documents', + query: { + match: { + 'documents.filename': req.query.file + } + } + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.locked) { + const document = user.body.hits.hits[0]._source.documents.filter(document => document.filename === req.query.file)[0] + fs.exists(__dirname + '/../' + document.path, exists => { + if (exists) { + res.set('Content-Disposition', `attachment; filename="${document.originalname}"`) + res.set('Content-Type', 'application/octet-stream') + fs.createReadStream(__dirname + '/../' + document.path).pipe(res) + } else { + return next(new Error('File not exists')) + } + }) + } else { + return next(new Error('File trouble')) + } + }) + } else { + return next(new Error('Is not a file')) + } + }) + + router.get('/files', (req, res, next) => { + if (req.user && req.user.user) { + client6.search({ + index: config.index, + body: { + query: { + match: { + user: req.user.user + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.locked) { + const documents = user.body.hits.hits[0]._source.documents + res.render('files', { + documents: documents.filter(document => !document.deleted).map(document => { + return { + name: document.originalname, + size: document.size, + mime: document.mimetype, + language: document.language, + filename: document.filename, + metadata: document.metadata + } + }), + user: req.user + }) + } + }) + } else { + return next(new Error('User required')) + } + }) + + router.get('/deletefile', (req, res, next) => { + if (req.query.file && req.query.file.length === 32 && req.query.file.match(/^[0-9a-f]{32}$/g)) { + client6.search({ + index: config.index, + body: { + query: { + nested: { + path: 'documents', + query: { + match: { + 'documents.filename': req.query.file + } + } + } + } + } + }, async (err, user) => { + if (err) { + return next(err) + } else if (user.body.hits.total === 1 && !user.body.hits.hits[0]._source.locked) { + await client6.update({ + index: config.index, + type: config.type, + id: user.body.hits.hits[0]._id, + body: { + script: { + lang: 'painless', + source: 'for (d in ctx._source.documents) { if (d.filename == "' + req.query.file + '") { d.deleted = true }}' + } + }, + refresh: 'wait_for', + retry_on_conflict: 6 + }).catch(err => next(err)) + return res.redirect('/user/files') + } else { + return next(new Error('File trouble')) + } + }) + } else { + return next(new Error('File required')) + } + }) + + return router +} \ No newline at end of file diff --git a/production/arjion/arjion/package.json b/production/arjion/arjion/package.json new file mode 100644 index 0000000..c029db4 --- /dev/null +++ b/production/arjion/arjion/package.json @@ -0,0 +1,35 @@ +{ + "name": "arjion", + "version": "1.0.0", + "description": "Arjion HatMeta", + "main": "server.js", + "scripts": { + "install": "cp -r node_modules/material-components-web/dist/material-components-web.min.css* node_modules/material-icons/iconfont public/css/ && cp node_modules/material-components-web/dist/material-components-web.min.js public/js/" + }, + "keywords": [ + "arjion", + "metadata" + ], + "author": "ale & gus", + "license": "MIT", + "dependencies": { + "body-parser": "*", + "connect-ensure-login": "*", + "connect-flash": "*", + "ejs": "*", + "es6": "npm:@elastic/elasticsearch@^6.8.0", + "es6-promisify": "*", + "express": "*", + "express-session": "*", + "material-components-web": "*", + "material-icons": "*", + "morgan": "*", + "multer": "*", + "node-exiftool": "*", + "nodemailer": "*", + "passport": "*", + "passport-local": "*", + "rotating-file-stream": "^1.4.6", + "tika": "*" + } +} diff --git a/production/arjion/arjion/public/css/main.css b/production/arjion/arjion/public/css/main.css new file mode 100644 index 0000000..4bd8543 --- /dev/null +++ b/production/arjion/arjion/public/css/main.css @@ -0,0 +1,43 @@ +body { + margin: 0 auto; +} + +.index { + color: white; + text-decoration: none; +} + +.mdc-card { + margin: 1rem; +} + +.mdc-layout-grid__cell { + text-align: center; + margin: 0 auto; + width: 650px; +} + +.collapsible:after { + content: "\0002B"; /* Unicode character for "plus" sign (+) */ + font-size: 13px; + color: white; + float: right; + margin-left: 5px; +} + +.active:after { + content: "\2212"; /* Unicode character for "minus" sign (-) */ +} + +.content { + padding: 0 18px; + background-color: white; + max-height: 0; + overflow: hidden; + transition: max-height 0.2s ease-out; +} + +:root { + --mdc-theme-primary: black; + --mdc-theme-secondary: black; +} \ No newline at end of file diff --git a/production/arjion/arjion/public/js/main.js b/production/arjion/arjion/public/js/main.js new file mode 100644 index 0000000..4720366 --- /dev/null +++ b/production/arjion/arjion/public/js/main.js @@ -0,0 +1,46 @@ +window.onload = function () { + new mdc.topAppBar.MDCTopAppBar(document.querySelector('.mdc-top-app-bar')) + var menu = new mdc.menu.MDCMenu(document.querySelector('.mdc-menu')) + menu.setAnchorCorner(mdc.menuSurface.Corner.BOTTOM_LEFT) + document.getElementById('menu-button').addEventListener('click', function (event) { + menu.open = !menu.open + }) + document.querySelectorAll('.mdc-text-field').forEach(function (field) { + mdc.textField.MDCTextField.attachTo(field) + }) + document.querySelectorAll('.mdc-icon-button').forEach(function (field) { + new mdc.iconButton.MDCIconButtonToggle(field) + }) + if (document.querySelector('.collapsible')) { + document.querySelectorAll('.collapsible').forEach(function (col) { + col.addEventListener('click', function () { + this.classList.toggle('active') + var content = this.parentNode.parentNode.nextElementSibling.nextElementSibling + if (content.style.maxHeight) { + content.style.maxHeight = null + } else { + content.style.maxHeight = content.scrollHeight + "px" + } + }) + }) + } + if (document.querySelector('.mdc-dialog')) { + var dialog = new mdc.dialog.MDCDialog(document.querySelector('.mdc-dialog')) + if (document.querySelector('.mdc-dialog #delete')) { + document.querySelectorAll('.delete').forEach(function (d) { + d.addEventListener('click', function (event) { + document.body.setAttribute('data-selected', this.getAttribute('data-filename')) + dialog.open() + }) + }) + document.querySelector('.opened').addEventListener('click', function (event) { + document.body.getAttribute('data-selected') ? window.location.href = '/user/deletefile?file=' + document.body.getAttribute('data-selected') : '' + }) + document.querySelector('.closed').addEventListener('click', function (event) { + dialog.close() + }) + } else if (document.querySelector('.mdc-dialog #error')) { + dialog.open() + } + } +} \ No newline at end of file diff --git a/production/arjion/arjion/server.js b/production/arjion/arjion/server.js new file mode 100644 index 0000000..aa5faf9 --- /dev/null +++ b/production/arjion/arjion/server.js @@ -0,0 +1,79 @@ +const express = require('express'), + passport = require('passport'), + Strategy = require('passport-local').Strategy, + crypto = require('crypto'), + fs = require('fs'), + config = require('./config'), + rfs = require('rotating-file-stream'), + accessLogStream = rfs('access.log', { + interval: '1d', // rotate daily + path: __dirname + '/log' + }), + upload = require('multer')({ + dest: 'uploads/', + limits: { + fileSize: 5 * 1024 * 1024 // 5Mb + } + }), + tika = require('tika'), + flash = require('connect-flash'), + promisify = require("es6-promisify").promisify, + nodemailer = require('nodemailer'), + transporter = nodemailer.createTransport({ + host: config.mailserver, + port: config.mailport, + secure: config.mailsecure, + auth: { + user: config.mailuser, + pass: config.mailpass + } + }), + { Client: Client6 } = require('es6'), + client6 = new Client6({ + node: config.indexhost, + auth: { + username: config.indexuser, + password: config.indexpass + } + }), + exiftool = require('node-exiftool'); + +// Initialize elastic +require('./lib/elastic')(config, client6) + +// Server +const app = express(), + server = app.disable('x-powered-by').listen(config.port, () => { + console.log(`Listening on ${server.address().address}:${server.address().port}`) + }) + +app.set('trust proxy', 1) + +app.set('views', __dirname + '/views') +app.set('view engine', 'ejs') + +// Middleware +app.use(require('morgan')('combined', { stream: accessLogStream })) +app.use(require('body-parser').json()) +app.use(require('body-parser').urlencoded({ extended: false })) +app.use(require('express-session')({ secret: 'keyboard hat', resave: false, saveUninitialized: true })) +app.use(flash()) + +// Auth +require('./lib/passport')(passport, Strategy, crypto, config, client6) +app.use(passport.initialize()) +app.use(passport.session({ cookie: { maxAge: 43200 } })) // 12H + +// Routes +app.use('/', require('./lib/index')(express.Router(), passport, config, client6, upload, fs, tika, promisify, crypto, transporter)) +app.use('/user', require('connect-ensure-login').ensureLoggedIn('/login'), require('./lib/user')(express.Router(), config, client6, upload, fs, tika, promisify, crypto, exiftool)) + +// Resources +app.use('/css', express.static(__dirname + '/public/css')) +app.use('/js', express.static(__dirname + '/public/js')) + +// Errors +app.use((err, req, res, next) => { + res.status(500) + return res.render('error', { error: err.message }) +}) \ No newline at end of file diff --git a/production/arjion/arjion/views/error.ejs b/production/arjion/arjion/views/error.ejs new file mode 100644 index 0000000..2e2a04a --- /dev/null +++ b/production/arjion/arjion/views/error.ejs @@ -0,0 +1,5 @@ +<%- include('header') %> +

Error: <%= locals.error %>, go

+<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/file.ejs b/production/arjion/arjion/views/file.ejs new file mode 100644 index 0000000..b7ed1d8 --- /dev/null +++ b/production/arjion/arjion/views/file.ejs @@ -0,0 +1,78 @@ +<%- include('header') %> +<% if (locals.documents && locals.documents.length > 0) { %> +<% documents.map(document => { + var chips = [] %> +
+
+ +
+
+<% }) + } else { %> +
+
+
+

Error

+
+
    +
  • + NO Documents +
  • +
+
+
+
+
+
+<% } %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/files.ejs b/production/arjion/arjion/views/files.ejs new file mode 100644 index 0000000..6220904 --- /dev/null +++ b/production/arjion/arjion/views/files.ejs @@ -0,0 +1,117 @@ +<%- include('header') %> +<% if (locals.documents && locals.documents.length > 0) { %> +<% documents.map(document => { + var chips = [] %> +
+
+ +
+
+
+ + +
+
+ +
+
+
+<% }) %> +
+
+
+

Delete file?

+
+ You will can NOT recover it... +
+
+ + +
+
+
+
+
+<% } else { %> +
+
+
+

Error

+
+
    +
  • + NO Documents +
  • +
+
+
+
+
+
+<% } %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/footer.ejs b/production/arjion/arjion/views/footer.ejs new file mode 100644 index 0000000..35b14ad --- /dev/null +++ b/production/arjion/arjion/views/footer.ejs @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/production/arjion/arjion/views/header.ejs b/production/arjion/arjion/views/header.ejs new file mode 100644 index 0000000..47de4ab --- /dev/null +++ b/production/arjion/arjion/views/header.ejs @@ -0,0 +1,75 @@ + + + + + + + + + + + + + +
+
+
+ +

school HatMeta

+
+
+
+
+ +
+ +
+
+
+
+
+



+
+
+
\ No newline at end of file diff --git a/production/arjion/arjion/views/home.ejs b/production/arjion/arjion/views/home.ejs new file mode 100644 index 0000000..a02835f --- /dev/null +++ b/production/arjion/arjion/views/home.ejs @@ -0,0 +1,14 @@ +<%- include('header') %> +<% if (!locals.user) { %> +

Welcome! Please or +

+<% } else { %> +

Hello, <%= locals.user.user %>. View your or view your

+<% } %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/login.ejs b/production/arjion/arjion/views/login.ejs new file mode 100644 index 0000000..4bce933 --- /dev/null +++ b/production/arjion/arjion/views/login.ejs @@ -0,0 +1,36 @@ +<%- include('header') %> +
+
+ +
+ +
+
+ +
+ +
+

+
+ +
+
+<% if (locals.error && locals.error.length > 0) { %> +
+
+
+

Error

+
+
    +
  • + <%= locals.error %> +
  • +
+
+
+
+
+
+<% } %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/profile.ejs b/production/arjion/arjion/views/profile.ejs new file mode 100644 index 0000000..dfb1955 --- /dev/null +++ b/production/arjion/arjion/views/profile.ejs @@ -0,0 +1,15 @@ +<%- include('header') %> +
    +
  • + User: <%= locals.user.user %> +
  • + +
  • + Email: <%= locals.user.email %> +
  • + +
+

+ +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/register.ejs b/production/arjion/arjion/views/register.ejs new file mode 100644 index 0000000..585a117 --- /dev/null +++ b/production/arjion/arjion/views/register.ejs @@ -0,0 +1,32 @@ +<%- include('header') %> +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+

+
+ +
+
+<% if (locals.error && locals.error.length > 0) { %> +

Error: <%= locals.error %>

+<% } %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/upload.ejs b/production/arjion/arjion/views/upload.ejs new file mode 100644 index 0000000..c0f38fd --- /dev/null +++ b/production/arjion/arjion/views/upload.ejs @@ -0,0 +1,13 @@ +<%- include('header') %> +
+
+ +
+
+

+
+ +
+
+<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/arjion/views/verify.ejs b/production/arjion/arjion/views/verify.ejs new file mode 100644 index 0000000..7a1bfd9 --- /dev/null +++ b/production/arjion/arjion/views/verify.ejs @@ -0,0 +1,14 @@ +<%- include('header') %> +<% if (locals.message) { + if(message.accepted.length > 0) { + %> +

Visit your email to activate your account

+<% } else { %> +

Error sending email, go

+<% } +} %> +<%- include('footer') %> \ No newline at end of file diff --git a/production/arjion/docker-compose.yml b/production/arjion/docker-compose.yml new file mode 100644 index 0000000..71aaab1 --- /dev/null +++ b/production/arjion/docker-compose.yml @@ -0,0 +1,25 @@ +version: '2' + +services: + arjion: + build: ./arjion + container_name: arjion + hostname: arjion + restart: always + entrypoint: + - /bin/bash + - /arjion/entrypoint.sh + volumes: + - ./arjion:/arjion + expose: + - 3000 + networks: + mynet: + ipv4_address: 172.134.0.101 + +networks: + mynet: + driver: bridge + ipam: + config: + - subnet: 172.134.0.0/24