Skip to content

Commit 0b012de

Browse files
author
Hans Kristian Flaatten
committed
Merge branch 'email/unsubscribe'
2 parents b47ee0c + c86f9c4 commit 0b012de

File tree

8 files changed

+308
-24
lines changed

8 files changed

+308
-24
lines changed

apps/auth/controller.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@ const qs = require('querystring');
2020
const admins = new Set(process.env.APP_ADMINS.split(','));
2121

2222
app.get('/login', (req, res) => {
23-
const error = req.query.error;
24-
const errorDescription = req.query.error_description;
23+
let error;
2524

26-
res.render('login.html', { req, error, errorDescription });
25+
if (req.query.error) {
26+
error = {
27+
title: `Error: ${req.query.error}`,
28+
message: req.query.error_description,
29+
};
30+
}
31+
32+
res.render('login.html', { req, error });
2733
});
2834

2935
app.get('/logout', (req, res) => {

apps/auth/middleware.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ module.exports = function authMiddleware(req, res, next) {
1111
if (!req.session.auth
1212
&& !/^\/favicon.ico/.test(req.originalUrl)
1313
&& !/^\/login/.test(req.originalUrl)
14-
&& !/^\/page\//.test(req.originalUrl)
15-
&& !/^\/app(\/[^\/]+){2}\/(webhook|[0-9a-f]{40})\/?$/.test(req.originalUrl)
14+
&& !/^\/email/.test(req.originalUrl)
1615
) {
1716
return res.redirect('/login');
1817
}

apps/email/controller.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* eslint no-unused-vars: 0 */
2+
'use strict';
3+
4+
const router = require('express').Router;
5+
6+
const app = router();
7+
const ApiUser = require('../app/model').ApiUser;
8+
9+
app.get('/', (req, res) => res.redirect('/email/unsubscribe'));
10+
11+
app.get('/unsubscribe', (req, res, next) => {
12+
if (req.session.auth) {
13+
res.redirect('/profile');
14+
} else {
15+
next();
16+
}
17+
});
18+
19+
app.get('/unsubscribe', (req, res, next) => {
20+
const error = req.session.message;
21+
22+
delete req.session.message;
23+
res.render('email/unsubscribe.html', { req, error });
24+
});
25+
26+
app.get('/unsubscribed', (req, res, next) => {
27+
const error = {
28+
class: 'positive',
29+
title: 'Avmelding gjennomført',
30+
message: 'Du vil ikke lenger motta epost fra Nasjonal Turbase.',
31+
};
32+
33+
res.render('email/unsubscribed.html', { req, error });
34+
});
35+
36+
app.post('/unsubscribe', (req, res, next) => {
37+
if (!req.body.email) {
38+
req.session.message = {
39+
title: 'Avmelding feilet',
40+
message: 'Epost kan ikke være tom',
41+
};
42+
43+
res.set('x-app-status', 'failure');
44+
res.set('x-app-message', 'empty_email');
45+
return res.redirect(303, '/email/unsubscribe');
46+
}
47+
48+
return ApiUser.findOne({ 'contact.email': req.body.email }, (findErr, user) => {
49+
if (findErr) { return res.redirect('/email/unsubscribe'); }
50+
if (!user) { return res.redirect(303, '/email/unsubscribed'); }
51+
52+
user.notify = false;
53+
return user.save({ validateBeforeSave: false }, (saveErr) => {
54+
if (saveErr) { return res.redirect(303, '/email/unsubscribe'); }
55+
return res.redirect(303, '/email/unsubscribed');
56+
});
57+
});
58+
});
59+
60+
app.get('/unsubscribe/:id', (req, res, next) => {
61+
ApiUser.findOne({ _id: req.params.id }, (findErr, user) => {
62+
if (findErr) { return res.redirect(303, '/email/unsubscribe'); }
63+
if (!user) { return res.redirect(303, '/email/unsubscribed'); }
64+
65+
user.notify = false;
66+
return user.save({ validateBeforeSave: false }, (saveErr) => {
67+
if (saveErr) { return res.redirect(303, '/email/unsubscribe'); }
68+
return res.redirect(303, '/email/unsubscribed');
69+
});
70+
});
71+
});
72+
73+
app.get('*', (req, res) => res.redirect('/email'));
74+
75+
module.exports = app;

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ app.use('/', require('./apps/auth/controller'));
3636
app.use('/profile', require('./apps/profile/controller'));
3737
app.use('/app', require('./apps/app/controller'));
3838
app.use('/admin', require('./apps/admin/controller'));
39+
app.use('/email', require('./apps/email/controller'));
3940

4041
// Redirect to /app
4142
app.get('/', (req, res) => {

test/acceptance/email.js

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const supertest = require('supertest');
5+
const req = supertest(require('../../').app);
6+
7+
const ApiUser = require('../../apps/app/model').ApiUser;
8+
const apps = require('../fixtures/apps');
9+
10+
describe('GET /email', () => {
11+
const url = '/email';
12+
13+
it('redirects user to unsubscribe', done => {
14+
req.get(url)
15+
.expect(302)
16+
.expect('Location', '/email/unsubscribe', done);
17+
});
18+
});
19+
20+
describe('GET /email/unsubscribe', () => {
21+
const url = '/email/unsubscribe';
22+
23+
it('redirects authenticated user to profile', done => {
24+
req.get(url)
25+
.set('Cookie', process.env.USER_NO_APPS_COOKIE)
26+
.expect(302)
27+
.expect('Location', '/profile', done);
28+
});
29+
30+
it('returns unsubscribe form', done => {
31+
req.get(url)
32+
.expect(200)
33+
.expect(/Avmelding/)
34+
.expect(/Meld av/, done);
35+
});
36+
});
37+
38+
describe('POST /email/unsubscribe', () => {
39+
const url = '/email/unsubscribe';
40+
41+
it('returns error for missing email', done => {
42+
req.post(url)
43+
.type('form')
44+
.expect(303)
45+
.expect('x-app-status', 'failure')
46+
.expect('x-app-message', 'empty_email')
47+
.expect('Location', '/email/unsubscribe', done);
48+
});
49+
50+
it('unsubscribes existing API user', done => {
51+
req.post(url)
52+
.type('form')
53+
.send({ email: apps[2].contact.email })
54+
.expect(303)
55+
.expect('Location', '/email/unsubscribed')
56+
.end(err => {
57+
assert.ifError(err);
58+
59+
ApiUser.findOne({ _id: apps[2]._id }, (findErr, user) => {
60+
assert.ifError(findErr);
61+
assert.equal(user.notify, false);
62+
done();
63+
});
64+
});
65+
});
66+
67+
it('unsubscribes unsubscribed API user', done => {
68+
req.post(url)
69+
.type('form')
70+
.send({ email: apps[3].contact.email })
71+
.expect(303)
72+
.expect('Location', '/email/unsubscribed')
73+
.end(err => {
74+
assert.ifError(err);
75+
76+
ApiUser.findOne({ _id: apps[3]._id }, (findErr, user) => {
77+
assert.ifError(findErr);
78+
assert.equal(user.notify, false);
79+
done();
80+
});
81+
});
82+
});
83+
84+
it('unsubscribes non-existing API user', done => {
85+
const id = '999999999999999999999999';
86+
const email = '[email protected]';
87+
88+
req.post(url)
89+
.type('form')
90+
.send({ email })
91+
.expect(303)
92+
.expect('Location', '/email/unsubscribed')
93+
.end(err => {
94+
assert.ifError(err);
95+
96+
ApiUser.findOne({ _id: id }, (findErr, user) => {
97+
assert.ifError(findErr);
98+
assert.deepEqual(user, null);
99+
done();
100+
});
101+
});
102+
});
103+
});
104+
105+
describe('GET /email/unsubscribed', () => {
106+
const url = '/email/unsubscribed';
107+
108+
it('returns unsubscribed page', done => {
109+
req.get(url)
110+
.expect(200)
111+
.expect(/Avmeldt/)
112+
.expect(/Avmelding gjennomført/, done);
113+
});
114+
});
115+
116+
describe('GET /email/unsubscribe/:id', () => {
117+
const url = '/email/unsubscribe';
118+
119+
it('redirects user for invalid :id', done => {
120+
req.get(`${url}/123abc`)
121+
.expect(303)
122+
.expect('Location', '/email/unsubscribe', done);
123+
});
124+
125+
it('unsubscribes existing API user', done => {
126+
req.get(`${url}/${apps[1]._id}`)
127+
.expect(303)
128+
.expect('Location', '/email/unsubscribed')
129+
.end(err => {
130+
assert.ifError(err);
131+
132+
ApiUser.findOne({ _id: apps[1]._id }, (findErr, user) => {
133+
assert.ifError(findErr);
134+
assert.equal(user.notify, false);
135+
done();
136+
});
137+
});
138+
});
139+
140+
it('unsubscribes unsubscribed API user', done => {
141+
req.get(`${url}/${apps[2]._id}`)
142+
.expect(303)
143+
.expect('Location', '/email/unsubscribed')
144+
.end(err => {
145+
assert.ifError(err);
146+
147+
ApiUser.findOne({ _id: apps[2]._id }, (findErr, user) => {
148+
assert.ifError(findErr);
149+
assert.equal(user.notify, false);
150+
done();
151+
});
152+
});
153+
});
154+
155+
it('unsubscribes non-existing API user', done => {
156+
const id = '999999999999999999999999';
157+
158+
req.get(`${url}/${id}`)
159+
.expect(303)
160+
.expect('Location', '/email/unsubscribed')
161+
.end(err => {
162+
assert.ifError(err);
163+
164+
ApiUser.findOne({ _id: id }, (findErr, user) => {
165+
assert.ifError(findErr);
166+
assert.deepEqual(user, null);
167+
done();
168+
});
169+
});
170+
});
171+
});

views/email/unsubscribe.html

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% extends "login.html" %}
2+
3+
{% block title %}Avmelding – Nasjonal Turbase{% endblock %}
4+
5+
{% block form %}
6+
<h2 class="ui image header">
7+
<i class="send icon"></i>
8+
<div class="content">Avmelding</div>
9+
</h2>
10+
<form class="ui large form" method="post">
11+
<div class="ui stacked segment">
12+
<div class="two fields">
13+
<div class="field">
14+
<input name="email" type="email" placeholder="Epost">
15+
</div>
16+
<div class="field">
17+
<button type="submit" class="ui fluid large submit button">
18+
Meld av
19+
</button>
20+
</div>
21+
</div>
22+
</div>
23+
24+
{% include "components/message.html" %}
25+
</form>
26+
{% endblock %}

views/email/unsubscribed.html

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{% extends "login.html" %}
2+
3+
{% block title %}Avmeldt – Nasjonal Turbase{% endblock %}
4+
5+
{% block form %}
6+
<h2 class="ui image header">
7+
<i class="send outline icon"></i>
8+
<div class="content">Avmeldt</div>
9+
</h2>
10+
11+
{% endblock %}

views/login.html

+14-19
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,21 @@
2424

2525
<div class="ui middle aligned center aligned grid">
2626
<div class="column">
27-
<h2 class="ui green image header">
28-
<i class="huge map icon"></i>
29-
<div class="content">Nasjonal Turbase Developer</div>
30-
</h2>
31-
<form class="ui large form">
32-
<div class="ui stacked segment">
33-
<a href="/login/github" class="ui fluid large green submit button">
34-
<i class="github icon"></i> Logg inn med GitHub
35-
</a>
36-
</div>
27+
{% block form %}
28+
<h2 class="ui green image header">
29+
<i class="huge map icon"></i>
30+
<div class="content">Nasjonal Turbase Developer</div>
31+
</h2>
32+
<form class="ui large form">
33+
<div class="ui stacked segment">
34+
<a href="/login/github" class="ui fluid large green submit button">
35+
<i class="github icon"></i> Logg inn med GitHub
36+
</a>
37+
</div>
38+
</form>
39+
{% endblock %}
3740

38-
{% if error %}
39-
<div class="ui left aligned top aligned negative message">
40-
<i class="close icon"></i>
41-
<div class="header">Error: {{ error }}</div>
42-
<p>{{ errorDescription }}</p>
43-
</div>
44-
{% endif %}
45-
46-
</form>
41+
{% include "components/message.html" %}
4742

4843
<div class="ui message">
4944
Ny til Nasjonal Turbase? <a href="http://www.nasjonalturbase.no">Les mer</a>

0 commit comments

Comments
 (0)