Merge pull request #7564 from QuincyLarson/feature/settings-page

Create settings page with email settings
This commit is contained in:
Berkeley Martinez
2016-03-15 11:33:56 -07:00
6 changed files with 270 additions and 118 deletions

View File

@ -170,6 +170,10 @@ ul {
margin-top: 15px; margin-top: 15px;
} }
.positive-20 {
margin-top: 20px;
}
.positive-15-bottom { .positive-15-bottom {
margin-bottom: 15px; margin-bottom: 15px;
} }

View File

@ -110,6 +110,14 @@
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
"sendNotificationEmail": {
"type": "boolean",
"default": true
},
"sendQuincyEmail": {
"type": "boolean",
"default": true
},
"isLocked": { "isLocked": {
"type": "boolean", "type": "boolean",
"default": false, "default": false,

View File

@ -26,7 +26,9 @@ module.exports = function(app) {
router.get('/pmi-acp-agile-project-managers-form', agileProjectManagersForm); router.get('/pmi-acp-agile-project-managers-form', agileProjectManagersForm);
router.get('/nonprofits', nonprofits); router.get('/nonprofits', nonprofits);
router.get('/nonprofits-form', nonprofitsForm); router.get('/nonprofits-form', nonprofitsForm);
router.get('/unsubscribe/:email', unsubscribe); router.get('/unsubscribe/:email', unsubscribeMonthly);
router.get('/unsubscribe-notifications/:email', unsubscribeNotifications);
router.get('/unsubscribe-quincy/:email', unsubscribeQuincy);
router.get('/unsubscribed', unsubscribed); router.get('/unsubscribed', unsubscribed);
router.get('/get-started', getStarted); router.get('/get-started', getStarted);
router.get('/submit-cat-photo', submitCatPhoto); router.get('/submit-cat-photo', submitCatPhoto);
@ -279,18 +281,45 @@ module.exports = function(app) {
res.redirect('https://twitch.tv/freecodecamp'); res.redirect('https://twitch.tv/freecodecamp');
} }
function unsubscribe(req, res, next) { function unsubscribeMonthly(req, res, next) {
User.findOne({ where: { email: req.params.email } }, function(err, user) { req.checkParams('email', 'Must send a valid email').isEmail();
if (user) { return User.findOne({ where: { email: req.params.email } }, (err, user) => {
if (err) { return next(err); }
return user.updateAttribute('sendMonthlyEmail', false, (err) => {
if (err) { return next(err); } if (err) { return next(err); }
user.sendMonthlyEmail = false; req.flash('info', {
return user.save(function() { msg: 'We\'ve successfully updated your Email preferences.'
if (err) { return next(err); }
return res.redirect('/unsubscribed');
}); });
} else {
return res.redirect('/unsubscribed'); return res.redirect('/unsubscribed');
} });
});
}
function unsubscribeNotifications(req, res, next) {
req.checkParams('email', 'Must send a valid email').isEmail();
return User.findOne({ where: { email: req.params.email } }, (err, user) => {
if (err) { return next(err); }
return user.updateAttribute('sendNotificationEmail', false, (err) => {
if (err) { return next(err); }
req.flash('info', {
msg: 'We\'ve successfully updated your Email preferences.'
});
return res.redirect('/unsubscribed');
});
});
}
function unsubscribeQuincy(req, res, next) {
req.checkParams('email', 'Must send a valid email').isEmail();
return User.findOne({ where: { email: req.params.email } }, (err, user) => {
if (err) { return next(err); }
return user.updateAttribute('sendQuincyEmail', false, (err) => {
if (err) { return next(err); }
req.flash('info', {
msg: 'We\'ve successfully updated your Email preferences.'
});
return res.redirect('/unsubscribed');
});
}); });
} }

View File

@ -153,6 +153,21 @@ module.exports = function(app) {
sendNonUserToMap, sendNonUserToMap,
toggleLockdownMode toggleLockdownMode
); );
router.get(
'/toggle-announcement-email-mode',
sendNonUserToMap,
toggleReceivesAnnouncementEmails
);
router.get(
'/toggle-notification-email-mode',
sendNonUserToMap,
toggleReceivesNotificationEmails
);
router.get(
'/toggle-quincy-email-mode',
sendNonUserToMap,
toggleReceivesQuincyEmails
);
router.post( router.post(
'/account/delete', '/account/delete',
ifNoUser401, ifNoUser401,
@ -163,6 +178,11 @@ module.exports = function(app) {
sendNonUserToMap, sendNonUserToMap,
getAccount getAccount
); );
router.get(
'/settings',
sendNonUserToMap,
getSettings
);
router.get('/vote1', vote1); router.get('/vote1', vote1);
router.get('/vote2', vote2); router.get('/vote2', vote2);
@ -228,6 +248,10 @@ module.exports = function(app) {
return res.redirect('/' + username); return res.redirect('/' + username);
} }
function getSettings(req, res) {
res.render('account/settings');
}
function returnUser(req, res, next) { function returnUser(req, res, next) {
const username = req.params.username.toLowerCase(); const username = req.params.username.toLowerCase();
const { user, path } = req; const { user, path } = req;
@ -326,7 +350,7 @@ module.exports = function(app) {
user => { user => {
if (!user) { if (!user) {
req.flash('errors', { req.flash('errors', {
msg: `We couldn't find the user with the username ${username}` msg: `We couldn't find a user with the username ${username}`
}); });
return res.redirect('/'); return res.redirect('/');
} }
@ -394,33 +418,62 @@ module.exports = function(app) {
} }
function toggleLockdownMode(req, res, next) { function toggleLockdownMode(req, res, next) {
if (req.user.isLocked === true) { return User.findById(req.accessToken.userId, function(err, user) {
req.user.isLocked = false;
return req.user.save(function(err) {
if (err) { return next(err); }
req.flash('success', {
msg: dedent`
Other people can now view all your challenge solutions.
You can change this back at any time in the "Manage My Account"
section at the bottom of this page.
`
});
return res.redirect('/' + req.user.username);
});
}
req.user.isLocked = true;
return req.user.save(function(err) {
if (err) { return next(err); } if (err) { return next(err); }
return user.updateAttribute('isLocked', !user.isLocked, function(err) {
req.flash('success', { if (err) { return next(err); }
msg: dedent` req.flash('info', {
All your challenge solutions are now hidden from other people. msg: 'We\'ve successfully updated your Privacy preferences.'
You can change this back at any time in the "Manage My Account" });
section at the bottom of this page. return res.redirect('/settings');
` });
});
}
function toggleReceivesAnnouncementEmails(req, res, next) {
return User.findById(req.accessToken.userId, function(err, user) {
if (err) { return next(err); }
return user.updateAttribute(
'sendMonthlyEmail',
!user.sendMonthlyEmail,
(err) => {
if (err) { return next(err); }
req.flash('info', {
msg: 'We\'ve successfully updated your Email preferences.'
});
return res.redirect('/settings');
});
});
}
function toggleReceivesQuincyEmails(req, res, next) {
return User.findById(req.accessToken.userId, function(err, user) {
if (err) { return next(err); }
return user.updateAttribute('sendQuincyEmail', !user.sendQuincyEmail,
(err) => {
if (err) { return next(err); }
req.flash('info', {
msg: 'We\'ve successfully updated your Email preferences.'
});
return res.redirect('/settings');
}
);
});
}
function toggleReceivesNotificationEmails(req, res, next) {
return User.findById(req.accessToken.userId, function(err, user) {
if (err) { return next(err); }
return user.updateAttribute(
'sendNotificationEmail',
!user.sendNotificationEmail,
function(err) {
if (err) { return next(err); }
req.flash('info', {
msg: 'We\'ve successfully updated your Email preferences.'
});
return res.redirect('/settings');
}); });
return res.redirect('/' + req.user.username);
}); });
} }
@ -428,7 +481,7 @@ module.exports = function(app) {
User.destroyById(req.user.id, function(err) { User.destroyById(req.user.id, function(err) {
if (err) { return next(err); } if (err) { return next(err); }
req.logout(); req.logout();
req.flash('info', { msg: 'Your account has been deleted.' }); req.flash('info', { msg: 'You\'ve successfully deleted your account.' });
return res.redirect('/'); return res.redirect('/');
}); });
} }
@ -459,7 +512,7 @@ module.exports = function(app) {
if (err) { return next(err); } if (err) { return next(err); }
debug('password reset processed successfully'); debug('password reset processed successfully');
req.flash('info', { msg: 'password reset processed successfully' }); req.flash('info', { msg: 'You\'ve successfully reset your password.' });
return res.redirect('/'); return res.redirect('/');
}); });
}); });

View File

@ -0,0 +1,129 @@
extends ../layout
block content
h1.text-center Settings for your Account
hr
h2.text-center Actions
.row
.col-xs-12
if (!user.isGithubCool)
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
i.fa.fa-github
| Link my GitHub to unlock my portfolio
else
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
i.fa.fa-github
| Update my portfolio from GitHub
if (!user.twitter)
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/link/twitter')
i.fa.fa-twitter
| Add my Twitter to my portfolio
if (!user.facebook)
a.btn.btn-lg.btn-block.btn-facebook.btn-link-social(href='/link/facebook')
i.fa.fa-facebook
| Add my Facebook to my portfolio
if (!user.linkedin)
a.btn.btn-lg.btn-block.btn-linkedin.btn-link-social(href='/link/linkedin')
i.fa.fa-linkedin
| Add my LinkedIn to my portfolio
if (!user.google)
a.btn.btn-lg.btn-block.btn-google-plus.btn-link-social(href='/link/google')
i.fa.fa-google-plus
| Add my Google+ to my portfolio
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/logout')
| Sign me out of Free Code Camp
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='mailto:team@freecodecamp.com')
| Email us at team@freecodecamp.com
.spacer
h2.text-center Account Settings
.row
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/commit')
| Edit my pledge
.spacer
h2.text-center Privacy Settings
.row
.col-xs-12.col-sm-8.col-sm-offset-2.col-md-6.col-md-offset-3
.row
.col-xs-9
p.large-p Make all of my solutions private
br
| (this disables your certificates)
if (user.isLocked)
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.active.positive-20(href='/toggle-lockdown-mode') On
else
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.positive-20(href='/toggle-lockdown-mode') Off
.spacer
h2.text-center Email settings
.row
.col-xs-12.col-sm-8.col-sm-offset-2.col-md-6.col-md-offset-3
.row
.col-xs-9
p.large-p Send me announcement emails
br
| (we'll send you these every Thursday)
if (user.sendMonthlyEmail)
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.active.positive-20(href='/toggle-announcement-email-mode') On
else
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.positive-20(href='/toggle-announcement-email-mode') Off
.row
.col-xs-9
p.large-p Send me notification emails
br
| (these will pertain to your account)
if (user.sendNotificationEmail)
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.active.positive-20(href='/toggle-notification-email-mode') On
else
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.positive-20(href='/toggle-notification-email-mode') Off
.row
.col-xs-9
p.large-p Send me Quincy's weekly email
br
| (with new articles every Tuesday)
if (user.sendQuincyEmail)
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.active.positive-20(href='/toggle-quincy-email-mode') On
else
.col-xs-3
a.btn.btn-lg.btn-primary.btn-block.positive-20(href='/toggle-quincy-email-mode') Off
.spacer
h2.text-center Danger Zone
.row
.col-xs-12
a.btn.btn-lg.btn-block.btn-danger.btn-link-social.confirm-deletion
| Delete my Free Code Camp account
script.
$('.confirm-deletion').on("click", function () {
$('#modal-dialog').modal('show');
});
#modal-dialog.modal.animated.wobble
.modal-dialog
.modal-content
.modal-header
a.close(href='#', data-dismiss='modal', aria-hidden='true') ×
h3 You don't really want to delete your account, do you?
.modal-body
p This will really delete all your data, including all your progress, news stories and brownie points.
p We won't be able to recover any of it for you later, even if you change your mind.
p If there's something we could do better, send us an email instead and we'll do our best:  
a(href="mailto:team@freecodecamp.com") team@freecodecamp.com
| .
.modal-footer
a.btn.btn-success.btn-block(href='#', data-dismiss='modal', aria-hidden='true')
| Nevermind, I don't want to delete all of my progress
.spacer
form(action='/account/delete', method='POST')
input(type='hidden', name='_csrf', value=_csrf)
button.btn.btn-danger.btn-block(type='submit')
| I am 100% sure I want to delete my account and all of my progress

View File

@ -4,33 +4,14 @@ block content
script. script.
var challengeName = 'Profile View'; var challengeName = 'Profile View';
if (user && user.username === username) if (user && user.username === username)
h1.text-center Update your code portfolio .row
.row if (!user.isGithubCool)
.col-xs-12 a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
if (!user.isGithubCool) i.fa.fa-github
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github') | Link my GitHub to unlock my portfolio
i.fa.fa-github .col-xs-12
| Link my GitHub to unlock my portfolio a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/settings')
else | Update your settings
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
i.fa.fa-github
| Update my portfolio from GitHub
if (!user.twitter)
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/link/twitter')
i.fa.fa-twitter
| Add my Twitter to my portfolio
if (!user.facebook)
a.btn.btn-lg.btn-block.btn-facebook.btn-link-social(href='/link/facebook')
i.fa.fa-facebook
| Add my Facebook to my portfolio
if (!user.linkedin)
a.btn.btn-lg.btn-block.btn-linkedin.btn-link-social(href='/link/linkedin')
i.fa.fa-linkedin
| Add my LinkedIn to my portfolio
if (!user.google)
a.btn.btn-lg.btn-block.btn-google-plus.btn-link-social(href='/link/google')
i.fa.fa-google-plus
| Add my Google+ to my portfolio
.spacer .spacer
h1.text-center #{username}'s code portfolio h1.text-center #{username}'s code portfolio
hr hr
@ -187,56 +168,4 @@ block content
if (challenge.solution) if (challenge.solution)
a(href='/challenges/' + removeOldTerms(challenge.name) + '?solution=' + encodeURIComponent(encodeFcc(challenge.solution)), target='_blank')= removeOldTerms(challenge.name) a(href='/challenges/' + removeOldTerms(challenge.name) + '?solution=' + encodeURIComponent(encodeFcc(challenge.solution)), target='_blank')= removeOldTerms(challenge.name)
else else
a(href='/challenges/' + removeOldTerms(challenge.name))= removeOldTerms(challenge.name) a(href='/challenges/' + removeOldTerms(challenge.name))= removeOldTerms(challenge.name)
if (user && user.username === username)
h1.text-center Manage your account
hr
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/logout')
| Sign me out of Free Code Camp
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='mailto:team@freecodecamp.com')
| Email us at team@freecodecamp.com
if (!user.isLocked)
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/toggle-lockdown-mode')
| Hide all my solutions from other people
br
| (this will disable your certificates)
else
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/toggle-lockdown-mode')
| Let other people see all my solutions
br
| (this will enable your certificates)
.col-xs-12
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='/commit')
| Edit my pledge
.col-xs-12
a.btn.btn-lg.btn-block.btn-danger.btn-link-social.confirm-deletion
| Delete my Free Code Camp account
script.
$('.confirm-deletion').on("click", function () {
$('#modal-dialog').modal('show');
});
#modal-dialog.modal.animated.wobble
.modal-dialog
.modal-content
.modal-header
a.close(href='#', data-dismiss='modal', aria-hidden='true') ×
h3 You don't really want to delete your account, do you?
.modal-body
p This will really delete all your data, including all your progress, news stories and brownie points.
p We won't be able to recover any of it for you later, even if you change your mind.
p If there's something we could do better, send us an email instead and we'll do our best:  
a(href="mailto:team@freecodecamp.com") team@freecodecamp.com
| .
.modal-footer
a.btn.btn-success.btn-block(href='#', data-dismiss='modal', aria-hidden='true')
| Nevermind, I don't want to delete all of my progress
.spacer
form(action='/account/delete', method='POST')
input(type='hidden', name='_csrf', value=_csrf)
button.btn.btn-danger.btn-block(type='submit')
| I am 100% sure I want to delete my account and all of my progress