Unverified Commit a8b8e36a authored by mntmn's avatar mntmn
Browse files

wip: migrate from deprecated swig templates to ejs

parent b4f0fa16
......@@ -2,23 +2,23 @@
To add a new language to Spacedeck Open, follow these steps:
*The steps are ilustrated with Spanish (locale 'es') as the new language*
*The steps are illustrated with Spanish (locale 'es') as the new language*
- Include the new locale ('es') at the locale list (./spacedeck.js)
- Include the new locale ('es') in the locale list (./spacedeck.js):
```
locales: ["en",..., "es"],
```
- Create the new translation file (/locales/**es.js** thar it's a copy of /locales/en.js). and translate the entries.
- Include the javascript for letting Spanish info accesible (at the end of /views/spacedeck.html)
- Create the new translation file (/locales/**es.js**, a copy of /locales/en.js) and translate the entries.
- Include the javascript for the new translation at the end of /views/spacedeck.ejs:
```
...
window.locales.es = {};
...
window.locales.es.translation = {% include "./../locales/es.js" %};
window.locales.es.translation = <%- include "./../locales/es.js" %>;
</script>
```
- Include a radiobutton for users could seleect the new language (/views/partials/account.html)
- Include a radio button for users to select the new language (/views/partials/account.html)
```
<label class="radio" v-bind:class="{checked: user.prefs_language=='es'}" v-on:click="save_user_language('es')">
<input type="radio" id="user-preferences_language" name="language" value="es"><span>Español</span>
......
......@@ -2,8 +2,6 @@
const config = require('config');
const nodemailer = require('nodemailer');
const swig = require('swig');
//var AWS = require('aws-sdk');
module.exports = {
sendMail: (to_email, subject, body, options) => {
......@@ -24,14 +22,9 @@ module.exports = {
plaintext+="\n"+options.action.link+"\n\n";
}
const htmlText = swig.renderFile('./views/emails/action.html', {
text: body.replace(/(?:\n)/g, '<br />'),
options: options
});
if (config.get('mail_provider') === 'console') {
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + htmlText + "\n\n plaintext:\n" + plaintext);
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + plaintext + "\n\n plaintext:\n" + plaintext);
} else if (config.get('mail_provider') === 'smtp') {
let transporter;
......@@ -55,14 +48,12 @@ module.exports = {
});
}
transporter.sendMail({
from: from,
replyTo: reply_to,
to: to_email,
subject: subject,
text: plaintext,
html: htmlText,
text: plaintext
}, function(err, info) {
if (err) {
console.error("Error sending email:", err);
......
......@@ -16,6 +16,7 @@
"cheerio": "0.22.0",
"config": "1.25.1",
"cookie-parser": "~1.4.3",
"ejs": "3.1.5",
"execSync": "latest",
"express": "^4.16.4",
"file-type": "^7.6.0",
......@@ -42,7 +43,6 @@
"serve-static": "^1.13.1",
"slug": "^1.1.0",
"sqlite3": "^4.0.0",
"swig": "1.4.2",
"umzug": "^2.1.0",
"underscore": "1.8.3",
"uuid": "^3.2.1",
......
......@@ -59,9 +59,6 @@ function load_resource(method, path, data, on_success, on_error, on_progress) {
if (channel_id) {
req.setRequestHeader("X-Spacedeck-Channel", channel_id);
}
if (csrf_token) {
req.setRequestHeader("X-csrf-token", csrf_token);
}
try {
if (data) {
......
......@@ -11,7 +11,6 @@ var importer = require('../../helpers/importer');
var bcrypt = require('bcryptjs');
var crypto = require('crypto');
var swig = require('swig');
var async = require('async');
var _ = require('underscore');
var fs = require('fs');
......
......@@ -15,7 +15,7 @@ const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');
router.get('/', (req, res) => {
res.render('index', { title: 'Spaces' });
res.render('index', { config:config, user:req.user });
});
router.get('/ping', (req, res) => {
......@@ -23,35 +23,35 @@ router.get('/ping', (req, res) => {
});
router.get('/spaces', (req, res) => {
res.render('spacedeck', { title: 'Spaces' });
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/not_found', (req, res) => {
res.render('not_found', { title: 'Spaces' });
res.render('not_found', {});
});
router.get('/confirm/:token', (req, res) => {
res.render('spacedeck', { title: 'Space' });
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/folders/:id', (req, res) => {
res.render('spacedeck', {});
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/signup', (req, res) => {
res.render('spacedeck', {});
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/accept/:id', (req, res) => {
res.render('spacedeck', {});
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/password-reset', (req, res) => {
res.render('spacedeck', { title: 'Signup' });
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/password-confirm/:token', (req, res) => {
res.render('spacedeck', { title: 'Signup' });
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/de/*', (req, res) => {
......@@ -69,6 +69,7 @@ router.get('/fr/*', (req, res) => {
router.get('/fr', (req, res) => {
res.redirect("/t/fr");
});
router.get('/oc/*', (req, res) => {
res.redirect("/t/oc");
});
......@@ -76,6 +77,7 @@ router.get('/oc/*', (req, res) => {
router.get('/oc', (req, res) => {
res.redirect("/t/oc");
});
router.get('/en/*', (req, res) => {
res.redirect("/t/en");
});
......@@ -89,27 +91,11 @@ router.get('/account', (req, res) => {
});
router.get('/login', (req, res) => {
res.render('spacedeck');
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/logout', (req, res) => {
res.render('spacedeck');
});
router.get('/contact', (req, res) => {
res.render('public/contact');
});
router.get('/about', (req, res) => {
res.render('public/about');
});
router.get('/terms', (req, res) => {
res.render('public/terms');
});
router.get('/privacy', (req, res) => {
res.render('public/privacy');
res.render('spacedeck', { config:config, user:req.user });
});
router.get('/t/:id', (req, res) => {
......@@ -136,7 +122,7 @@ router.get('/s/:hash', (req, res) => {
}
} else {
if (req.accepts('text/html')) {
res.status(404).render('not_found', { title: 'Page Not Found.' });
res.status(404).render('not_found', {});
} else {
res.status(404).json({});
}
......@@ -145,7 +131,7 @@ router.get('/s/:hash', (req, res) => {
});
router.get('/spaces/:id', (req, res) => {
res.render('spacedeck', { title: 'Space' });
res.render('spacedeck', { config:config, user:req.user });
});
module.exports = router;
......@@ -16,7 +16,6 @@ const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const swig = require('swig');
const i18n = require('i18n-2');
const helmet = require('helmet');
......@@ -40,16 +39,7 @@ i18n.expressBind(app, {
devMode: (app.get('env') == 'development')
});
swig.setDefaults({
varControls: ["[[", "]]"] // otherwise it's not compatible with vue.js
});
swig.setFilter('cdn', function(input, idx) {
return input;
});
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('view engine', 'ejs');
if (isProduction) {
app.set('views', path.join(__dirname, 'build', 'views'));
......@@ -114,7 +104,6 @@ if (config.get('storage_local_path')) {
//app.use(require('./middlewares/404'));
if (app.get('env') == 'development') {
app.set('view cache', false);
swig.setDefaults({cache: false});
} else {
app.use(require('./middlewares/500'));
}
......
<html>
<body>
<h2>[[space.name]]</h2>
<table class="table table-striped" border=1>
<tr>
<th>created</th>
<th>updated</th>
<th>filetype</th>
<th>filename</th>
<th>preview</th>
</tr>
{% for a in space.artifacts %}
<tr>
<td>[[ a.created_at | date('d.m.Y H:i') ]] by [[ a.user.email ]][[ a.editor_name ]]</td>
<td>[[ a.updated_at | date('d.m.Y H:i') ]] by [[ a.update_user.email ]][[ a.last_update_editor_name ]]</td>
<td>[[ a.mime ]]</td>
<td>{% if a.payload_uri %}<a href="[[a.payload_uri]]">[[ a.filename ]]</a>{% endif %}</td>
<td>[[ a.description ]]</td>
</tr>
{% endfor %}
</table>
</body>
</html>
[[ text | safe ]]
{% if options.message %}
<p>
<i>[[options.message]]</i>
</p>
{% endif %}
{% if options.action %}<br><br>
<a href="[[options.action.link]]" target="_blank">[[options.action.name]]</a><br>
{% endif %}
<%- include('layouts/outer-header') -%>
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>
<%- include('layouts/outer-footer') -%>
<h1>[[ message ]]</h1>
<h2>[[ error.status ]]</h2>
<pre>[[ error.stack ]]</pre>
<!DOCTYPE html>
<html>
<head>
<title>[[space.name]]</title>
<meta charset="utf-8" />
<meta property="og:title" content="[[space.name]]" />
<meta property="og:description" content="" />
<meta property="og:updated_time" content="[[space.updated_at.getTime()]]" />
<meta property="og:type" content="website" />
<meta property="og:image" content="[[space.thumbnail_url]]" />
</head>
<body>
<h1>[[space.name]]</h1>
{% for a in space.artifacts %}
<tr>
<td>[[ a.mime ]]</td>
<td>[[ a.description | striptags ]]</td>
<td>{% if a.payload_uri %}<a href="[[ a.payload_uri ]]">download</a>{% endif %}</td>
</tr>
{% endfor %}
</body>
</html>
{% extends 'layouts/outer.html' %}
{% block title %}Spacedeck{% endblock %}
{% block content %}
<%- include('layouts/outer-header') %>
<div id="landing">
<section>
<h1>Work Together, Visually.</h1>
......@@ -30,5 +25,4 @@
</p>
</section>
</div>
{% endblock %}
<%- include('layouts/outer-footer') %>
<div class="footer">
<p>
<div class="col-xs-6">
&copy; 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br>
&copy; 2011–2020 Spacedeck GmbH (in liquidation)<br>
Source Code: <a href="https://github.com/mntmn/spacedeck-open">https://github.com/mntmn/spacedeck-open</a>
<br>
Font: <a href="https://rsms.me/inter/">Inter by rsms</a>
</div>
</p>
</div>
</body>
</html>
......@@ -2,49 +2,28 @@
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Spacedeck Open – {% block title %}{% endblock %}</title>
<title>Spacedeck Open</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link href="[[ '/images/favicon.png' | cdn ]]" rel="icon" type="image/x-icon" />
<link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]">
<script> var csrf_token = '[[ csrf_token ]]'; </script>
<!--script src="[[ '/javascripts/jquery-2.1.4.min.js' | cdn ]]"></script-->
<link href="/images/favicon.png" rel="icon" type="image/x-icon" />
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<header id="landing-header" class="header">
<div class="header-left">
<a class="btn btn-transparent btn-nude" href="[[config.endpoint]]/"><img src="[[ '/images/sd6-logo-black.svg' | cdn ]]" width="190"></a>
<a class="btn btn-transparent btn-nude" href="<%= config.endpoint %>/"><img src="/images/sd6-logo-black.svg" width="190"></a>
</div>
<div class="header-right pull-right">
{% if !user %}
<a class="btn btn-md btn-dark btn-round" href="/login">[[__("login")]]</a>
<a class="btn btn-md btn-dark btn-round" href="/signup">[[__("signup")]]</a>
{% else %}
<a class="btn btn-md btn-dark btn-round" href="/spaces">[[__("spaces")]]</a>
<a class="btn btn-md btn-dark btn-round" href="/logout">[[__("logout")]]</a>
{% endif %}
<% if (!user) { %>
<a class="btn btn-md btn-dark btn-round" href="/login"><%=__("login")%></a>
<a class="btn btn-md btn-dark btn-round" href="/signup"><%=__("signup")%></a>
<% } else { %>
<a class="btn btn-md btn-dark btn-round" href="/spaces"><%=__("spaces")%></a>
<a class="btn btn-md btn-dark btn-round" href="/logout"><%=__("logout")%></a>
<% } %>
</div>
</header>
{% block content %}{% endblock %}
<div class="footer">
<p>
<div class="col-xs-6">
&copy; 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br>
&copy; 2011–2019 Spacedeck GmbH (in liquidation)<br>
Source Code: <a href="https://github.com/mntmn/spacedeck-open">https://github.com/mntmn/spacedeck-open</a>
<br>
Font: <a href="https://rsms.me/inter/">Inter by rsms</a>
</div>
</p>
</div>
</body>
</html>
{% extends 'layouts/outer.html' %}
{% block title %}[[ __("not_found") ]]{% endblock %}
{% block content %}
<div id="landing" style="padding-top:200px;margin:auto;width:300px;">
<h1>[[__("not_found")]]</h1>
<h1><%=__("not_found")%></h1>
</div>
{% endblock %}
......@@ -17,11 +17,11 @@
<div class="dialog-freestanding dialog in" v-if="active_view == 'account' && user" v-cloak>
<div class="dialog-tabs" style="margin:auto">
<div class="dialog-tab" v-bind:class="{open:account=='profile'}" v-on:click="account='profile'"><span>[[__("profile_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='language'}" v-on:click="account='language'"><span>[[__("language_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='notifications'}" v-on:click="account='notifications'"><span>[[__("notifications_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='password'}" v-on:click="account='password'"><span>[[__("password_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='terminate'}" v-on:click="account='terminate'"><span>[[__("terminate_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='profile'}" v-on:click="account='profile'"><span><%=__("profile_caption")%></span></div>
<div class="dialog-tab" v-bind:class="{open:account=='language'}" v-on:click="account='language'"><span><%=__("language_caption")%></span></div>
<div class="dialog-tab" v-bind:class="{open:account=='notifications'}" v-on:click="account='notifications'"><span><%=__("notifications_caption")%></span></div>
<div class="dialog-tab" v-bind:class="{open:account=='password'}" v-on:click="account='password'"><span><%=__("password_caption")%></span></div>
<div class="dialog-tab" v-bind:class="{open:account=='terminate'}" v-on:click="account='terminate'"><span><%=__("terminate_caption")%></span></div>
</div>
<div class="dialog-section text-left">
......@@ -44,11 +44,11 @@
<div class="form-group">
<label class="file btn btn-md btn-darken" style="margin-right: 5px;">
<input type="file" v-on:change="save_user_avatar_image(this)">
<span v-if="!uploading_avatar">[[__("upload_avatar")]]</span>
<span v-if="uploading_avatar">[[__("uploading_avatar")]]</span>
<span v-if="!uploading_avatar"><%=__("upload_avatar")%></span>
<span v-if="uploading_avatar"><%=__("uploading_avatar")%></span>
</label>
<p class="message">[[__("avatar_dimensions")]]</p>
<p class="message"><%=__("avatar_dimensions")%></p>
</div>
</div>
</div>
......@@ -66,7 +66,7 @@
</div>
<div class="form-group">
<label class="label" >[[__("profile_name")]]</label>
<label class="label" ><%=__("profile_name")%></label>
<input type="text" id="user-nickname"
pattern=".{3,}"
required title="3 characters minimum"
......@@ -75,7 +75,7 @@
</div>
<div class="form-group">
<label class="label">[[__("profile_email")]]</label>
<label class="label"><%=__("profile_email")%></label>
<input
type="email"
id="new-email"
......@@ -120,7 +120,7 @@
<label class="checkbox"
v-bind:class="{checked: user.prefs_email_notifications}"
v-on:click="account_save_user_notifications(!user.prefs_email_notifications);">
<span>[[__('notifications_option_chat')]]</span>
<span><%=__('notifications_option_chat')%></span>
</label>
</div>
</div>
......@@ -130,15 +130,15 @@
<h4>Change Password</h4>
<div class="modal-section labels-inline">
<div class="form-group">
<label class="label">[[__("current_password")]]</label>
<label class="label"><%=__("current_password")%></label>
<input id="current-password" class="input input-white no-b" v-model="password_change_current" type="password">
</div>
<div class="form-group">
<label class="label">[[__("new_password")]]</label>
<label class="label"><%=__("new_password")%></label>
<input id="new-password" class="input input-white no-b" v-model="password_change_new" type="password">
</div>
<div class="form-group">
<label class="label">[[__("verify_password")]]</label>
<label class="label"><%=__("verify_password")%></label>
<input id="new-password-confirmation" class="input input-white no-b" v-model="password_change_new_confirmation" type="password">
</div>
......@@ -149,7 +149,7 @@
<button
class="btn btn-dark btn-md"
v-on:click="save_user_password(password_change_current, password_change_new, password_change_new_confirmation);" >
[[__("change_password")]]
<%=__("change_password")%>
</button>
</div>
</div>
......@@ -158,14 +158,14 @@
<h4>Terminate Account</h4>
<div class="modal-section labels-inline">
<div class="form-group">
<label class="label">[[__("current_password")]]</label>
<label class="label"><%=__("current_password")%></label>
<input v-model="account_remove_password" class="input input-white no-b" type="password">
</div>
<div class="form-group">
<label class="label">[[__("terminate_reason")]]</label>
<label class="label"><%=__("terminate_reason")%></label>
<textarea class="input input-white no-b" v-model="account_remove_feedback"></textarea>
<p class="message">[[__("terminate_reason_caption")]]</p>
<p class="message"><%=__("terminate_reason_caption")%></p>
</div>
</div>
......
......@@ -3,9 +3,9 @@
<a class="btn btn-dark btn-md btn-round btn-icon" href="/spaces">
<span class="icon icon-svg icon-sd6"></span>
</a>
<button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-dark btn-md btn-round" v-on:click="create_space('space')">[[ __('create_space') ]]</button>
<button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-dark btn-md btn-round" v-on:click="create_space('space')"><%= __('create_space') %></button>
<button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-stroke-darken btn-md btn-round" v-on:click="create_space('folder')">
<span>[[ __('create_folder') ]]</span>
<span><%= __('create_folder') %></span>
</button>
<label class="relative compact-hidden" v-if="logged_in">
......@@ -13,33 +13,33 @@
<input id="folder-search"
type="search" name="search"
style="padding-left: 40px !important; margin-right: 10px;"
placeholder="[[ __('search') ]]"
placeholder="<%= __('search') %>"
class="input input-md input-white input-round no-b w-2"
v-model="folder_spaces_search" v-on:change="search_spaces">
</label>
<div class="dropdown top light m-r-20 compact-hidden" v-bind:class="{open : active_dropdown=='folder_sorting'}" v-if="logged_in">
<button class="btn btn-sm btn-nude" v-on:click="activate_dropdown('folder_sorting')">
<span>[[ __('sort_by') ]]</span>:
<b v-if="folder_sorting=='updated_at'">[[ __('last_modified') ]]</b>
<b v-if="folder_sorting=='name'">[[ __('title') ]]</b>
<b v-if="folder_sorting=='space_type'">[[ __('type') ]]</b>
<span><%= __('sort_by') %></span>:
<b v-if="folder_sorting=='updated_at'"><%= __('last_modified') %></b>
<b v-if="folder_sorting=='name'"><%= __('title') %></b>
<b v-if="folder_sorting=='space_type'"><%= __('type') %></b>
</button>
<div class="dropdown-menu" role="menu">
<ul class="select-list">
<li v-bind:class="{checked:folder_sorting=='updated_at'}"
v-on:click="set_folder_sorting('updated_at',true)">
<span>[[ __('last_modified') ]]</span>
<span><%= __('last_modified') %></span>
</li>
<li v-bind:class="{checked:folder_sorting=='name'}"
v-on:click="set_folder_sorting('name',false)">
<span>[[ __('title') ]]</span>
<span><%= __('title') %></span>
</li>
<li v-bind:class="{checked:folder_sorting=='space_type'}"
v-on:click="set_folder_sorting('space_type',false)">
<span>[[ __('type') ]]</span>
<span><%= __('type') %></span>