Made espionage mode simpler, and added an admin user lookup.

This commit is contained in:
Nick Winter 2014-08-30 17:09:57 -07:00
parent 4d24233b0d
commit 24d3d189df
4 changed files with 79 additions and 37 deletions
app
templates
views/admin
server

View file

@ -2,17 +2,23 @@ extends /templates/base
block content
h3 Espionage mode
h5 Please enter the email/username of the person you want to spy on
.form
.form-group
label.control-label Email
input#user-email
.form-group
label.control-label Username
input#user-username
button.btn.btn-primary.btn-large#enter-espionage-mode 007
.form-horizontal
.form-group
label.control-label.col-sm-2(for="espionage-name-or-email") Espionage
.col-sm-4
input.form-control#espionage-name-or-email(placeholder="Email or username", type="text")
.col-sm-1
button.btn.btn-primary.btn-large#enter-espionage-mode 007
label.control-label.col-sm-5(for="espionage-name-or-email")
em you are currently #{me.get('name')} at #{me.get('email')}
.form-group
label.control-label.col-sm-2(for="user-search") User Search
.col-sm-4
input.form-control#user-search(placeholder="Email, username, name, whatever", type="text")
.col-sm-1
button.btn.btn-primary.btn-large#user-search-button Search
#user-search-result
h3(data-i18n="admin.av_title") Admin Views

View file

@ -5,32 +5,56 @@ template = require 'templates/admin'
module.exports = class MainAdminView extends RootView
id: 'admin-view'
template: template
lastUserSearchValue: ''
events:
'keyup': 'checkForFormSubmissionEnterPress'
'click #enter-espionage-mode': 'enterEspionageMode'
'click #user-search-button': 'searchForUser'
'click #increment-button': 'incrementUserAttribute'
checkForFormSubmissionEnterPress: (e) ->
if e.which is 13 and @$el.find('#espionage-name-or-email').val() isnt ''
@enterEspionageMode()
return
if @$el.find('#user-search').val() isnt @lastUserSearchValue
@searchForUser()
enterEspionageMode: ->
userEmail = $('#user-email').val().toLowerCase()
username = $('#user-username').val().toLowerCase()
postData =
usernameLower: username
emailLower: userEmail
userNameOrEmail = @$el.find('#espionage-name-or-email').val().toLowerCase()
$.ajax
type: 'POST',
url: '/auth/spy'
data: postData
data: {nameOrEmailLower: userNameOrEmail}
success: @espionageSuccess
error: @espionageFailure
espionageSuccess: (model) ->
window.location.reload()
espionageFailure: (jqxhr, status,error)->
espionageFailure: (jqxhr, status, error)->
console.log "There was an error entering espionage mode: #{error}"
searchForUser: ->
return @onSearchRequestSuccess [] unless @lastUserSearchValue = @$el.find('#user-search').val().toLowerCase()
$.ajax
type: 'POST',
url: '/db/user/-/admin_search'
data: {search: @lastUserSearchValue}
success: @onSearchRequestSuccess
error: @onSearchRequestFailure
onSearchRequestSuccess: (users) =>
result = ''
if users.length
result = ("<tr><td><code>#{user._id}</code></td><td>#{_.escape(user.name or 'Anoner')}</td><td>#{_.escape(user.email)}</td></tr>" for user in users)
result = "<table class=\"table\">#{result.join('\n')}</table>"
@$el.find('#user-search-result').html(result)
onSearchRequestFailure: (jqxhr, status, error) =>
return if @destroyed
console.warn "There was an error looking up #{@lastUserSearchValue}:", error
incrementUserAttribute: (e) ->
val = $('#increment-field').val()
me.set(val, me.get(val) + 1)

View file

@ -32,23 +32,14 @@ module.exports.setup = (app) ->
app.post '/auth/spy', (req, res, next) ->
if req?.user?.isAdmin()
username = req.body.usernameLower
emailLower = req.body.emailLower
if emailLower
query = {'emailLower': emailLower}
else if username
query = {'nameLower': username}
else
return errors.badInput res, 'You need to supply one of emailLower or username'
target = req.body.nameOrEmailLower
return errors.badInput res, 'Specify a username or email to espionage.' unless target
query = $or: [{nameLower: target}, {emailLower: target}]
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'
if err? then return errors.serverError res, 'There was an error logging in with the specified user'
res.send(UserHandler.formatEntity(req, user))
return res.end()
else
@ -117,7 +108,7 @@ module.exports.setup = (app) ->
)
)
app.get '/auth/unsubscribe', (req, res) ->
app.get '/auth/unsubscribe', (req, res) ->
req.query.email = decodeURIComponent(req.query.email)
email = req.query.email
unless req.query.email
@ -132,7 +123,7 @@ module.exports.setup = (app) ->
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}'"
@ -147,7 +138,7 @@ module.exports.setup = (app) ->
else if req.query.employerNotes
emails.employerNotes ?= {}
emails.employerNotes.enabled = false
msg = "Unsubscribed #{req.query.email} from employer emails."
else
msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!"

View file

@ -13,6 +13,7 @@ LevelSession = require '../levels/sessions/LevelSession'
LevelSessionHandler = require '../levels/sessions/level_session_handler'
EarnedAchievement = require '../achievements/EarnedAchievement'
UserRemark = require './remarks/UserRemark'
{isID} = require '../lib/utils'
serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset']
candidateProperties = [
@ -187,6 +188,7 @@ UserHandler = class UserHandler extends Handler
return @getRecentlyPlayed(req, res, args[0]) if args[1] is 'recently_played'
return @trackActivity(req, res, args[0], args[2], args[3]) if args[1] is 'track' and args[2]
return @getRemark(req, res, args[0]) if args[1] is 'remark'
return @searchForUser(req, res) if args[1] is 'admin_search'
return @sendNotFoundError(res)
super(arguments...)
@ -388,6 +390,25 @@ UserHandler = class UserHandler extends Handler
return @sendNotFoundError res unless remark?
@sendSuccess res, remark
searchForUser: (req, res) ->
# TODO: also somehow search the CLAs to find a match amongst those fields and to find GitHub ids
return @sendUnauthorizedError(res) unless req.user.isAdmin()
search = req.body.search
query = email: {$exists: true}, $or: [
{emailLower: search}
{nameLower: search}
]
query.$or.push {_id: mongoose.Types.ObjectId(search) if isID search}
if search.length > 5
searchParts = search.split(/[.+@]/)
if searchParts.length > 1
query.$or.push {emailLower: {$regex: '^' + searchParts[0]}}
projection = name: 1, email: 1, dateCreated: 1
User.find(query).select(projection).lean().exec (err, users) =>
return @sendDatabaseError res, err if err
@sendSuccess res, users
countEdits = (model, done) ->
statKey = User.statsMapping.edits[model.modelName]
return done(new Error 'Could not resolve statKey for model') unless statKey?
@ -578,7 +599,7 @@ UserHandler = class UserHandler extends Handler
thangTypeTranslationPatches: (done) ->
countPatchesByUsersInMemory {'target.collection': 'thang_type'}, isTranslationPatch, User.statsMapping.translations['thang.type'], done
recalculateStats: (statName, done) =>
done new Error 'Recalculation handler not found' unless statName of @statRecalculators
@statRecalculators[statName] done