feat: add gdpr privacy and terms
This commit is contained in:
@ -99,6 +99,10 @@
|
||||
"twitter": {
|
||||
"type": "string"
|
||||
},
|
||||
"acceptedPrivacyTerms": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"sendQuincyEmail": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
|
@ -51,6 +51,20 @@ module.exports = function enableAuthentication(app) {
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/accept-privacy-terms',
|
||||
ifNoUserRedirectHome,
|
||||
(req, res) => {
|
||||
const { user } = req;
|
||||
if (user && !user.acceptedPrivacyTerms) {
|
||||
return res.render('account/accept-privacy-terms', {
|
||||
title: 'Privacy Policy and Terms of Service'
|
||||
});
|
||||
}
|
||||
return res.redirect('/settings');
|
||||
}
|
||||
);
|
||||
|
||||
const defaultErrorMsg = dedent`
|
||||
Oops, something is not right,
|
||||
please request a fresh link to sign in / sign up.
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { check } from 'express-validator/check';
|
||||
|
||||
import {
|
||||
ifNoUser401,
|
||||
createValidatorErrorHandler
|
||||
@ -147,6 +146,36 @@ export default function settingsController(app) {
|
||||
);
|
||||
}
|
||||
|
||||
const updatePrivacyTerms = (req, res, next) => {
|
||||
const {
|
||||
user,
|
||||
body: { quincyemails }
|
||||
} = req;
|
||||
const update = {
|
||||
acceptedPrivacyTerms: true,
|
||||
sendQuincyEmail: !!quincyemails
|
||||
};
|
||||
return user.update$(update)
|
||||
.do(() => {
|
||||
req.user = Object.assign(req.user, update);
|
||||
})
|
||||
.subscribe(
|
||||
() => {
|
||||
res.status(200).json({
|
||||
message: 'We have updated your preferences. ' +
|
||||
'You can now continue using freeCodeCamp.'
|
||||
});
|
||||
},
|
||||
next
|
||||
);
|
||||
};
|
||||
|
||||
api.post(
|
||||
'/update-privacy-terms',
|
||||
ifNoUser401,
|
||||
updatePrivacyTerms
|
||||
);
|
||||
|
||||
api.post(
|
||||
'/refetch-user-completed-challenges',
|
||||
ifNoUser401,
|
||||
|
@ -57,7 +57,8 @@
|
||||
"./middlewares/csp": {},
|
||||
"./middlewares/jade-helpers": {},
|
||||
"./middlewares/flash-cheaters": {},
|
||||
"./middlewares/passport-login": {}
|
||||
"./middlewares/passport-login": {},
|
||||
"./middlewares/privacy-terms-notice": {}
|
||||
},
|
||||
"files": {},
|
||||
"final:after": {
|
||||
|
22
server/middlewares/privacy-terms-notice.js
Normal file
22
server/middlewares/privacy-terms-notice.js
Normal file
@ -0,0 +1,22 @@
|
||||
const ALLOWED_METHODS = ['GET'];
|
||||
const EXCLUDED_PATHS = [
|
||||
'/api/flyers/findOne',
|
||||
'/signout',
|
||||
'/accept-privacy-terms'
|
||||
];
|
||||
|
||||
export default function privacyTermsNotAcceptedNotice() {
|
||||
return function(req, res, next) {
|
||||
if (
|
||||
ALLOWED_METHODS.indexOf(req.method) !== -1 &&
|
||||
EXCLUDED_PATHS.indexOf(req.path) === -1
|
||||
) {
|
||||
const { user } = req;
|
||||
if (user && user.acceptedPrivacyTerms !== true) {
|
||||
res.redirect('/accept-privacy-terms');
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return next();
|
||||
};
|
||||
}
|
123
server/views/account/accept-privacy-terms.jade
Normal file
123
server/views/account/accept-privacy-terms.jade
Normal file
@ -0,0 +1,123 @@
|
||||
extends ../layout
|
||||
block content
|
||||
.container
|
||||
.row.flashMessage.negative-30
|
||||
.col-sm-6.col-sm-offset-3
|
||||
#flash-board.alert.fade.in(style='display: none;')
|
||||
button.close(type='button', data-dismiss='alert')
|
||||
span.ion-close-circled#flash-close
|
||||
#flash-content
|
||||
.col-xs-12
|
||||
#accept-privacy-terms
|
||||
.row
|
||||
.text-center
|
||||
h3 Please review our privacy policy and the terms of service.
|
||||
br
|
||||
.row
|
||||
.col-sm-6.col-sm-offset-3
|
||||
form(method='POST', action='/update-privacy-terms')
|
||||
input(type='hidden', name='_csrf', value=_csrf)
|
||||
.checkbox
|
||||
label
|
||||
input(id='terms', name='privacy', type='checkbox')
|
||||
span.cr
|
||||
i.cr-icon.fa.fa-check
|
||||
| I accept the
|
||||
a(href='https://www.freecodecamp.org/terms' target='_blank') terms of service
|
||||
| (required).
|
||||
.checkbox
|
||||
label
|
||||
input(id='privacy', name='privacy', type='checkbox')
|
||||
span.cr
|
||||
i.cr-icon.fa.fa-check
|
||||
| I accept the
|
||||
a(href='https://www.freecodecamp.org/privacy' target='_blank') privacy policy
|
||||
| (required).
|
||||
.checkbox
|
||||
label
|
||||
input(id='quincyemails', name='quincyemails', type='checkbox')
|
||||
span.cr
|
||||
i.cr-icon.fa.fa-check
|
||||
| I want weekly emails from Quincy (freeCodeCamp.org's founder)
|
||||
.button-spacer
|
||||
button.btn.btn-primary.btn-lg.btn-block(id='submit-button', type='submit')
|
||||
.row
|
||||
.col-sm-6.col-sm-offset-3
|
||||
a.btn.btn-primary.btn-lg.btn-block(id='continue-button', href='/', style='display: none;')
|
||||
| Continue to freeCodeCamp
|
||||
|
||||
script.
|
||||
$(document).ready(function() {
|
||||
|
||||
var checkedBoxCount = 0;
|
||||
function disableContinueButtonForAgreement(isLaunched) {
|
||||
if (isLaunched) {
|
||||
$('#submit-button').prop('disabled', true).html(
|
||||
'<span style="color:#E0E0E0;">Submit<\/span>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLaunched && checkedBoxCount === 2){
|
||||
$('#submit-button').prop('disabled', false).html(
|
||||
'<span>Submit<\/span>');
|
||||
}
|
||||
}
|
||||
disableContinueButtonForAgreement(true);
|
||||
|
||||
$('#terms').click(function() {
|
||||
if (this.checked) {
|
||||
checkedBoxCount++;
|
||||
disableContinueButtonForAgreement(false);
|
||||
} else {
|
||||
checkedBoxCount--;
|
||||
disableContinueButtonForAgreement(true);
|
||||
}
|
||||
});
|
||||
|
||||
$('#privacy').click(function() {
|
||||
if (this.checked) {
|
||||
checkedBoxCount++;
|
||||
disableContinueButtonForAgreement(false);
|
||||
} else {
|
||||
checkedBoxCount--;
|
||||
disableContinueButtonForAgreement(true);
|
||||
}
|
||||
});
|
||||
|
||||
$('form').submit(function(event){
|
||||
event.preventDefault();
|
||||
$('#flash-board').hide();
|
||||
var $form = $(event.target);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : $form.attr('action'),
|
||||
data : $form.serialize(),
|
||||
dataType : 'json',
|
||||
encode : true,
|
||||
xhrFields : { withCredentials: true }
|
||||
})
|
||||
.fail(error => {
|
||||
if (error.responseText){
|
||||
var data = JSON.parse(error.responseText);
|
||||
if(data.message)
|
||||
$('#flash-content').html(data.message);
|
||||
$('#flash-board')
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-info')
|
||||
.fadeIn();
|
||||
}
|
||||
})
|
||||
.done(data =>{
|
||||
if(data && data.message){
|
||||
$('#flash-content').html(data.message);
|
||||
$('#flash-board')
|
||||
.removeClass('alert-info')
|
||||
.addClass('alert-success')
|
||||
.fadeIn();
|
||||
|
||||
$('#accept-privacy-terms').hide();
|
||||
$('#continue-button').show();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user