Merge pull request #2359 from laituan245/master

Added ability to delete account
This commit is contained in:
Nick Winter 2015-02-24 09:30:22 -08:00
commit 4cbbcdad6d
7 changed files with 97 additions and 5 deletions

View file

@ -50,7 +50,12 @@ module.exports.loginUser = (userObject, failure=genericFailure, nextURL=null) ->
module.exports.logoutUser = ->
FB?.logout?()
res = $.post('/auth/logout', {}, -> window.location.reload())
callback = ->
if (window.location.href.indexOf("/account/settings") > -1)
window.location = '/'
else
window.location.reload()
res = $.post('/auth/logout', {}, callback)
res.fail(genericFailure)
onSetVolume = (e) ->

View file

@ -604,13 +604,17 @@
autosave: "Changes Save Automatically"
me_tab: "Me"
picture_tab: "Picture"
delete_account_tab: "Delete Your Account"
wrong_email: "Wrong Email"
upload_picture: "Upload a picture"
delete_this_account: "Delete this account permanently"
god_mode: "God Mode"
password_tab: "Password"
emails_tab: "Emails"
admin: "Admin"
new_password: "New Password"
new_password_verify: "Verify"
type_in_email: "Type in your email to confirm the deletion"
email_subscriptions: "Email Subscriptions"
email_subscriptions_none: "No Email Subscriptions."
email_announcements: "Announcements"

View file

@ -276,6 +276,7 @@ _.extend UserSchema.properties,
earned: c.RewardSchema 'earned by achievements'
purchased: c.RewardSchema 'purchased with gems or money'
deleted: {type: 'boolean'}
spent: {type: 'number'}
stripeCustomerID: { type: 'string' } # TODO: Migrate away from this property

View file

@ -34,6 +34,9 @@
.panel-title
font-size: 20px
#delete-account-panel-title
color: #F00
//- Panel specific stuff
.profile-photo

View file

@ -48,6 +48,16 @@ else
label.control-label(for="password2", data-i18n="account_settings.new_password_verify") Verify
input#password2.form-control(name="password2", type="password")
.panel.panel-default
.panel-heading
.panel-title#delete-account-panel-title(data-i18n="account_settings.delete_account_tab")
.panel-body
.form
.form-group
label.control-label(for="email1", data-i18n="account_settings.type_in_email") Type in your email to confirm the deletion
input#email1.form-control(name="email1", type="text")
button#delete-account-button.btn.form-control.btn-primary(data-i18n="account_settings.delete_this_account")
.col-md-6
#email-panel.panel.panel-default

View file

@ -4,6 +4,8 @@ template = require 'templates/account/account-settings-view'
forms = require 'core/forms'
User = require 'models/User'
AuthModal = require 'views/core/AuthModal'
ConfirmModal = require 'views/editor/modal/ConfirmModal'
{logoutUser, me} = require('core/auth')
module.exports = class AccountSettingsView extends CocoView
id: 'account-settings-view'
@ -16,6 +18,7 @@ module.exports = class AccountSettingsView extends CocoView
'click #toggle-all-button': 'toggleEmailSubscriptions'
'click .profile-photo': 'onEditProfilePhoto'
'click #upload-photo-button': 'onEditProfilePhoto'
'click #delete-account-button': 'confirmAccountDeletion'
constructor: (options) ->
super options
@ -35,10 +38,12 @@ module.exports = class AccountSettingsView extends CocoView
#- Form input callbacks
onInputChanged: (e) ->
$(e.target).addClass 'changed'
@trigger 'input-changed'
if (JSON.stringify(document.getElementById('email1').className)).indexOf("changed") > -1
$(e.target).removeClass 'changed'
else
@trigger 'input-changed'
toggleEmailSubscriptions: =>
subs = @getSubscriptions()
@ -62,7 +67,49 @@ module.exports = class AccountSettingsView extends CocoView
#- Just copied from OptionsView, TODO refactor
confirmAccountDeletion: ->
forms.clearFormAlerts(@$el)
myEmail = me.get 'email'
email1 = document.getElementById('email1').value
if Boolean(email1) and email1 is myEmail
renderData =
'confirmTitle': 'Are you really sure?'
'confirmBody': 'This will completely delete your account. This action CANNOT be undone. Are you entirely sure?'
'confirmDecline': 'Not really'
'confirmConfirm': 'Definitely'
confirmModal = new ConfirmModal renderData
confirmModal.on 'confirm', @deleteAccount
@openModalView confirmModal
else
message = $.i18n.t('account_settings.wrong_email', defaultValue: 'Wrong Email.')
err = [message: message, property: 'email1', formatted: true]
forms.applyErrorsToForm(@$el, err)
$('.nano').nanoScroller({scrollTo: @$el.find('.has-error')})
deleteAccount: ->
myID = me.id
$.ajax
type: 'DELETE'
success: ->
noty
timeout: 5000
text: 'Your account is gone.'
type: 'success'
layout: 'topCenter'
_.delay ->
Backbone.Mediator.publish("auth:logging-out", {})
window.tracker?.trackEvent 'Log Out', category:'Homepage', ['Google Analytics'] if @id is 'home-view'
logoutUser($('#login-email').val())
, 500
error: (jqXHR, status, error) ->
console.error jqXHR
timeout: 5000
text: "Deleting account failed with error code #{jqXHR.status}"
type: 'error'
layout: 'topCenter'
url: "/db/user/#{myID}"
onEditProfilePhoto: (e) ->
return if window.application.isIPadApp # TODO: have an iPad-native way of uploading a photo, since we don't want to load FilePicker on iPad (memory)
photoContainer = @$el.find('.profile-photo')

View file

@ -28,6 +28,8 @@ candidateProperties = [
UserHandler = class UserHandler extends Handler
modelClass: User
allowedMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
getEditableProperties: (req, document) ->
props = super req, document
props.push 'permissions' unless config.isProduction
@ -211,11 +213,31 @@ UserHandler = class UserHandler extends Handler
@put(req, res)
hasAccessToDocument: (req, document) ->
if req.route.method in ['put', 'post', 'patch']
if req.route.method in ['put', 'post', 'patch', 'delete']
return true if req.user?.isAdmin()
return req.user?._id.equals(document._id)
return true
delete: (req, res, userID) ->
# Instead of just deleting the User object, we should remove all the properties except for _id
# And add a `deleted: true` property
@getDocumentForIdOrSlug userID, (err, user) => # Check first
return @sendDatabaseError res, err if err
return @sendNotFoundError res unless user
return @sendForbiddenError res unless @hasAccessToDocument(req, user)
obj = user.toObject()
for prop, val of obj
user.set(prop, undefined) unless prop is '_id'
user.set('deleted', true)
# Hack to get saving of Users to work. Probably should replace these props with strings
# so that validation doesn't get hung up on Date objects in the documents.
delete obj.dateCreated
user.save (err) =>
return @sendDatabaseError(res, err) if err
@sendNoContent res
getByRelationship: (req, res, args...) ->
return @agreeToCLA(req, res) if args[1] is 'agreeToCLA'
return @agreeToEmployerAgreement(req, res) if args[1] is 'agreeToEmployerAgreement'