mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 22:13:32 -04:00
Ripped out Gravatar profiles in favor of our own photo uploads, with Gravatar and Wizard portrait fallbacks.
This commit is contained in:
parent
f17775cc10
commit
dd46f9d039
14 changed files with 110 additions and 212 deletions
app
lib
locale
models
styles/account
templates
views
server/users
|
@ -11,7 +11,6 @@ init = ->
|
|||
me.set 'testGroupNumber', Math.floor(Math.random() * 256)
|
||||
me.save()
|
||||
|
||||
me.loadGravatarProfile() if me.get('email')
|
||||
Backbone.listenTo(me, 'sync', Backbone.Mediator.publish('me:synced', {me:me}))
|
||||
|
||||
module.exports.createUser = (userObject, failure=backboneFailure, nextURL=null) ->
|
||||
|
@ -52,4 +51,3 @@ trackFirstArrival = ->
|
|||
storage.save(BEEN_HERE_BEFORE_KEY, true)
|
||||
|
||||
init()
|
||||
|
||||
|
|
|
@ -142,9 +142,6 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
|
|||
password_tab: "Password"
|
||||
emails_tab: "Emails"
|
||||
admin: "Admin"
|
||||
gravatar_select: "Select which Gravatar photo to use"
|
||||
gravatar_add_photos: "Add thumbnails and photos to a Gravatar account for your email to choose an image."
|
||||
gravatar_add_more_photos: "Add more photos to your Gravatar account to access them here."
|
||||
wizard_color: "Wizard Clothes Color"
|
||||
new_password: "New Password"
|
||||
new_password_verify: "Verify"
|
||||
|
@ -166,17 +163,6 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
|
|||
edit_settings: "Edit Settings"
|
||||
profile_for_prefix: "Profile for "
|
||||
profile_for_suffix: ""
|
||||
profile: "Profile"
|
||||
user_not_found: "No user found. Check the URL?"
|
||||
gravatar_not_found_mine: "We couldn't find your profile associated with:"
|
||||
gravatar_not_found_email_suffix: "."
|
||||
gravatar_signup_prefix: "Sign up at "
|
||||
gravatar_signup_suffix: " to get set up!"
|
||||
gravatar_not_found_other: "Alas, there's no profile associated with this person's email address."
|
||||
gravatar_contact: "Contact"
|
||||
gravatar_websites: "Websites"
|
||||
gravatar_accounts: "As Seen On"
|
||||
gravatar_profile_link: "Full Gravatar Profile"
|
||||
|
||||
play_level:
|
||||
level_load_error: "Level could not be loaded: "
|
||||
|
@ -628,3 +614,4 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
|
|||
gplus_friend_sessions: "G+ Friend Sessions"
|
||||
leaderboard: "Leaderboard"
|
||||
user_schema: "User Schema"
|
||||
user_profile: "User Profile"
|
||||
|
|
|
@ -8,53 +8,23 @@ module.exports = class User extends CocoModel
|
|||
|
||||
initialize: ->
|
||||
super()
|
||||
@on 'change:emailHash', ->
|
||||
@gravatarProfile = null
|
||||
@loadGravatarProfile()
|
||||
|
||||
isAdmin: ->
|
||||
permissions = @attributes['permissions'] or []
|
||||
return 'admin' in permissions
|
||||
|
||||
gravatarAvatarURL: ->
|
||||
avatar_url = GRAVATAR_URL + 'avatar/'
|
||||
return avatar_url if not @emailHash
|
||||
return avatar_url + @emailHash
|
||||
|
||||
loadGravatarProfile: ->
|
||||
emailHash = @get('emailHash')
|
||||
return if not emailHash
|
||||
functionName = 'gotProfile'+emailHash
|
||||
profileUrl = "#{GRAVATAR_URL}#{emailHash}.json?callback=#{functionName}"
|
||||
script = $("<script src='#{profileUrl}' type='text/javascript'></script>")
|
||||
$('head').append(script)
|
||||
window[functionName] = (profile) =>
|
||||
@gravatarProfile = profile
|
||||
@trigger('change', @)
|
||||
|
||||
func = => @gravatarProfile = null unless @gravatarProfile
|
||||
setTimeout(func, 1000)
|
||||
|
||||
displayName: ->
|
||||
@get('name') or @gravatarName() or "Anoner"
|
||||
@get('name') or "Anoner"
|
||||
|
||||
lang: ->
|
||||
@get('preferredLanguage') or "en-US"
|
||||
|
||||
gravatarName: ->
|
||||
@gravatarProfile?.entry[0]?.name?.formatted or ''
|
||||
|
||||
gravatarPhotoURLs: ->
|
||||
photos = @gravatarProfile?.entry[0]?.photos
|
||||
return if not photos
|
||||
(photo.value for photo in photos)
|
||||
|
||||
getPhotoURL: ->
|
||||
photoURL = @get('photoURL')
|
||||
validURLs = @gravatarPhotoURLs()
|
||||
return @gravatarAvatarURL() unless validURLs and validURLs.length
|
||||
return validURLs[0] unless photoURL in validURLs
|
||||
return photoURL
|
||||
getPhotoURL: (size=80) ->
|
||||
if photoURL = @get('photoURL')
|
||||
prefix = if photoURL.search(/\?/) is -1 then "?" else "&"
|
||||
return "#{photoURL}#{prefix}s=#{size}" if photoURL.search('http') isnt -1 # legacy
|
||||
return "/file/#{photoURL}#{prefix}s=#{size}"
|
||||
return "/db/user/#{@id}/avatar?s=#{size}"
|
||||
|
||||
@getByID = (id, properties, force) ->
|
||||
{me} = require('lib/auth')
|
||||
|
@ -66,7 +36,8 @@ module.exports = class User extends CocoModel
|
|||
success: ->
|
||||
user.loading = false
|
||||
Backbone.Mediator.publish('user:fetched')
|
||||
user.loadGravatarProfile()
|
||||
console.log 'triggering sync'
|
||||
user.trigger 'sync'
|
||||
)
|
||||
cache[id] = user
|
||||
user
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
margin: 2px
|
||||
i
|
||||
margin-right: 5px
|
||||
|
||||
|
||||
img.img-thumbnail
|
||||
margin: 5px 20px 20px 20px
|
||||
|
||||
.approved, .not-approved
|
||||
display: none
|
||||
|
@ -27,6 +23,13 @@
|
|||
border-radius: 0
|
||||
padding: 10px
|
||||
|
||||
.public-profile-container
|
||||
padding: 20px
|
||||
|
||||
img.profile-photo
|
||||
width: 256px
|
||||
border-radius: 6px
|
||||
|
||||
.job-profile-container
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
@ -112,6 +115,7 @@
|
|||
margin-top: 10px
|
||||
img
|
||||
max-width: 524px - 60px
|
||||
max-height: 200px
|
||||
|
||||
.header-icon
|
||||
margin-right: 10px
|
||||
|
|
|
@ -11,12 +11,8 @@
|
|||
#save-button
|
||||
float: right
|
||||
|
||||
.thumbnails
|
||||
text-align: center
|
||||
.thumbnail
|
||||
margin-bottom: 30px
|
||||
margin-right: 20px
|
||||
float: left
|
||||
.gravatar-fallback
|
||||
margin-top: 10px
|
||||
|
||||
input.range
|
||||
position: relative
|
||||
|
|
|
@ -21,7 +21,7 @@ block content
|
|||
.job-profile-row
|
||||
.left-column.full-height-column
|
||||
.profile-photo-container
|
||||
img.profile-photo(src=photoURL)
|
||||
img.profile-photo(src=user.getPhotoURL(240))
|
||||
.profile-caption= profile.jobTitle || 'Software Developer'
|
||||
|
||||
if profileLinks.length
|
||||
|
@ -89,65 +89,13 @@ block content
|
|||
a(href=project.link).btn.btn-large.btn-inverse.flat-button Check it out
|
||||
|
||||
else
|
||||
h2
|
||||
if grav && grav.name && grav.name.formatted
|
||||
.public-profile-container
|
||||
h2
|
||||
span(data-i18n="account_profile.profile_for_prefix") Profile for
|
||||
span= grav.name.formatted
|
||||
span= user.get('name')
|
||||
span(data-i18n="account_profile.profile_for_suffix")
|
||||
else
|
||||
span(data-i18n="account_profile.profile") Profile
|
||||
|
||||
if loadingProfile
|
||||
p(data-i18n="common.loading") Loading...
|
||||
|
||||
else if !user.get('emailHash')
|
||||
p(data-i18n="account_profile.user_not_found") No user found. Check the URL?
|
||||
|
||||
else if !user.gravatarProfile
|
||||
if myProfile
|
||||
p
|
||||
span(data-i18n="account_profile.gravatar_not_found_mine") We couldn't find your profile associated with:
|
||||
strong "#{me.get('email')}"
|
||||
span(data-i18n="account_profile.gravatar_not_found_email_suffix") .
|
||||
span
|
||||
span(data-i18n="account_profile.gravatar_signup_prefix") Sign up at
|
||||
a(href="http://en.gravatar.com/") Gravatar
|
||||
span(data-i18n="account_profile.gravatar_signup_suffix") to get set up!
|
||||
else
|
||||
p(data-i18n="account_profile.gravatar_not_found_other")
|
||||
| Alas, there's no profile associated with this person's email address.
|
||||
|
||||
else
|
||||
.container
|
||||
div.row
|
||||
div.col-xs-3
|
||||
img(src=photoURL).img-thumbnail
|
||||
|
||||
p.about-me #{grav.aboutMe}
|
||||
|
||||
if grav.emails
|
||||
div.col-xs-3
|
||||
h3(data-i18n="account_profile.gravatar_contact") Contact
|
||||
ul
|
||||
each email in grav.emails
|
||||
li #{email.value}
|
||||
|
||||
if grav.urls && grav.urls.length
|
||||
div.col-xs-3
|
||||
h3(data-i18n="account_profile.gravatar_websites") Websites
|
||||
ul
|
||||
each url in grav.urls
|
||||
li
|
||||
a(href="#{url.value}") #{url.title}
|
||||
|
||||
if grav.accounts
|
||||
div.col-xs-3
|
||||
h3(data-i18n="account_profile.gravatar_accounts") As Seen On
|
||||
ul
|
||||
each account in grav.accounts
|
||||
li
|
||||
a(href="#{account.url}") #{account.domain}
|
||||
|
||||
hr
|
||||
p
|
||||
a(href="#{grav.profileUrl}", data-i18n="account_profile.gravatar_profile_link") Full Gravatar Profile
|
||||
img.profile-photo(src=user.getPhotoURL(256))
|
||||
|
||||
h2 TODO
|
||||
p Public user profiles are not ready yet.
|
|
@ -31,7 +31,7 @@ block content
|
|||
.form
|
||||
.form-group
|
||||
label.control-label(for="name", data-i18n="general.name") Name
|
||||
input#name.form-control(name="name", type="text", value="#{me.get('name')||''}", placeholder="#{gravatarName}")
|
||||
input#name.form-control(name="name", type="text", value="#{me.get('name') || ''}")
|
||||
.form-group
|
||||
label.control-label(for="email", data-i18n="general.email") Email
|
||||
input#email.form-control(name="email", type="text", value="#{me.get('email')}")
|
||||
|
@ -42,23 +42,11 @@ block content
|
|||
|
||||
|
||||
#picture-pane.tab-pane
|
||||
h3(data-i18n="account_settings.gravatar_select") Select which Gravatar photo to use
|
||||
p
|
||||
if !photos
|
||||
span(data-i18n="account_settings.gravatar_add_photos") Add thumbnails and photos to a Gravatar account for your email to choose an image.
|
||||
|
||||
else
|
||||
.thumbnails
|
||||
each photo, i in photos
|
||||
.thumbnail
|
||||
label(for="photo-#{i}")
|
||||
img(src=photo)
|
||||
br
|
||||
input(type="radio", name="photoURL", value="#{photo}", id="photo-#{i}", checked=photo==chosenPhoto)
|
||||
.clearfix
|
||||
p
|
||||
a(href="http://en.gravatar.com/profiles/edit/?noclose#your-images", target="_blank", data-i18n="account_settings.gravatar_add_more_photos") Add more photos to your Gravatar account to access them here.
|
||||
|
||||
h3(data-i18n="account_settings.upload_picture") Upload a picture
|
||||
#picture-treema
|
||||
.gravatar-fallback
|
||||
img(src=me.getPhotoURL(256), alt="Gravatar", title="Gravatar fallback image")
|
||||
|
||||
#wizard-pane.tab-pane
|
||||
#wizard-settings-view
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ body
|
|||
|
||||
if me.get('anonymous') === false
|
||||
button.btn.btn-primary.navbuttontext.header-font#logout-button(data-i18n="login.log_out") Log Out
|
||||
a.btn.btn-primary.navbuttontext.header-font(href="/account/profile/#{me.id}")
|
||||
a.btn.btn-primary.navbuttontext.header-font(href=me.get('jobProfile') ? "/account/profile/#{me.id}" : "/account/settings")
|
||||
div.navbuttontext-user-name
|
||||
| #{me.displayName()}
|
||||
i.icon-cog.icon-white.big
|
||||
|
|
|
@ -54,11 +54,10 @@ block content
|
|||
tr(data-candidate-id=candidate.id)
|
||||
td
|
||||
if authorized
|
||||
// Want image, but it doesn't work without loading every Gravatar profile
|
||||
//img(src=candidate.getPhotoURL(), alt=profile.name, title=profile.name, width=50)
|
||||
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, width=50)
|
||||
p= profile.name
|
||||
else
|
||||
//img(src="/images/pages/contribute/archmage.png", alt="", title="Sign up as an employer to see our candidates", width=50)
|
||||
img(src="/images/pages/contribute/archmage.png", alt="", title="Sign up as an employer to see our candidates", width=50)
|
||||
p Developer ##{index + 1}
|
||||
if profile.country == 'USA'
|
||||
td= profile.city
|
||||
|
|
|
@ -5,7 +5,6 @@ User = require 'models/User'
|
|||
module.exports = class ProfileView extends View
|
||||
id: "profile-view"
|
||||
template: template
|
||||
loadingProfile: true
|
||||
|
||||
events:
|
||||
'click #toggle-job-profile-approved': 'toggleJobProfileApproved'
|
||||
|
@ -14,30 +13,16 @@ module.exports = class ProfileView extends View
|
|||
constructor: (options, @userID) ->
|
||||
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
|
||||
super options
|
||||
@user = User.getByID(@userID)
|
||||
@loadingProfile = false if 'gravatarProfile' of @user
|
||||
@listenTo(@user, 'change', @userChanged)
|
||||
@listenTo(@user, 'error', @userError)
|
||||
|
||||
userChanged: (user) ->
|
||||
@loadingProfile = false if 'gravatarProfile' of user
|
||||
@render()
|
||||
|
||||
userError: (user) ->
|
||||
@loadingProfile = false
|
||||
@render()
|
||||
if @userID is me.id
|
||||
@user = me
|
||||
else
|
||||
@user = User.getByID(@userID)
|
||||
@addResourceToLoad @user, 'user_profile'
|
||||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
grav = @user.gravatarProfile
|
||||
grav = grav.entry[0] if grav
|
||||
addedContext =
|
||||
user: @user
|
||||
loadingProfile: @loadingProfile
|
||||
myProfile: @user.id is context.me.id
|
||||
grav: grav
|
||||
photoURL: @user.getPhotoURL()
|
||||
context[key] = addedContext[key] for key of addedContext
|
||||
context.user = @user
|
||||
context.myProfile = @user.id is context.me.id
|
||||
context.marked = marked
|
||||
context.moment = moment
|
||||
context.iconForLink = @iconForLink
|
||||
|
|
|
@ -20,18 +20,7 @@ module.exports = class SettingsView extends View
|
|||
@save = _.debounce(@save, 200)
|
||||
super options
|
||||
return unless me
|
||||
@listenTo(me, 'change', @refreshPicturePane) # depends on gravatar load
|
||||
@listenTo(me, 'invalid', (errors) -> forms.applyErrorsToForm(@$el, me.validationError))
|
||||
window.f = @getSubscriptions
|
||||
|
||||
refreshPicturePane: ->
|
||||
h = $(@template(@getRenderData()))
|
||||
newPane = $('#picture-pane', h)
|
||||
oldPane = $('#picture-pane')
|
||||
active = oldPane.hasClass('active')
|
||||
oldPane.replaceWith(newPane)
|
||||
newPane.i18n()
|
||||
newPane.addClass('active') if active
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -55,6 +44,11 @@ module.exports = class SettingsView extends View
|
|||
@listenTo @jobProfileView, 'change', @save
|
||||
@insertSubView @jobProfileView
|
||||
|
||||
if me.schema().loaded
|
||||
@buildPictureTreema()
|
||||
else
|
||||
@listenToOnce me, 'schema-loaded', @buildPictureTreema
|
||||
|
||||
chooseTab: (category) ->
|
||||
id = "##{category}-pane"
|
||||
pane = $(id, @$el)
|
||||
|
@ -68,9 +62,6 @@ module.exports = class SettingsView extends View
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
return c unless me
|
||||
c.gravatarName = c.me?.gravatarName()
|
||||
c.photos = me.gravatarPhotoURLs()
|
||||
c.chosenPhoto = me.getPhotoURL()
|
||||
c.subs = {}
|
||||
c.subs[sub] = 1 for sub in c.me.get('emailSubscriptions') or ['announcement', 'notification', 'tester', 'level_creator', 'developer']
|
||||
c.showsJobProfileTab = me.isAdmin() or me.get('jobProfile') or location.hash.search('job-profile-') isnt -1
|
||||
|
@ -88,6 +79,30 @@ module.exports = class SettingsView extends View
|
|||
$('#email-pane input[type="checkbox"]', @$el).prop('checked', not Boolean(subs.length))
|
||||
@save()
|
||||
|
||||
buildPictureTreema: ->
|
||||
data = photoURL: me.get('photoURL')
|
||||
if data.photoURL?.search('gravatar') isnt -1
|
||||
# Old style
|
||||
data.photoURL = null
|
||||
schema = _.cloneDeep me.schema().attributes
|
||||
schema.properties = _.pick me.schema().get('properties'), 'photoURL'
|
||||
schema.required = ['photoURL']
|
||||
console.log 'schema is', schema
|
||||
treemaOptions =
|
||||
filePath: "db/user/#{me.id}"
|
||||
schema: schema
|
||||
data: data
|
||||
callbacks: {change: @onPictureChanged}
|
||||
|
||||
@pictureTreema = @$el.find('#picture-treema').treema treemaOptions
|
||||
@pictureTreema.build()
|
||||
@pictureTreema.open()
|
||||
@$el.find('.gravatar-fallback').toggle not me.get 'photoURL'
|
||||
|
||||
onPictureChanged: (e) =>
|
||||
@trigger 'change'
|
||||
@$el.find('.gravatar-fallback').toggle not me.get 'photoURL'
|
||||
|
||||
save: ->
|
||||
forms.clearFormAlerts(@$el)
|
||||
@grabData()
|
||||
|
@ -127,9 +142,10 @@ module.exports = class SettingsView extends View
|
|||
me.set('password', password1)
|
||||
|
||||
grabOtherData: ->
|
||||
me.set('name', $('#name', @$el).val())
|
||||
me.set('email', $('#email', @$el).val())
|
||||
me.set('emailSubscriptions', @getSubscriptions())
|
||||
me.set 'name', $('#name', @$el).val()
|
||||
me.set 'email', $('#email', @$el).val()
|
||||
me.set 'emailSubscriptions', @getSubscriptions()
|
||||
me.set 'photoURL', @pictureTreema.get('/photoURL')
|
||||
|
||||
adminCheckbox = @$el.find('#admin')
|
||||
if adminCheckbox.length
|
||||
|
|
|
@ -104,15 +104,15 @@ module.exports = class CocoView extends Backbone.View
|
|||
context
|
||||
|
||||
afterRender: ->
|
||||
|
||||
|
||||
# Resource and request loading management for any given view
|
||||
|
||||
|
||||
addResourceToLoad: (modelOrCollection, name, value=1) ->
|
||||
@loadProgress.resources.push {resource:modelOrCollection, value:value, name:name}
|
||||
@listenToOnce modelOrCollection, 'sync', @updateProgress
|
||||
@listenTo modelOrCollection, 'error', @onResourceLoadFailed
|
||||
@updateProgress()
|
||||
|
||||
|
||||
addRequestToLoad: (jqxhr, name, retryFunc, value=1) ->
|
||||
@loadProgress.requests.push {request:jqxhr, value:value, name: name, retryFunc: retryFunc}
|
||||
jqxhr.done @updateProgress
|
||||
|
@ -152,7 +152,7 @@ module.exports = class CocoView extends Backbone.View
|
|||
num += r.value for r in @loadProgress.requests when r.request.status
|
||||
num += r.value for r in @loadProgress.somethings when r.loaded
|
||||
#console.log 'update progress', @, num, denom, arguments
|
||||
|
||||
|
||||
progress = if denom then num / denom else 0
|
||||
# sometimes the denominator isn't known from the outset, so make sure the overall progress only goes up
|
||||
@loadProgress.progress = progress if progress > @loadProgress.progress
|
||||
|
@ -160,7 +160,7 @@ module.exports = class CocoView extends Backbone.View
|
|||
if num is denom and not @loaded
|
||||
@loaded = true
|
||||
@onLoaded()
|
||||
|
||||
|
||||
updateProgressBar: =>
|
||||
prog = "#{parseInt(@loadProgress.progress*100)}%"
|
||||
@$el.find('.loading-screen .progress-bar').css('width', prog)
|
||||
|
@ -169,7 +169,7 @@ module.exports = class CocoView extends Backbone.View
|
|||
@render()
|
||||
|
||||
# Error handling for loading
|
||||
|
||||
|
||||
onResourceLoadFailed: (resource, jqxhr) ->
|
||||
for r, index in @loadProgress.resources
|
||||
break if r.resource is resource
|
||||
|
@ -179,12 +179,12 @@ module.exports = class CocoView extends Backbone.View
|
|||
resourceIndex: index,
|
||||
responseText: jqxhr.responseText
|
||||
})).i18n()
|
||||
|
||||
|
||||
onRetryResource: (e) ->
|
||||
r = @loadProgress.resources[$(e.target).data('resource-index')]
|
||||
r.resource.fetch()
|
||||
$(e.target).closest('.loading-error-alert').remove()
|
||||
|
||||
|
||||
onRequestLoadFailed: (jqxhr) =>
|
||||
for r, index in @loadProgress.requests
|
||||
break if r.request is jqxhr
|
||||
|
@ -194,7 +194,7 @@ module.exports = class CocoView extends Backbone.View
|
|||
requestIndex: index,
|
||||
responseText: jqxhr.responseText
|
||||
}))
|
||||
|
||||
|
||||
onRetryRequest: (e) ->
|
||||
r = @loadProgress.requests[$(e.target).data('request-index')]
|
||||
@[r.retryFunc]?()
|
||||
|
|
|
@ -9,6 +9,7 @@ errors = require '../commons/errors'
|
|||
async = require 'async'
|
||||
log = require 'winston'
|
||||
LevelSession = require('../levels/sessions/LevelSession')
|
||||
LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
||||
|
||||
serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset']
|
||||
privateProperties = [
|
||||
|
@ -48,18 +49,8 @@ UserHandler = class UserHandler extends Handler
|
|||
delete obj[prop] for prop in privateProperties unless includePrivates
|
||||
includeCandidate = includePrivates or (obj.jobProfileApproved and req.user and ('employer' in (req.user.permissions ? [])))
|
||||
delete obj[prop] for prop in candidateProperties unless includeCandidate
|
||||
obj.emailHash = @buildEmailHash document
|
||||
return obj
|
||||
|
||||
buildEmailHash: (user) ->
|
||||
# emailHash is used by gravatar
|
||||
hash = crypto.createHash('md5')
|
||||
if user.get('email')
|
||||
hash.update(_.trim(user.get('email')).toLowerCase())
|
||||
else
|
||||
hash.update(user.get('_id') + '')
|
||||
hash.digest('hex')
|
||||
|
||||
waterfallFunctions: [
|
||||
# FB access token checking
|
||||
# Check the email is the same as FB reports
|
||||
|
@ -126,7 +117,7 @@ UserHandler = class UserHandler extends Handler
|
|||
|
||||
getById: (req, res, id) ->
|
||||
if req.user?._id.equals(id)
|
||||
return @sendSuccess(res, @formatEntity(req, req.user))
|
||||
return @sendSuccess(res, @formatEntity(req, req.user, 256))
|
||||
super(req, res, id)
|
||||
|
||||
getNamesByIds: (req, res) ->
|
||||
|
@ -203,9 +194,11 @@ UserHandler = class UserHandler extends Handler
|
|||
@sendSuccess(res, {result:'success'})
|
||||
|
||||
avatar: (req, res, id) ->
|
||||
@modelClass.findById(id).exec (err, document) ->
|
||||
@modelClass.findById(id).exec (err, document) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
res.redirect(document?.get('photoURL') or '/images/generic-wizard-icon.png')
|
||||
photoURL = document?.get('photoURL')
|
||||
photoURL ||= @buildGravatarURL document
|
||||
res.redirect photoURL
|
||||
res.end()
|
||||
|
||||
getLevelSessions: (req, res, userID) ->
|
||||
|
@ -217,7 +210,7 @@ UserHandler = class UserHandler extends Handler
|
|||
projection[field] = 1 for field in req.query.project.split(',')
|
||||
LevelSession.find(query).select(projection).exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (@formatEntity(req, doc) for doc in documents)
|
||||
documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
|
||||
getCandidates: (req, res) ->
|
||||
|
@ -235,13 +228,27 @@ UserHandler = class UserHandler extends Handler
|
|||
@sendSuccess(res, candidates)
|
||||
|
||||
formatCandidate: (authorized, document) ->
|
||||
fields = if authorized then ['jobProfile', 'jobProfileApproved', '_id'] else ['jobProfile']
|
||||
fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile']
|
||||
obj = _.pick document.toObject(), fields
|
||||
obj.emailHash = @buildEmailHash document
|
||||
obj.photoURL ||= @buildGravatarURL document if authorized
|
||||
subfields = ['country', 'city', 'lookingFor', 'skills', 'experience', 'updated']
|
||||
if authorized
|
||||
subfields = subfields.concat ['name', 'work']
|
||||
obj.jobProfile = _.pick obj.jobProfile, subfields
|
||||
obj
|
||||
|
||||
buildGravatarURL: (user) ->
|
||||
emailHash = @buildEmailHash user
|
||||
defaultAvatar = "http://codecombat.com/file/db/thang.type/52a00d55cf1818f2be00000b/portrait.png"
|
||||
"https://www.gravatar.com/avatar/#{emailHash}?default=#{defaultAvatar}"
|
||||
|
||||
buildEmailHash: (user) ->
|
||||
# emailHash is used by gravatar
|
||||
hash = crypto.createHash('md5')
|
||||
if user.get('email')
|
||||
hash.update(_.trim(user.get('email')).toLowerCase())
|
||||
else
|
||||
hash.update(user.get('_id') + '')
|
||||
hash.digest('hex')
|
||||
|
||||
module.exports = new UserHandler()
|
||||
|
|
|
@ -9,7 +9,7 @@ UserSchema = c.object {},
|
|||
gender: {type: 'string', 'enum': ['male', 'female']}
|
||||
password: {type: 'string', maxLength: 256, minLength: 2, title:'Password'}
|
||||
passwordReset: {type: 'string'}
|
||||
photoURL: {type: 'string', format: 'url', required: false}
|
||||
photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image to serve as your profile picture.'}
|
||||
|
||||
facebookID: c.shortString({title: 'Facebook ID'})
|
||||
gplusID: c.shortString({title: 'G+ ID'})
|
||||
|
@ -36,7 +36,6 @@ UserSchema = c.object {},
|
|||
passwordHash: {type: 'string', maxLength: 256}
|
||||
|
||||
# client side
|
||||
#gravatarProfile: {} (should only ever be kept locally)
|
||||
emailHash: {type: 'string'}
|
||||
|
||||
#Internationalization stuff
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue