Improved my-matches rank history and name fetching, ladder update emails, ladder update unsubscribes.

This commit is contained in:
Nick Winter 2014-03-10 21:30:46 -07:00
parent c393ecd51a
commit 32baf2ae79
4 changed files with 55 additions and 39 deletions
app
templates/play/ladder
views/play/ladder
server/routes

View file

@ -21,9 +21,10 @@ div#columns.row
span.ranked.hidden Submitted for Ranking
span.failed.hidden Failed to Rank
tr
th(colspan=4, style="color: #{team.primaryColor}")
img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score+History&chts=#{team.chartColor},16,c&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}")
if team.chartData
tr
th(colspan=4, style="color: #{team.primaryColor}")
img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score+History&chts=#{team.chartColor},16,c&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}")
tr
th Result

View file

@ -35,7 +35,7 @@ module.exports = class MyMatchesTabView extends CocoView
for session in @sessions.models
for match in session.get('matches') or []
opponent = match.opponents[0]
@nameMap[opponent.userID] = nameMap[opponent.userID]
@nameMap[opponent.userID] ?= nameMap[opponent.userID]
@finishRendering()
$.ajax('/db/user/-/names', {
@ -76,15 +76,16 @@ module.exports = class MyMatchesTabView extends CocoView
team.wins = _.filter(team.matches, {state: 'win'}).length
team.ties = _.filter(team.matches, {state: 'tie'}).length
team.losses = _.filter(team.matches, {state: 'loss'}).length
team.scoreHistory = team.session.get('scoreHistory')
team.chartColor = team.primaryColor.replace '#', ''
times = (s[0] for s in team.scoreHistory)
times = (100 * (t - times[0]) / (times[times.length - 1] - times[0]) for t in times)
scores = (s[1] for s in team.scoreHistory)
lowest = _.min scores
highest = _.max scores
scores = (100 * (s - lowest) / highest for s in scores)
team.chartData = times.join(',') + '|' + scores.join(',')
team.scoreHistory = team.session?.get('scoreHistory')
if team.scoreHistory?.length > 1
team.chartColor = team.primaryColor.replace '#', ''
times = (s[0] for s in team.scoreHistory)
times = ((100 * (t - times[0]) / (times[times.length - 1] - times[0])).toFixed(1) for t in times)
scores = (s[1] for s in team.scoreHistory)
lowest = _.min scores
highest = _.max scores
scores = (Math.round(100 * (s - lowest) / (highest - lowest)) for s in scores)
team.chartData = times.join(',') + '|' + scores.join(',')
ctx

View file

@ -2,6 +2,7 @@ authentication = require('passport')
LocalStrategy = require('passport-local').Strategy
User = require('../users/User')
UserHandler = require('../users/user_handler')
LevelSession = require '../levels/sessions/LevelSession'
config = require '../../server_config'
errors = require '../commons/errors'
mail = require '../commons/mail'
@ -21,16 +22,16 @@ module.exports.setup = (app) ->
if passwordReset and password.toLowerCase() is passwordReset
User.update {_id: user.get('_id')}, {passwordReset: ''}, {}, ->
return done(null, user)
hash = User.hashPassword(password)
unless user.get('passwordHash') is hash
return done(null, false, {message:'is wrong, wrong, wrong', property:'password'})
return done(null, false, {message:'is wrong, wrong, wrong', property:'password'})
return done(null, user)
)
))
app.post '/auth/spy', (req, res, next) ->
if req?.user?.isAdmin()
username = req.body.usernameLower
emailLower = req.body.emailLower
if emailLower
@ -39,19 +40,19 @@ module.exports.setup = (app) ->
query = {"nameLower":username}
else
return errors.badInput res, "You need to supply one of emailLower or username"
User.findOne query, (err, user) ->
if err? then return errors.serverError res, "There was an error finding the specified user"
unless user then return errors.badInput res, "The specified user couldn't be found"
req.logIn user, (err) ->
if err? then return errors.serverError res, "There was an error logging in with the specified"
res.send(UserHandler.formatEntity(req, user))
return res.end()
else
return errors.unauthorized res, "You must be an admin to enter espionage mode"
app.post('/auth/login', (req, res, next) ->
authentication.authenticate('local', (err, user, info) ->
return next(err) if err
@ -87,11 +88,11 @@ module.exports.setup = (app) ->
user.save((err) ->
if err
return @sendDatabaseError(res, err)
req.logIn(user, (err) ->
if err
return @sendDatabaseError(res, err)
if send
return @sendSuccess(res, user)
next() if next
@ -110,7 +111,7 @@ module.exports.setup = (app) ->
User.findOne({emailLower:req.body.email.toLowerCase()}).exec((err, user) ->
if not user
return errors.notFound(res, [{message:'not found.', property:'email'}])
user.set('passwordReset', Math.random().toString(36).slice(2,7).toUpperCase())
user.save (err) =>
return errors.serverError(res) if err
@ -127,12 +128,22 @@ module.exports.setup = (app) ->
return res.end()
)
)
app.get '/auth/unsubscribe', (req, res) ->
email = req.query.email
unless req.query.email
return errors.badInput res, 'No email provided to unsubscribe.'
if req.query.session
# Unsubscribe from just one session's notifications instead.
return LevelSession.findOne({_id: req.query.session}).exec (err, session) ->
return errors.serverError res, 'Could not unsubscribe: #{req.query.session}, #{req.query.email}: #{err}' if err
session.set 'unsubscribed', true
session.save (err) ->
return errors.serverError res, 'Database failure.' if err
res.send "Unsubscribed #{req.query.email} from CodeCombat emails for #{session.levelName} #{session.team} ladder updates. Sorry to see you go! <p><a href='/play/ladder/#{session.levelID}#my-matches'>Ladder preferences</a></p>"
res.end()
User.findOne({emailLower:req.query.email.toLowerCase()}).exec (err, user) ->
if not user
return errors.notFound res, "No user found with email '#{req.query.email}'"
@ -152,4 +163,4 @@ createMailOptions = (receiver, password) ->
replyTo: config.mail.username
subject: "[CodeCombat] Password Reset"
text: "You can log into your account with: #{password}"
#
#

View file

@ -46,7 +46,7 @@ handleLadderUpdate = (req, res) ->
#endTime = startTime + 1.5 * 60 * 60 * 1000 # Debugging: make sure there's something to send
findParameters = {submitted: true, submitDate: {$gt: new Date(startTime), $lte: new Date(endTime)}}
# TODO: think about putting screenshots in the email
selectString = "creator team levelName levelID totalScore matches submitted submitDate numberOfWinsAndTies numberOfLosses"
selectString = "creator team levelName levelID totalScore matches submitted submitDate"
query = LevelSession.find(findParameters)
.select(selectString)
.lean()
@ -63,8 +63,8 @@ sendLadderUpdateEmail = (session, daysAgo) ->
if err
log.error "Couldn't find user for #{session.creator} from session #{session._id}"
return
unless user.email and ('notification' in user.emailSubscriptions)
log.info "Not sending email to #{user.email} #{user.name} because they only want emails about #{user.emailSubscriptions}"
unless user.email and ('notification' in user.emailSubscriptions) and not session.unsubscribed
log.info "Not sending email to #{user.email} #{user.name} because they only want emails about #{user.emailSubscriptions} - session unsubscribed: #{session.unsubscribed}"
return
unless session.levelName
log.info "Not sending email to #{user.email} #{user.name} because the session had no levelName in it."
@ -72,23 +72,32 @@ sendLadderUpdateEmail = (session, daysAgo) ->
name = if user.firstName and user.lastName then "#{user.firstName} #{user.lastName}" else user.name
name = "Wizard" if not name or name is "Anoner"
# Fetch the most recent defeat and victory, if there are any.
# (We could look at strongest/weakest, but we'd have to fetch everyone, or denormalize more.)
matches = _.filter session.matches, (match) -> match.date >= (new Date() - 86400 * 1000 * daysAgo)
defeats = _.filter matches, (match) -> match.metrics.rank is 1 and match.opponents[0].metrics.rank is 0
victories = _.filter matches, (match) -> match.metrics.rank is 0
defeat = _.last defeats
victory = _.last victories
sendEmail = (defeatContext, victoryContext) ->
# TODO: do something with the preferredLanguage?
context =
email_id: sendwithus.templates.ladder_update_email
recipient:
#address: user.email
address: 'nick@codecombat.com' # Debugging
address: user.email
#address: 'nick@codecombat.com' # Debugging
name: name
email_data:
name: name
days_ago: daysAgo
wins: session.numberOfWinsAndTies
losses: session.numberOfLosses
wins: victories.length
losses: defeats.length
total_score: Math.round(session.totalScore * 100)
team: session.team
team_name: session.team[0].toUpperCase() + session.team.substr(1)
level_name: session.levelName
session_id: session._id
ladder_url: "http://codecombat.com/play/ladder/#{session.levelID}#my-matches"
defeat: defeatContext
victory: victoryContext
@ -96,12 +105,6 @@ sendLadderUpdateEmail = (session, daysAgo) ->
sendwithus.api.send context, (err, result) ->
log.error "Error sending ladder update email: #{err} with result #{result}" if err
# Fetch the most recent defeat and victory, if there are any.
# (We could look at strongest/weakest, but we'd have to fetch everyone, or denormalize more.)
defeats = _.filter session.matches, (match) -> match.metrics.rank is 1 and match.opponents[0].metrics.rank is 0
victories = _.filter session.matches, (match) -> match.metrics.rank is 0
defeat = _.last defeats
victory = _.last victories
urlForMatch = (match) ->
"http://codecombat.com/play/level/#{session.levelID}?team=#{session.team}&session=#{session._id}&opponent=#{match.opponents[0].sessionID}"