diff --git a/client/less/main.less b/client/less/main.less index 8ae2225ba5..9170725425 100644 --- a/client/less/main.less +++ b/client/less/main.less @@ -170,6 +170,10 @@ ul { margin-top: 15px; } +.positive-20 { + margin-top: 20px; +} + .positive-15-bottom { margin-bottom: 15px; } diff --git a/common/models/user.json b/common/models/user.json index 4aa16172f0..f696b49102 100644 --- a/common/models/user.json +++ b/common/models/user.json @@ -110,6 +110,14 @@ "type": "boolean", "default": true }, + "sendNotificationEmail": { + "type": "boolean", + "default": true + }, + "sendQuincyEmail": { + "type": "boolean", + "default": true + }, "isLocked": { "type": "boolean", "default": false, diff --git a/server/boot/user.js b/server/boot/user.js index 8af387b323..6a8308052f 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -153,6 +153,21 @@ module.exports = function(app) { sendNonUserToMap, 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( '/account/delete', ifNoUser401, @@ -163,6 +178,11 @@ module.exports = function(app) { sendNonUserToMap, getAccount ); + router.get( + '/settings', + sendNonUserToMap, + getSettings + ); router.get('/vote1', vote1); router.get('/vote2', vote2); @@ -228,6 +248,10 @@ module.exports = function(app) { return res.redirect('/' + username); } + function getSettings(req, res, next) { + res.render('account/settings'); + } + function returnUser(req, res, next) { const username = req.params.username.toLowerCase(); const { user, path } = req; @@ -406,7 +430,7 @@ module.exports = function(app) { section at the bottom of this page. ` }); - return res.redirect('/' + req.user.username); + res.redirect('/settings'); }); } req.user.isLocked = true; @@ -420,7 +444,40 @@ module.exports = function(app) { section at the bottom of this page. ` }); - return res.redirect('/' + req.user.username); + res.redirect('/settings'); + }); + } + + function toggleReceivesAnnouncementEmails(req, res, next) { + return User.findById(req.accessToken.userId, function(err, user) { + if (err) { return next(err); } + user.updateAttribute('sendMonthlyEmail', typeof user.sendMonthlyEmail !== "undefined" ? !user.sendMonthlyEmail : true, function(err) { + if (err) { return next(err); } + req.flash('info', { msg: 'Email preferences updated successfully.' }); + res.redirect('/settings'); + }); + }); + } + + function toggleReceivesQuincyEmails(req, res, next) { + return User.findById(req.accessToken.userId, function(err, user) { + if (err) { return next(err); } + user.updateAttribute('sendQuincyEmail', typeof user.sendQuincyEmail !== "undefined" ? !user.sendQuincyEmail : true, function(err) { + if (err) { return next(err); } + req.flash('info', { msg: 'Email preferences updated successfully.' }); + res.redirect('/settings'); + }); + }); + } + + function toggleReceivesNotificationEmails(req, res, next) { + return User.findById(req.accessToken.userId, function(err, user) { + if (err) { return next(err); } + user.updateAttribute('sendNotificationEmail', typeof user.sendNotificationEmail !== "undefined" ? !user.sendNotificationEmail : true, function(err) { + if (err) { return next(err); } + req.flash('info', { msg: 'Email preferences updated successfully.' }); + res.redirect('/settings'); + }); }); } diff --git a/server/views/account/settings.jade b/server/views/account/settings.jade new file mode 100644 index 0000000000..1b810118d3 --- /dev/null +++ b/server/views/account/settings.jade @@ -0,0 +1,104 @@ +extends ../layout +block content + h1.text-center Settings for your Account + hr + h2.text-center Actions + .row + .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 \ No newline at end of file diff --git a/server/views/account/show.jade b/server/views/account/show.jade index 8d3e4bc576..c7c3050ffb 100644 --- a/server/views/account/show.jade +++ b/server/views/account/show.jade @@ -187,56 +187,4 @@ block content if (challenge.solution) a(href='/challenges/' + removeOldTerms(challenge.name) + '?solution=' + encodeURIComponent(encodeFcc(challenge.solution)), target='_blank')= removeOldTerms(challenge.name) else - 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 + a(href='/challenges/' + removeOldTerms(challenge.name))= removeOldTerms(challenge.name) \ No newline at end of file