Skip to content
This repository has been archived by the owner on Feb 26, 2023. It is now read-only.

Commit

Permalink
Add Front-End (#7)
Browse files Browse the repository at this point in the history
* Escape input emails

* Add basic template engine

* Add basic noscript fallback

* Change folder structure and add fallbacks

* Add static files

* Prettify using CSS

* Add JS For a single template

* Extract css and js to dedicated files

* Move stuff to template

* Add frontend

* Trim whitespace

* Add verification Email-Template

* Re-Enable button after success

* Split Layout

* Add dice template

* Fix template

* Please checkstyle

* Use different config file for public directory

* Add full stop

* Add more accurate email validation

* Remove unecessary escape to please eslint
  • Loading branch information
RoiEXLab authored and ssoloff committed Nov 26, 2018
1 parent cf4c048 commit 55a6359
Show file tree
Hide file tree
Showing 23 changed files with 309 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "airbnb-base"
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"body-parser": "^1.18.3",
"express": "^4.16.4",
"express-async-errors": "^3.1.1",
"liquidjs": "^6.1.1",
"nconf": "^0.10.0",
"nodemailer": "^4.7.0",
"pg-promise": "^8.5.2",
Expand Down
7 changes: 7 additions & 0 deletions public/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "airbnb-base",
"env": {
"browser": true,
"node": false
}
}
26 changes: 26 additions & 0 deletions public/email-templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{{ subject }}</title>
<style media="screen">
a.big {
text-align: center;
}
a.big:link, a.big:visited {
background-color: #B8242B;
color: white;
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
}
a.big:hover, a.big:active {
background-color: #8D1C21;
}
</style>
</head>
<body>
{% block -%}{%- endblock %}
</body>
</html>
5 changes: 5 additions & 0 deletions public/email-templates/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<br>
<footer>
<p>This email was sent automatically, if it wasn't you who requested this email, please ignore it.</p>
<p>You can always unsubscribe <a href="{{ unsub }}">here</a>.</p>
</footer>
10 changes: 10 additions & 0 deletions public/email-templates/verify-dice.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% layout 'base' %}
<h1>The dice have been cast!</h1>
<p>Roll-Time: {{ date }}</p>
<p>Results: {{ dice }}</p>
<br>
<p>You can click below to verify your results:</p>
<a class="big" href="{{ url }}">Verify!</a>
<br>
<p>Note we might not be able to correctly verify integrity for very old (1+ years) dice rolls.</p>
{% include 'footer' %}
7 changes: 7 additions & 0 deletions public/email-templates/verify-email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% layout 'base' %}
<h1>Verify your Email on {{ host }}</h1>
<p>You (or someone else prententing to be you) recently registered this email to be used for the dice rolling service.</p>
<p>In order to allow you to use this service you need to click 'Confirm!' below:</p>
<a class="big" href="{{ url }}">Confirm!</a>
<p>Note: The link expires after 24 hours or when a new confirmation email is sent.</p>
{% include 'footer' %}
13 changes: 13 additions & 0 deletions public/partials/form-ajaxify.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% include 'submit-button' %}
<span id="error-display" style="display: none; text-align: center;"></span>
<script type="text/javascript" src="./js/ajax-form.js"></script>
<script type="text/javascript">
registerForm(
'{{ formId }}',
'submit-button',
'error-display',
'{{ method }}',
'{{ url }}',
'{{ buttonText }}',
'Success!');
</script>
14 changes: 14 additions & 0 deletions public/partials/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{{title}} | TripleA Dice Server</title>
<link rel="stylesheet" type="text/css" href="./css/base.css">
</head>
<body>
<div class="center">
<h1>{{title}}</h1>
{% block -%}{%- endblock %}
</div>
</body>
</html>
5 changes: 5 additions & 0 deletions public/partials/submit-button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="extended">
<div class="button-center">
<button id="submit-button" type="submit" name="button">{{ buttonText }}</button>
</div>
</div>
64 changes: 64 additions & 0 deletions public/static/css/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
button {
background-color: #B8242B;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
button:disabled {
background-color: #B8242B7F;
}
button:hover:not(:disabled) {
background-color: #8D1C21;
color: #EEE;
}
input[type=text], input[type=email]{
width: 100%;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
}
.center {
margin: auto;
width: 50%;
padding: 10%;
}
.button-center {
margin: auto;
width: 50%;
text-align: center;
}
h1 {
width: 100%;
text-align: center;
}
.extended {
width: 100%;
}
.lds-dual-ring {
display: inline-block;
width: 32px;
height: 32px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 23px;
height: 23px;
margin: 1px;
border-radius: 50%;
border: 5px solid #fff;
border-color: #fff transparent #fff transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Binary file added public/static/favicon.ico
Binary file not shown.
30 changes: 30 additions & 0 deletions public/static/js/ajax-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
window.registerForm = (formId, buttonId, errorDisplayId, method, url, text, successText) => {
const form = document.getElementById(formId);
const button = document.getElementById(buttonId);
const errorDisplay = document.getElementById(errorDisplayId);
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
button.disabled = true;
button.value = '';
button.innerHTML = '<div class="lds-dual-ring"></div>';
const request = new XMLHttpRequest();
request.addEventListener('load', (serverResponse) => {
const response = JSON.parse(serverResponse.target.responseText);
if (response.status === 'OK') {
errorDisplay.style.display = 'none';
button.innerHTML = successText;
button.disabled = false;
} else {
errorDisplay.style.display = 'block';
errorDisplay.innerHTML = response.errors.join('<br>');
button.disabled = false;
button.innerHTML = text;
}
});
request.open(method, url);
// urlencode the FormData
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send([...formData.entries()].map(e => `${encodeURIComponent(e[0])}=${encodeURIComponent(e[1])}`).join('&'));
});
};
2 changes: 2 additions & 0 deletions public/static/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *
Disallow: /
12 changes: 12 additions & 0 deletions public/views/confirm-register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{%- layout 'layout', title: 'Confirm Registration' -%}
{%- if email and token -%}
{%- capture url %}./api/register/{{ token }}{% endcapture -%}
{%- assign method = 'POST' -%}
{%- assign formId = 'form' -%}
<form id="{{ formId }}" action="{{ url }}" method="{{ method }}">
<input type="hidden" name="email" value="{{ email }}" required>
{% include 'form-ajaxify', buttonText: 'Confirm Registration!' %}
</form>
{%- else -%}
<h2>Invalid Arguments!</h2>
{%- endif -%}
8 changes: 8 additions & 0 deletions public/views/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{%- layout 'layout', title: 'Register for the Dice-Server' -%}
{%- assign url ='./api/register' -%}
{%- assign method = 'POST' -%}
{%- assign formId = 'form' -%}
<form id="{{ formId }}" action="{{ url }}" method="{{ method }}">
<input type="email" name="email" placeholder="Insert your email adress" required>
{% include 'form-ajaxify', buttonText: 'Register!', formId: 'form' %}
</form>
9 changes: 9 additions & 0 deletions public/views/unregister.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{%- layout 'layout', title: 'Unregister from the dice Server' -%}
{%- assign url ='./api/unregister' -%}
{%- assign method = 'POST' -%}
{%- assign formId = 'form' -%}

<form id="{{ formId }}" action="{{ url }}" method="{{ method }}">
<input type="email" name="email" placeholder="Insert your email adress" value="{{ email }}" required>
{% include 'form-ajaxify', buttonText: 'Unregister!' %}
</form>
15 changes: 15 additions & 0 deletions public/views/verify.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{%- layout 'layout', title: 'Verify your dice' %}
{%- if invalid -%}
<h2>Invalid link!</h2>
{%- elsif token and dice and date -%}
{%- capture url %}./api/verify/{{ token }}{% endcapture -%}
{%- assign method = 'GET' -%}
{%- assign formId = 'form' -%}
<form id="{{ formId }}" action="{{ url }}" method="{{ method }}">
<p>Dice Rolled: {{ dice | join: ", " }}</p>
<p>At {{ date | date: "%a, %b %d, %y" }}</p>
{% include 'form-ajaxify', buttonText: 'Verify!' %}
</form>
{%- else -%}
<h2>Malformed JSON</h2>
{%- endif -%}
22 changes: 17 additions & 5 deletions src/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ const Validator = require('./validator');
const EmailManager = require('./email-manager.js');
const Handler = require('./db-handler');

const emailValidation = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

class Api {
constructor(database) {
this.dbHandler = new Handler(database);
this.emailManager = new EmailManager(this.dbHandler, nconf.get('smtp'), nconf.get('server'), nconf.get('emailsender'));
this.validator = new Validator();
}

static isEmail(email) {
return emailValidation.test(email);
}

async registrationMiddleware(req, res, next) {
const errors = [];
await Promise.all([req.body.email1, req.body.email2].map(email => (
Expand Down Expand Up @@ -124,13 +130,13 @@ class Api {
}

async handleEmailRegisterConfirm(req, res) {
const verified = await this.emailManager.verifyEmail(req.params.email, req.params.token);
const verified = await this.emailManager.verifyEmail(req.body.email, req.params.token);
if (verified) {
res.status(200).json({ status: 'OK' });
} else {
res.status(403).json({
status: 'Error',
errors: 'invalid Token or mail.',
errors: ['Invalid Token or E-Mail.'],
});
}
}
Expand All @@ -149,7 +155,14 @@ class Api {

static verifyEmailParam(req, res, next) {
if (typeof req.body.email === 'string') {
next();
if (Api.isEmail(req.body.email)) {
next();
} else {
res.status(422).json({
status: 'Error',
errors: ['Email has invalid format'],
});
}
} else {
res.status(422).json({
status: 'Error',
Expand All @@ -164,8 +177,7 @@ module.exports = (router, database) => {
router.get('/verify/:token', Api.validateVerifyArgs, api.handleVerify.bind(api));
router.post('/roll', api.registrationMiddleware.bind(api), Api.validateRollArgs, api.handleRoll.bind(api));
router.post('/register', Api.verifyEmailParam, api.handleEmailRegister.bind(api));
// TODO replace with frontend and merge with middleware above
router.get('/register/:email/:token', api.handleEmailRegisterConfirm.bind(api));
router.post('/register/:token', api.handleEmailRegisterConfirm.bind(api));
router.post('/unregister', Api.verifyEmailParam, api.handleEmailUnregister.bind(api));

// express.js behaves differently if no next parameter is used here
Expand Down
Loading

0 comments on commit 55a6359

Please sign in to comment.