mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
preliminary autocomplete. THIS IS NOT A WORKING STATUS. ONLY COMMIT TO PULL CHANGES
This commit is contained in:
commit
e756c83d9e
112 changed files with 3010 additions and 1162 deletions
12
.travis.yml
12
.travis.yml
|
@ -2,6 +2,12 @@ language: node_js
|
|||
node_js:
|
||||
- 0.10
|
||||
|
||||
before_install:
|
||||
- "sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10"
|
||||
- "echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list"
|
||||
- "sudo apt-get update"
|
||||
- "sudo apt-get install mongodb-org-server"
|
||||
|
||||
before_script:
|
||||
- "npm install"
|
||||
- export DISPLAY=:99.0
|
||||
|
@ -9,7 +15,11 @@ before_script:
|
|||
- "./node_modules/.bin/bower install"
|
||||
- "gem install sass"
|
||||
- "./node_modules/.bin/brunch b"
|
||||
- "mkdir mongo"
|
||||
- "mongod --dbpath=./mongo --fork --logpath ./mongodb.log"
|
||||
- "node index.js --unittest &"
|
||||
- "sleep 10" # to give node a chance to start
|
||||
|
||||
script:
|
||||
- "./node_modules/jasmine-node/bin/jasmine-node test/server/ --coffee --captureExceptions"
|
||||
- "./node_modules/karma/bin/karma start --browsers Firefox --single-run"
|
||||
|
||||
|
|
BIN
app/assets/images/pages/employer/employer_icon1.png
Normal file
BIN
app/assets/images/pages/employer/employer_icon1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
app/assets/images/pages/employer/employer_icon2.png
Normal file
BIN
app/assets/images/pages/employer/employer_icon2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
app/assets/images/pages/employer/employer_icon3.png
Normal file
BIN
app/assets/images/pages/employer/employer_icon3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
app/assets/images/pages/employer/employer_icon4.png
Normal file
BIN
app/assets/images/pages/employer/employer_icon4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
|
@ -13,9 +13,6 @@ userPropsToSave =
|
|||
|
||||
|
||||
module.exports = FacebookHandler = class FacebookHandler extends CocoClass
|
||||
constructor: ->
|
||||
super()
|
||||
|
||||
subscriptions:
|
||||
'facebook-logged-in':'onFacebookLogin'
|
||||
'facebook-logged-out': 'onFacebookLogout'
|
||||
|
@ -42,22 +39,18 @@ module.exports = FacebookHandler = class FacebookHandler extends CocoClass
|
|||
return
|
||||
|
||||
oldEmail = me.get('email')
|
||||
patch = {}
|
||||
patch.firstName = r.first_name if r.first_name
|
||||
patch.lastName = r.last_name if r.last_name
|
||||
patch.gender = r.gender if r.gender
|
||||
patch.email = r.email if r.email
|
||||
patch.facebookID = r.id if r.id
|
||||
me.set(patch)
|
||||
patch._id = me.id
|
||||
|
||||
me.set('firstName', r.first_name) if r.first_name
|
||||
me.set('lastName', r.last_name) if r.last_name
|
||||
me.set('gender', r.gender) if r.gender
|
||||
me.set('email', r.email) if r.email
|
||||
me.set('facebookID', r.id) if r.id
|
||||
|
||||
Backbone.Mediator.publish('logging-in-with-facebook')
|
||||
window.tracker?.trackEvent 'Facebook Login'
|
||||
window.tracker?.identify()
|
||||
me.save(patch, {
|
||||
patch: true
|
||||
me.patch({
|
||||
error: backboneFailure,
|
||||
url: "/db/user?facebookID=#{r.id}&facebookAccessToken=#{@authResponse.accessToken}"
|
||||
url: "/db/user/#{me.id}?facebookID=#{r.id}&facebookAccessToken=#{@authResponse.accessToken}"
|
||||
success: (model) ->
|
||||
window.location.reload() if model.get('email') isnt oldEmail
|
||||
})
|
||||
|
|
|
@ -22,13 +22,13 @@ module.exports = class LevelBus extends Bus
|
|||
'tome:spell-changed': 'onSpellChanged'
|
||||
'tome:spell-created': 'onSpellCreated'
|
||||
'application:idle-changed': 'onIdleChanged'
|
||||
|
||||
|
||||
constructor: ->
|
||||
super(arguments...)
|
||||
@changedSessionProperties = {}
|
||||
@saveSession = _.debounce(@saveSession, 1000, {maxWait: 5000})
|
||||
@playerIsIdle = false
|
||||
|
||||
|
||||
init: ->
|
||||
super()
|
||||
@fireScriptsRef = @fireRef?.child('scripts')
|
||||
|
@ -36,7 +36,7 @@ module.exports = class LevelBus extends Bus
|
|||
setSession: (@session) ->
|
||||
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
|
||||
@timerIntervalID = setInterval(@incrementSessionPlaytime, 1000)
|
||||
|
||||
|
||||
onIdleChanged: (e) ->
|
||||
@playerIsIdle = e.idle
|
||||
|
||||
|
@ -44,7 +44,7 @@ module.exports = class LevelBus extends Bus
|
|||
if @playerIsIdle then return
|
||||
@changedSessionProperties.playtime = true
|
||||
@session.set("playtime",@session.get("playtime") + 1)
|
||||
|
||||
|
||||
onPoint: ->
|
||||
return true unless @session?.get('multiplayer')
|
||||
super()
|
||||
|
@ -224,7 +224,7 @@ module.exports = class LevelBus extends Bus
|
|||
|
||||
saveSession: ->
|
||||
return if _.isEmpty @changedSessionProperties
|
||||
# don't let peaking admins mess with the session accidentally
|
||||
# don't let peeking admins mess with the session accidentally
|
||||
return unless @session.get('multiplayer') or @session.get('creator') is me.id
|
||||
Backbone.Mediator.publish 'level:session-will-save', session: @session
|
||||
patch = {}
|
||||
|
|
|
@ -18,6 +18,7 @@ doQuerySelector = (value, operatorObj) ->
|
|||
when '$ne' then return false if mapred value, body, (l, r) -> l == r
|
||||
when '$in' then return false unless _.reduce value, ((result, val) -> result or val in body), false
|
||||
when '$nin' then return false if _.reduce value, ((result, val) -> result or val in body), false
|
||||
when '$exists' then return false if value[0]? isnt body[0]
|
||||
else return false
|
||||
true
|
||||
|
||||
|
@ -34,11 +35,13 @@ matchesQuery = (target, queryObj) ->
|
|||
pieces = prop.split('.')
|
||||
obj = target
|
||||
for piece in pieces
|
||||
return false unless piece of obj
|
||||
unless piece of obj
|
||||
obj = null
|
||||
break
|
||||
obj = obj[piece]
|
||||
if typeof query != 'object' or _.isArray query
|
||||
return false unless obj == query or (query in obj if _.isArray obj)
|
||||
else return false unless doQuerySelector obj, query
|
||||
true
|
||||
|
||||
LocalMongo.matchesQuery = matchesQuery
|
||||
LocalMongo.matchesQuery = matchesQuery
|
||||
|
|
|
@ -10,7 +10,7 @@ init = ->
|
|||
if me and not me.get('testGroupNumber')?
|
||||
# Assign testGroupNumber to returning visitors; new ones in server/routes/auth
|
||||
me.set 'testGroupNumber', Math.floor(Math.random() * 256)
|
||||
me.save()
|
||||
me.patch()
|
||||
|
||||
Backbone.listenTo(me, 'sync', Backbone.Mediator.publish('me:synced', {me:me}))
|
||||
|
||||
|
|
|
@ -75,3 +75,25 @@ module.exports.getByPath = (target, path) ->
|
|||
return undefined unless piece of obj
|
||||
obj = obj[piece]
|
||||
obj
|
||||
|
||||
module.exports.round = _.curry (digits, n) ->
|
||||
n = +n.toFixed(digits)
|
||||
|
||||
positify = (func) -> (x) -> if x > 0 then func(x) else 0
|
||||
|
||||
# f(x) = ax + b
|
||||
createLinearFunc = (params) ->
|
||||
(x) -> (params.a or 1) * x + (params.b or 0)
|
||||
|
||||
# f(x) = ax² + bx + c
|
||||
createQuadraticFunc = (params) ->
|
||||
(x) -> (params.a or 1) * x * x + (params.b or 1) * x + (params.c or 0)
|
||||
|
||||
# f(x) = a log(b (x + c)) + d
|
||||
createLogFunc = (params) ->
|
||||
(x) -> if x > 0 then (params.a or 1) * Math.log((params.b or 1) * (x + (params.c or 0))) + (params.d or 0) else 0
|
||||
|
||||
module.exports.functionCreators =
|
||||
linear: positify(createLinearFunc)
|
||||
quadratic: positify(createQuadraticFunc)
|
||||
logarithmic: positify(createLogFunc)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports.thangNames = thangNames =
|
||||
"Soldier M": [
|
||||
"Duke"
|
||||
"William"
|
||||
"Lucas"
|
||||
"Marcus"
|
||||
|
@ -66,6 +67,7 @@ module.exports.thangNames = thangNames =
|
|||
"Coco"
|
||||
"Buffy"
|
||||
"Allankrita"
|
||||
"Kay"
|
||||
]
|
||||
"Peasant M": [
|
||||
"Yorik"
|
||||
|
@ -355,6 +357,8 @@ module.exports.thangNames = thangNames =
|
|||
"Hank"
|
||||
"Jeph"
|
||||
"Neville"
|
||||
"Alphonse"
|
||||
"Edward"
|
||||
]
|
||||
"Captain": [
|
||||
"Anya"
|
||||
|
@ -367,4 +371,5 @@ module.exports.thangNames = thangNames =
|
|||
"Jane"
|
||||
"Lia"
|
||||
"Hardcastle"
|
||||
"Leona"
|
||||
]
|
||||
|
|
|
@ -198,8 +198,8 @@
|
|||
done_editing: "Done Editing"
|
||||
profile_for_prefix: "Profile for "
|
||||
profile_for_suffix: ""
|
||||
approved: "Approved"
|
||||
not_approved: "Not Approved"
|
||||
featured: "Featured"
|
||||
not_featured: "Not Featured"
|
||||
looking_for: "Looking for:"
|
||||
last_updated: "Last updated:"
|
||||
contact: "Contact"
|
||||
|
@ -294,14 +294,25 @@
|
|||
project_picture_help: "Upload a 230x115px or larger image showing off the project."
|
||||
project_link: "Link"
|
||||
project_link_help: "Link to the project."
|
||||
|
||||
player_code: "Player Code"
|
||||
|
||||
employers:
|
||||
want_to_hire_our_players: "Want to hire expert CodeCombat players?"
|
||||
want_to_hire_our_players: "Hire CodeCombat Players"
|
||||
what: "What is CodeCombat?"
|
||||
what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. We support JavaScript, Python, Lua, Clojure, CoffeeScript, and Io."
|
||||
who: "Who Are the Players?"
|
||||
who_blurb: "CodeCombateers are software developers who enjoy using their programming skills to play games. They range from college seniors at top 20 engineering programs to 20-year industry veterans."
|
||||
how: "How Do We Find Developers?"
|
||||
how_blurb: "We host competitive tournaments to attract competitive software engieneers. We then use in-house algorithms to identify the best players among the top 5% of tournament winners."
|
||||
why: "Why Hire Through Us?"
|
||||
why_blurb_1: "We will save you time. Every CodeCombateer we feaure is "
|
||||
why_blurb_2: "looking for work"
|
||||
why_blurb_3: ", has "
|
||||
why_blurb_4: "demonstrated top notch technical skills"
|
||||
why_blurb_5: ", and has been "
|
||||
why_blurb_6: "personally screened by us"
|
||||
why_blurb_7: ". Stop screening and start hiring."
|
||||
see_candidates: "Click here to see our candidates"
|
||||
candidates_count_prefix: "We currently have "
|
||||
candidates_count_many: "many"
|
||||
candidates_count_suffix: "highly skilled and vetted developers looking for work."
|
||||
candidate_name: "Name"
|
||||
candidate_location: "Location"
|
||||
candidate_looking_for: "Looking For"
|
||||
|
@ -309,8 +320,9 @@
|
|||
candidate_top_skills: "Top Skills"
|
||||
candidate_years_experience: "Yrs Exp"
|
||||
candidate_last_updated: "Last Updated"
|
||||
candidate_approved: "Us?"
|
||||
candidate_active: "Them?"
|
||||
featured_developers: "Featured Developers"
|
||||
other_developers: "Other Developers"
|
||||
inactive_developers: "Inactive Developers"
|
||||
|
||||
play_level:
|
||||
done: "Done"
|
||||
|
@ -436,6 +448,7 @@
|
|||
av_entities_sub_title: "Entities"
|
||||
av_entities_users_url: "Users"
|
||||
av_entities_active_instances_url: "Active Instances"
|
||||
av_entities_employer_list_url: "Employer List"
|
||||
av_other_sub_title: "Other"
|
||||
av_other_debug_base_url: "Base (for debugging base.jade)"
|
||||
u_title: "User List"
|
||||
|
@ -505,7 +518,7 @@
|
|||
new_thang_title_login: "Log In to Create a New Thang Type"
|
||||
new_level_title_login: "Log In to Create a New Level"
|
||||
new_achievement_title: "Create a New Achievement"
|
||||
new_achievement_title_login: "Sign Up to Create a New Achievement"
|
||||
new_achievement_title_login: "Log In to Create a New Achievement"
|
||||
article_search_title: "Search Articles Here"
|
||||
thang_search_title: "Search Thang Types Here"
|
||||
level_search_title: "Search Levels Here"
|
||||
|
@ -784,9 +797,12 @@
|
|||
watch_victory: "Watch your victory"
|
||||
defeat_the: "Defeat the"
|
||||
tournament_ends: "Tournament ends"
|
||||
tournament_ended: "Tournament ended"
|
||||
tournament_rules: "Tournament Rules"
|
||||
tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details"
|
||||
tournament_blurb_blog: "on our blog"
|
||||
rules: "Rules"
|
||||
winners: "Winners"
|
||||
|
||||
ladder_prizes:
|
||||
title: "Tournament Prizes"
|
||||
|
@ -808,7 +824,6 @@
|
|||
license: "license"
|
||||
oreilly: "ebook of your choice"
|
||||
|
||||
|
||||
multiplayer_launch:
|
||||
introducing_dungeon_arena: "Introducing Dungeon Arena"
|
||||
new_way: "The new way to compete with code."
|
||||
|
@ -866,6 +881,7 @@
|
|||
source_document: "Source Document"
|
||||
document: "Document" # note to diplomats: not a physical document, a document in MongoDB, ie a record in a database
|
||||
sprite_sheet: "Sprite Sheet"
|
||||
candidate_sessions: "Candidate Sessions"
|
||||
|
||||
delta:
|
||||
added: "Added"
|
||||
|
|
|
@ -16,7 +16,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
play: "Jouer"
|
||||
retry: "Reessayer"
|
||||
watch: "Regarder"
|
||||
# unwatch: "Unwatch"
|
||||
unwatch: "Ne plus regarder"
|
||||
submit_patch: "Soumettre un correctif"
|
||||
|
||||
units:
|
||||
|
@ -26,14 +26,14 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
minutes: "minutes"
|
||||
hour: "heure"
|
||||
hours: "heures"
|
||||
# day: "day"
|
||||
# days: "days"
|
||||
# week: "week"
|
||||
# weeks: "weeks"
|
||||
# month: "month"
|
||||
# months: "months"
|
||||
# year: "year"
|
||||
# years: "years"
|
||||
day: "jour"
|
||||
days: "jours"
|
||||
week: "semaine"
|
||||
weeks: "semaines"
|
||||
month: "mois"
|
||||
months: "mois"
|
||||
year: "année"
|
||||
years: "années"
|
||||
|
||||
modal:
|
||||
close: "Fermer"
|
||||
|
@ -128,8 +128,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
forum_page: "notre forum"
|
||||
forum_suffix: " À la place."
|
||||
send: "Envoyer un commentaire"
|
||||
# contact_candidate: "Contact Candidate"
|
||||
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns."
|
||||
contact_candidate: "Contacter le candidat"
|
||||
recruitment_reminder: "Utilisez ce formulaire pour entrer en contact avec le candidat qui vous interesse. Souvenez-vous que CodeCombat facture 15% de la première année de salaire. Ces frais sont dues à l'embauche de l'employé, ils sont remboursable pendant 90 jours si l'employé ne reste pas employé. Les employés à temps partiel, à distance ou contractuel sont gratuits en tant que stagiaires."
|
||||
|
||||
diplomat_suggestion:
|
||||
title: "Aidez à traduire CodeCombat!"
|
||||
|
@ -173,11 +173,11 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
email_announcements: "Annonces"
|
||||
email_announcements_description: "Recevoir des mails sur les dernières actualités et sur le développement de CodeCombat."
|
||||
email_notifications: "Notifications"
|
||||
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
||||
# email_any_notes: "Any Notifications"
|
||||
email_notifications_summary: "Commandes pour personaliser les notifications automatiques d'email liées à votre activité sur CodeCombat."
|
||||
email_any_notes: "Toutes Notifications"
|
||||
email_any_notes_description: "Désactivez pour ne plus recevoir de notifications par e-mail."
|
||||
# email_recruit_notes: "Job Opportunities"
|
||||
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job."
|
||||
email_recruit_notes: "Offres d'emploi"
|
||||
email_recruit_notes_description: "Si vous jouez vraiment bien, nous pouvons vous contacter pour vous proposer un (meilleur) emploi."
|
||||
contributor_emails: "Emails des contributeurs"
|
||||
contribute_prefix: "Nous recherchons des personnes pour se joindre à notre groupe! Consultez la "
|
||||
contribute_page: "page de contributions"
|
||||
|
@ -186,15 +186,15 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
error_saving: "Problème d'enregistrement"
|
||||
saved: "Changements sauvegardés"
|
||||
password_mismatch: "Le mot de passe ne correspond pas."
|
||||
# job_profile: "Job Profile"
|
||||
# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks."
|
||||
# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
|
||||
# sample_profile: "See a sample profile"
|
||||
job_profile: "Profil d'emploi"
|
||||
job_profile_approved: "Votre profil d'emploi a été approuvé par CodeCombat. Les employeurs seront en mesure de voir votre profil jusqu'à ce que vous le marquez inactif ou qu'il n'a pas été changé pendant quatre semaines."
|
||||
job_profile_explanation: "Salut! Remplissez-le et nous prendrons contact pour vous trouver un emploi de développeur de logiciels."
|
||||
sample_profile: "Voir un exemple de profil"
|
||||
view_profile: "Voir votre profil"
|
||||
|
||||
account_profile:
|
||||
edit_settings: "Éditer les préférences"
|
||||
# done_editing_settings: "Done Editing"
|
||||
done_editing_settings: "Edition terminée"
|
||||
profile_for_prefix: "Profil pour "
|
||||
profile_for_suffix: ""
|
||||
approved: "Approuvé"
|
||||
|
@ -202,57 +202,57 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
looking_for: "à la recherche de:"
|
||||
last_updated: "Dernière Mise à jour:"
|
||||
contact: "Contact"
|
||||
# active: "Looking for interview offers now"
|
||||
# inactive: "Not looking for offers right now"
|
||||
# complete: "complete"
|
||||
# next: "Next"
|
||||
# next_city: "city?"
|
||||
# next_country: "pick your country."
|
||||
# next_name: "name?"
|
||||
# next_short_description: "summarize yourself at a glance."
|
||||
# next_long_description: "describe the work you're looking for."
|
||||
# next_skills: "list at least five skills."
|
||||
# next_work: "list your work experience."
|
||||
# next_education: "recount your educational ordeals."
|
||||
# next_projects: "show off up to three projects you've worked on."
|
||||
# next_links: "add any personal or social links."
|
||||
# next_photo: "add an optional professional photo."
|
||||
# next_active: "mark yourself open to offers to show up in searches."
|
||||
# example_blog: "Your Blog"
|
||||
# example_github: "Your GitHub"
|
||||
# links_header: "Personal Links"
|
||||
# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog."
|
||||
# links_name: "Link Name"
|
||||
# links_name_help: "What are you linking to?"
|
||||
# links_link_blurb: "Link URL"
|
||||
# basics_header: "Update basic info"
|
||||
# basics_active: "Open to Offers"
|
||||
# basics_active_help: "Want interview offers right now?"
|
||||
# basics_job_title: "Desired Job Title"
|
||||
# basics_job_title_help: "What role are you looking for?"
|
||||
# basics_city: "City"
|
||||
# basics_city_help: "City you want to work in (or live in now)."
|
||||
# basics_country: "Country"
|
||||
# basics_country_help: "Country you want to work in (or live in now)."
|
||||
# basics_visa: "US Work Status"
|
||||
# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship?"
|
||||
# basics_looking_for: "Looking For"
|
||||
# basics_looking_for_full_time: "Full-time"
|
||||
# basics_looking_for_part_time: "Part-time"
|
||||
# basics_looking_for_remote: "Remote"
|
||||
# basics_looking_for_contracting: "Contracting"
|
||||
# basics_looking_for_internship: "Internship"
|
||||
# basics_looking_for_help: "What kind of developer position do you want?"
|
||||
# name_header: "Fill in your name"
|
||||
# name_anonymous: "Anonymous Developer"
|
||||
# name_help: "Name you want employers to see, like 'Nick Winter'."
|
||||
# short_description_header: "Write a short description of yourself"
|
||||
active: "En recherche d'offres"
|
||||
inactive: "Ne recherche pas d'offres"
|
||||
complete: "terminé"
|
||||
next: "Suivant"
|
||||
next_city: "ville ?"
|
||||
next_country: "choisissez votre pays."
|
||||
next_name: "nom ?"
|
||||
next_short_description: "résumez votre profil en quelques mots."
|
||||
next_long_description: "décrivez le travail que vous cherchez."
|
||||
next_skills: "listez au moins 5 compétances."
|
||||
next_work: "décrivez votre expérience professionnelle."
|
||||
next_education: "raconter votre scolarité."
|
||||
next_projects: "décrivez jusqu'à 3 projets sur lesquels vous avez travaillé."
|
||||
next_links: "ajouter des liens internet vers des sites personnels ou des réseaux sociaux."
|
||||
next_photo: "ajouter une photo professionelle (optionnel)."
|
||||
next_active: "déclarez vous ouvert aux offres pour apparaitre dans les recherches."
|
||||
example_blog: "Votre blog"
|
||||
example_github: "Votre GitHub"
|
||||
links_header: "Liens personnels"
|
||||
links_blurb: "Lien vers d'autres sites ou profils que vous souhaitez mettre en avant, comme votre GitHub, LinkedIn ou votre blog."
|
||||
links_name: "Nom du lien"
|
||||
links_name_help: "A quoi êtes vous lié ?"
|
||||
links_link_blurb: "Lien URL"
|
||||
basics_header: "Mettre à jour les information basiques"
|
||||
basics_active: "Ouvert aux propositions"
|
||||
basics_active_help: "Voulez-vous des offres maintenant ?" # "Want interview offers right now?"
|
||||
basics_job_title: "Titre du poste souhaité"
|
||||
basics_job_title_help: "Quel est le rôle que vous cherchez ?"
|
||||
basics_city: "Ville"
|
||||
basics_city_help: "Ville dans laquelle vous souhaitez travailler (ou dans laquelle vous vivez actuellement)."
|
||||
basics_country: "Pays"
|
||||
basics_country_help: "Pays dans lequel vous souhaitez travailler (ou dans lequel vous vivez actuellement)."
|
||||
basics_visa: "Status de travail aux Etats-Unis"
|
||||
basics_visa_help: "Etes vous autorisé à travailler aux Etats-Unis ou avez vous besoin d'un parrainage pour le visa ?"
|
||||
basics_looking_for: "Recherche"
|
||||
basics_looking_for_full_time: "Temps plein"
|
||||
basics_looking_for_part_time: "Temps partiel"
|
||||
basics_looking_for_remote: "A distance"
|
||||
basics_looking_for_contracting: "Contrat"
|
||||
basics_looking_for_internship: "Stage"
|
||||
basics_looking_for_help: "Quel genre de poste de développeur voulez-vous ?"
|
||||
name_header: "Remplissez votre nom"
|
||||
name_anonymous: "Developpeur Anonyme"
|
||||
name_help: "Le nom que vous souhaitez que l'employeur voie, par exemple 'Chuck Norris'."
|
||||
short_description_header: "Décrivez vous en quelques mots"
|
||||
# short_description_blurb: "Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for."
|
||||
# short_description: "Short Description"
|
||||
# short_description_help: "Who are you, and what are you looking for? 140 characters max."
|
||||
# skills_header: "Skills"
|
||||
# skills_help: "Tag relevant developer skills in order of proficiency."
|
||||
# long_description_header: "Detail your desired position"
|
||||
short_description: "Description courte"
|
||||
short_description_help: "Qui êtes vous et que recherchez vous ? 140 caractères max."
|
||||
skills_header: "Compétences"
|
||||
skills_help: "Notez vos compétence de développement par ordre de maitrise."
|
||||
long_description_header: "Détaillez votre poste souhaité"
|
||||
# long_description_blurb_1: "Write a little longer section here to describe the role you would like to pursue next."
|
||||
# long_description_blurb_2: "Talk about how awesome you are and why it would be a good idea to hire you."
|
||||
# long_description: "Description"
|
||||
|
@ -322,7 +322,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
goals: "Objectifs"
|
||||
success: "Succès"
|
||||
incomplete: "Imcoplet"
|
||||
# timed_out: "Ran out of time"
|
||||
timed_out: "Plus de temps"
|
||||
failing: "Echec"
|
||||
action_timeline: "Action sur la ligne de temps"
|
||||
click_to_select: "Clique sur une unité pour la sélectionner."
|
||||
|
@ -465,8 +465,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
back: "Retour"
|
||||
revert: "Annuler"
|
||||
revert_models: "Annuler les modèles"
|
||||
# fork_title: "Fork New Version"
|
||||
# fork_creating: "Creating Fork..."
|
||||
fork_title: "Fork une nouvelle version"
|
||||
fork_creating: "Créer un Fork..."
|
||||
more: "Plus"
|
||||
wiki: "Wiki"
|
||||
live_chat: "Chat en live"
|
||||
|
@ -533,7 +533,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
message: "Message"
|
||||
code: "Code"
|
||||
ladder: "Companion"
|
||||
when: "Lorsuqe"
|
||||
when: "Quand"
|
||||
opponent: "Adversaire"
|
||||
rank: "Rang"
|
||||
score: "Score"
|
||||
|
@ -744,8 +744,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
simulation_explanation: "En simulant une partie, tu peux classer ton rang plus rapidement!"
|
||||
simulate_games: "Simuler une Partie!"
|
||||
simulate_all: "REINITIALISER ET SIMULER DES PARTIES"
|
||||
# games_simulated_by: "Games simulated by you:"
|
||||
# games_simulated_for: "Games simulated for you:"
|
||||
games_simulated_by: "Parties que vous avez simulé :"
|
||||
games_simulated_for: "parties simulées pour vous :"
|
||||
games_simulated: "Partie simulée"
|
||||
games_played: "Parties jouées"
|
||||
ratio: "Moyenne"
|
||||
|
@ -776,11 +776,11 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
warmup: "Préchauffe"
|
||||
vs: "VS"
|
||||
# friends_playing: "Friends Playing"
|
||||
# log_in_for_friends: "Log in to play with your friends!"
|
||||
# social_connect_blurb: "Connect and play against your friends!"
|
||||
log_in_for_friends: "Connectez vous pour jouer avec vos amis!"
|
||||
social_connect_blurb: "Connectez vous pour jouer contre vos amis!"
|
||||
# invite_friends_to_battle: "Invite your friends to join you in battle!"
|
||||
# fight: "Fight!"
|
||||
# watch_victory: "Watch your victory"
|
||||
fight: "Combattez !"
|
||||
watch_victory: "Regardez votre victoire"
|
||||
# defeat_the: "Defeat the"
|
||||
tournament_ends: "Fin du tournoi"
|
||||
tournament_rules: "Règles du tournoi"
|
||||
|
@ -835,7 +835,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
unknown: "Erreur inconnue."
|
||||
|
||||
resources:
|
||||
# your_sessions: "Your Sessions"
|
||||
your_sessions: "vos Sessions"
|
||||
level: "Niveau"
|
||||
# social_network_apis: "Social Network APIs"
|
||||
facebook_status: "Statut Facebook"
|
||||
|
@ -857,11 +857,11 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
# level_session: "Your Session"
|
||||
# opponent_session: "Opponent Session"
|
||||
article: "Article"
|
||||
# user_names: "User Names"
|
||||
user_names: "Nom d'utilisateur"
|
||||
# thang_names: "Thang Names"
|
||||
files: "Fichiers"
|
||||
top_simulators: "Top Simulateurs"
|
||||
# source_document: "Source Document"
|
||||
source_document: "Document Source"
|
||||
document: "Document"
|
||||
# sprite_sheet: "Sprite Sheet"
|
||||
|
||||
|
@ -869,7 +869,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
|||
added: "Ajouté"
|
||||
modified: "Modifié"
|
||||
deleted: "Supprimé"
|
||||
# moved_index: "Moved Index"
|
||||
# text_diff: "Text Diff"
|
||||
# merge_conflict_with: "MERGE CONFLICT WITH"
|
||||
moved_index: "Index changé"
|
||||
text_diff: "Différence de texte"
|
||||
merge_conflict_with: "Fusionner les conflits avec"
|
||||
no_changes: "Aucuns Changements"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
CocoModel = require './CocoModel'
|
||||
util = require '../lib/utils'
|
||||
|
||||
module.exports = class Achievement extends CocoModel
|
||||
@className: 'Achievement'
|
||||
|
@ -6,4 +7,10 @@ module.exports = class Achievement extends CocoModel
|
|||
urlRoot: '/db/achievement'
|
||||
|
||||
isRepeatable: ->
|
||||
@get('proportionalTo')?
|
||||
@get('proportionalTo')?
|
||||
|
||||
# TODO logic is duplicated in Mongoose Achievement schema
|
||||
getExpFunction: ->
|
||||
kind = @get('function')?.kind or @schema.function.default.kind
|
||||
parameters = @get('function')?.parameters or @schema.function.default.parameters
|
||||
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
||||
|
|
|
@ -97,6 +97,22 @@ class CocoModel extends Backbone.Model
|
|||
noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000
|
||||
@trigger "save", @
|
||||
return super attrs, options
|
||||
|
||||
patch: (options) ->
|
||||
return false unless @_revertAttributes
|
||||
options ?= {}
|
||||
options.patch = true
|
||||
|
||||
attrs = {_id: @id}
|
||||
keys = []
|
||||
for key in _.keys @attributes
|
||||
unless _.isEqual @attributes[key], @_revertAttributes[key]
|
||||
attrs[key] = @attributes[key]
|
||||
keys.push key
|
||||
|
||||
return unless keys.length
|
||||
console.debug 'Patching', @get('name') or @, keys
|
||||
@save(attrs, options)
|
||||
|
||||
fetch: ->
|
||||
@jqxhr = super(arguments...)
|
||||
|
@ -104,7 +120,6 @@ class CocoModel extends Backbone.Model
|
|||
@jqxhr
|
||||
|
||||
markToRevert: ->
|
||||
console.debug "Saving _revertAttributes for #{@constructor.className}: '#{@get('name')}'"
|
||||
if @type() is 'ThangType'
|
||||
@_revertAttributes = _.clone @attributes # No deep clones for these!
|
||||
else
|
||||
|
|
|
@ -19,8 +19,8 @@ module.exports = class LevelComponent extends CocoModel
|
|||
@set 'js', @compile(@get 'code') unless @get 'js'
|
||||
|
||||
compile: (code) ->
|
||||
if @get('language') and @get('language') isnt 'coffeescript'
|
||||
return console.error("Can't compile", @get('language'), "-- only CoffeeScript.", @)
|
||||
if @get('codeLanguage') and @get('codeLanguage') isnt 'coffeescript'
|
||||
return console.error("Can't compile", @get('codeLanguage'), "-- only CoffeeScript.", @)
|
||||
try
|
||||
js = CoffeeScript.compile(code, bare: true)
|
||||
catch e
|
||||
|
|
|
@ -21,8 +21,8 @@ module.exports = class LevelSystem extends CocoModel
|
|||
SystemNameLoader.setName @
|
||||
|
||||
compile: (code) ->
|
||||
if @get('language') and @get('language') isnt 'coffeescript'
|
||||
return console.error("Can't compile", @get('language'), "-- only CoffeeScript.", @)
|
||||
if @get('codeLanguage') and @get('codeLanguage') isnt 'coffeescript'
|
||||
return console.error("Can't compile", @get('codeLanguage'), "-- only CoffeeScript.", @)
|
||||
try
|
||||
js = CoffeeScript.compile(code, bare: true)
|
||||
catch e
|
||||
|
|
|
@ -52,22 +52,17 @@ _.extend(AchievementSchema.properties,
|
|||
description: 'For repeatables only. Denotes the field a repeatable achievement needs for its calculations'
|
||||
function:
|
||||
type: 'object'
|
||||
oneOf: [
|
||||
linear:
|
||||
properties:
|
||||
kind: {enum: ['linear', 'logarithmic'], default: 'linear'}
|
||||
parameters:
|
||||
type: 'object'
|
||||
properties:
|
||||
a: {type: 'number', default: 1},
|
||||
required: ['a']
|
||||
description: 'f(x) = a * x'
|
||||
logarithmic:
|
||||
type:'object'
|
||||
properties:
|
||||
a: {type: 'number', default: 1}
|
||||
b: {type: 'number', default: 1}
|
||||
required: ['a', 'b']
|
||||
description: 'f(x) = a * ln(1/b * (x + b))'
|
||||
]
|
||||
default: linear: a: 1
|
||||
c: {type: 'number', default: 1}
|
||||
default: {kind: 'linear', parameters: a: 1}
|
||||
required: ['kind', 'parameters']
|
||||
additionalProperties: false
|
||||
)
|
||||
|
||||
AchievementSchema.definitions = {}
|
||||
|
|
|
@ -20,15 +20,11 @@ module.exports =
|
|||
href: '/db/achievement/{($)}'
|
||||
}
|
||||
]
|
||||
collection:
|
||||
type: 'string'
|
||||
achievementName:
|
||||
type: 'string'
|
||||
created:
|
||||
type: 'date'
|
||||
changed:
|
||||
type: 'date'
|
||||
achievedAmount:
|
||||
type: 'number'
|
||||
notified:
|
||||
type: 'boolean'
|
||||
collection: type: 'string'
|
||||
achievementName: type: 'string'
|
||||
created: type: 'date'
|
||||
changed: type: 'date'
|
||||
achievedAmount: type: 'number'
|
||||
earnedPoints: type: 'number'
|
||||
previouslyAchievedAmount: {type: 'number', default: 0}
|
||||
notified: type: 'boolean'
|
||||
|
|
|
@ -70,13 +70,13 @@ DependencySchema = c.object {
|
|||
LevelComponentSchema = c.object {
|
||||
title: "Component"
|
||||
description: "A Component which can affect Thang behavior."
|
||||
required: ["system", "name", "description", "code", "dependencies", "propertyDocumentation", "language"]
|
||||
required: ["system", "name", "description", "code", "dependencies", "propertyDocumentation", "codeLanguage"]
|
||||
"default":
|
||||
system: "ai"
|
||||
name: "AttacksSelf"
|
||||
description: "This Component makes the Thang attack itself."
|
||||
code: attackSelfCode
|
||||
language: "coffeescript"
|
||||
codeLanguage: "coffeescript"
|
||||
dependencies: [] # TODO: should depend on something by default
|
||||
propertyDocumentation: []
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ _.extend LevelComponentSchema.properties,
|
|||
type: "string"
|
||||
maxLength: 2000
|
||||
"default": "This Component makes the Thang attack itself."
|
||||
language:
|
||||
codeLanguage:
|
||||
type: "string"
|
||||
title: "Language"
|
||||
description: "Which programming language this Component is written in."
|
||||
|
|
|
@ -54,12 +54,12 @@ DependencySchema = c.object {
|
|||
LevelSystemSchema = c.object {
|
||||
title: "System"
|
||||
description: "A System which can affect Level behavior."
|
||||
required: ["name", "description", "code", "dependencies", "propertyDocumentation", "language"]
|
||||
required: ["name", "description", "code", "dependencies", "propertyDocumentation", "codeLanguage"]
|
||||
"default":
|
||||
name: "JitterSystem"
|
||||
description: "This System makes all idle, movable Thangs jitter around."
|
||||
code: jitterSystemCode
|
||||
language: "coffeescript"
|
||||
codeLanguage: "coffeescript"
|
||||
dependencies: [] # TODO: should depend on something by default
|
||||
propertyDocumentation: []
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ _.extend LevelSystemSchema.properties,
|
|||
type: "string"
|
||||
maxLength: 2000
|
||||
"default": "This System doesn't do anything yet."
|
||||
language:
|
||||
codeLanguage:
|
||||
type: "string"
|
||||
title: "Language"
|
||||
description: "Which programming language this System is written in."
|
||||
|
|
|
@ -113,8 +113,10 @@ UserSchema = c.object {},
|
|||
signedEmployerAgreement: c.object {},
|
||||
linkedinID: c.shortString {title:"LinkedInID", description: "The user's LinkedIn ID when they signed the contract."}
|
||||
date: c.date {title: "Date signed employer agreement"}
|
||||
data: c.object {description: "Cached LinkedIn data slurped from profile."}
|
||||
data: c.object {description: "Cached LinkedIn data slurped from profile.", additionalProperties: true}
|
||||
points: {type:'number'}
|
||||
activity: {type: 'object', description: 'Summary statistics about user activity', additionalProperties: c.activity}
|
||||
|
||||
|
||||
|
||||
c.extendBasicProperties UserSchema, 'user'
|
||||
|
|
|
@ -8,7 +8,7 @@ combine = (base, ext) ->
|
|||
return base unless ext?
|
||||
return _.extend(base, ext)
|
||||
|
||||
urlPattern = '^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_=]*)?$'
|
||||
urlPattern = '^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_=]*)?$'
|
||||
|
||||
# Common schema properties
|
||||
me.object = (ext, props) -> combine {type: 'object', additionalProperties: false, properties: props or {}}, ext
|
||||
|
@ -17,7 +17,7 @@ me.shortString = (ext) -> combine({type: 'string', maxLength: 100}, ext)
|
|||
me.pct = (ext) -> combine({type: 'number', maximum: 1.0, minimum: 0.0}, ext)
|
||||
me.date = (ext) -> combine({type: ['object', 'string'], format: 'date-time'}, ext)
|
||||
# should just be string (Mongo ID), but sometimes mongoose turns them into objects representing those, so we are lenient
|
||||
me.objectId = (ext) -> schema = combine(['object', 'string'], ext)
|
||||
me.objectId = (ext) -> schema = combine({type: ['object', 'string'] }, ext)
|
||||
me.url = (ext) -> combine({type: 'string', format: 'url', pattern: urlPattern}, ext)
|
||||
|
||||
PointSchema = me.object {title: "Point", description: "An {x, y} coordinate point.", format: "point2d", required: ["x", "y"]},
|
||||
|
@ -54,7 +54,7 @@ basicProps = (linkFragment) ->
|
|||
me.extendBasicProperties = (schema, linkFragment) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
_.extend(schema.properties, basicProps(linkFragment))
|
||||
|
||||
|
||||
# PATCHABLE
|
||||
|
||||
patchableProps = ->
|
||||
|
@ -65,7 +65,7 @@ patchableProps = ->
|
|||
allowPatches: { type: 'boolean' }
|
||||
watchers: me.array({title:'Watchers'},
|
||||
me.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}]))
|
||||
|
||||
|
||||
me.extendPatchableProperties = (schema) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
_.extend(schema.properties, patchableProps())
|
||||
|
@ -176,3 +176,9 @@ me.codeSnippet = (mode) ->
|
|||
code: {type: 'string', title: 'Snippet', default: '', description: 'Code snippet. Use ${1:defaultValue} syntax to add flexible arguments'}
|
||||
# code: {type: 'string', format: 'ace', aceMode: 'ace/mode/'+mode, title: 'Snippet', default: '', description: 'Code snippet. Use ${1:defaultValue} syntax to add flexible arguments'}
|
||||
tab: {type: 'string', description: 'Tab completion text. Will be expanded to the snippet if typed and hit tab.'}
|
||||
|
||||
me.activity = me.object {description: "Stats on an activity"},
|
||||
first: me.date()
|
||||
last: me.date()
|
||||
count: {type: 'integer', minimum: 0}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
color: #555
|
||||
|
||||
ul.links, ul.projects
|
||||
ul.links, ul.projects, ul.sessions
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
|
@ -140,7 +140,7 @@
|
|||
background-color: rgb(177, 55, 25)
|
||||
padding: 15px
|
||||
font-size: 20px
|
||||
|
||||
|
||||
.middle-column
|
||||
width: $middle-width - 2 * $middle-padding
|
||||
padding-left: $middle-padding
|
||||
|
|
12
app/styles/editor/achievement/edit.sass
Normal file
12
app/styles/editor/achievement/edit.sass
Normal file
|
@ -0,0 +1,12 @@
|
|||
#editor-achievement-edit-view
|
||||
.treema-root
|
||||
margin: 28px 0px 20px
|
||||
|
||||
button
|
||||
float: right
|
||||
margin-top: 15px
|
||||
margin-left: 10px
|
||||
|
||||
textarea
|
||||
width: 92%
|
||||
height: 300px
|
|
@ -1,6 +1,32 @@
|
|||
#employers-view
|
||||
#see-candidates
|
||||
cursor: pointer
|
||||
|
||||
h1, h2, h3
|
||||
font: Arial
|
||||
|
||||
.see-candidates-header
|
||||
margin: 30px
|
||||
text-align: center
|
||||
|
||||
#see-candidates
|
||||
cursor: pointer
|
||||
|
||||
.employer_icon
|
||||
width: 125px
|
||||
float: left
|
||||
margin: 0px 15px 15px 0px
|
||||
|
||||
.information_row
|
||||
height: 150px
|
||||
padding-right: 15px
|
||||
|
||||
#leftside
|
||||
width: 500px
|
||||
float: left
|
||||
|
||||
#rightside
|
||||
width: 500px
|
||||
float: left
|
||||
|
||||
.tablesorter
|
||||
//img
|
||||
// display: none
|
||||
|
@ -36,3 +62,9 @@
|
|||
min-width: 50px
|
||||
td:nth-child(7) select
|
||||
min-width: 100px
|
||||
|
||||
#outer-content-wrapper, #intermediate-content-wrapper, #inner-content-wrapper
|
||||
background: #949494
|
||||
|
||||
.main-content-area
|
||||
background-color: #EAEAEA
|
||||
|
|
|
@ -45,3 +45,6 @@
|
|||
font-family: Bangers
|
||||
font-size: 16px
|
||||
float: right
|
||||
|
||||
.progress-bar-white
|
||||
background-color: white
|
||||
|
|
|
@ -101,9 +101,6 @@
|
|||
background-image: none
|
||||
color: white
|
||||
|
||||
td
|
||||
padding: 1px 2px
|
||||
|
||||
#must-log-in button
|
||||
margin-right: 10px
|
||||
|
||||
|
@ -135,6 +132,12 @@
|
|||
img
|
||||
margin-right: 10px
|
||||
|
||||
#winners
|
||||
.win
|
||||
color: #172
|
||||
.loss
|
||||
color: #712
|
||||
|
||||
@media only screen and (max-width: 800px)
|
||||
#ladder-view
|
||||
#level-column img
|
||||
|
|
|
@ -47,3 +47,6 @@
|
|||
position: absolute
|
||||
right: 15px
|
||||
bottom: -5px
|
||||
|
||||
td
|
||||
padding: 1px 2px
|
||||
|
|
|
@ -35,4 +35,5 @@
|
|||
tr.loss .state-cell
|
||||
color: #712
|
||||
|
||||
|
||||
td
|
||||
padding: 1px 2px
|
||||
|
|
|
@ -37,18 +37,13 @@ block content
|
|||
if profileApproved
|
||||
button.btn.btn-success#toggle-job-profile-approved(disabled=!me.isAdmin())
|
||||
i.icon-eye-open
|
||||
span(data-i18n='account_profile.approved') Approved
|
||||
span(data-i18n='account_profile.featured') Featured
|
||||
else if me.isAdmin()
|
||||
button.btn#toggle-job-profile-approved
|
||||
i.icon-eye-close
|
||||
span(data-i18n='account_profile.not_approved') Not Approved
|
||||
span(data-i18n='account_profile.not_featured') Not Featured
|
||||
if me.isAdmin() && !myProfile
|
||||
button.btn.edit-settings-button#enter-espionage-mode 007
|
||||
//if editing && myProfile
|
||||
// a.sample-profile(href="http://codecombat.com/images/pages/account/profile/sample_profile.png", target="_blank")
|
||||
// button.btn
|
||||
// i.icon-user
|
||||
// span(data-i18n="account_settings.sample_profile") See a sample profile
|
||||
|
||||
if profile && allowedToViewJobProfile
|
||||
div(class="job-profile-container" + (editing ? " editable-profile" : ""))
|
||||
|
@ -175,6 +170,19 @@ block content
|
|||
span(data-i18n="account_profile.contact") Contact
|
||||
| #{profile.name.split(' ')[0]}
|
||||
|
||||
if !editing && sessions.length
|
||||
h3(data-i18n="account_profile.player_code") Player Code
|
||||
ul.sessions
|
||||
each session in sessions
|
||||
li
|
||||
- var sessionLink = "/play/level/" + session.levelID + "?team=" + (session.team || 'humans') + (myProfile ? '' : "&session=" + session._id);
|
||||
a(href=sessionLink)
|
||||
span= session.levelName
|
||||
if session.team
|
||||
span #{session.team}
|
||||
if session.codeLanguage != 'javascript'
|
||||
span - #{{coffeescript: 'CoffeeScript', python: 'Python', lua: 'Lua', io: 'Io', clojure: 'Clojure'}[session.codeLanguage]}
|
||||
|
||||
.middle-column.full-height-column
|
||||
.sub-column
|
||||
#name-container.editable-section
|
||||
|
@ -222,11 +230,11 @@ block content
|
|||
h3.edit-label Tag your programming skills
|
||||
each skill in ["python", "coffeescript", "node", "ios", "objective-c", "javascript", "app-engine", "mongodb", "web dev", "django", "backbone"]
|
||||
code.edit-example-tag= skill
|
||||
span
|
||||
span
|
||||
else
|
||||
each skill in profile.skills
|
||||
code= skill
|
||||
span
|
||||
span
|
||||
|
||||
form.editable-form
|
||||
.editable-icon.glyphicon.glyphicon-remove
|
||||
|
@ -267,7 +275,7 @@ block content
|
|||
img.header-icon(src="/images/pages/account/profile/work.png", alt="")
|
||||
span(data-i18n="account_profile.work_experience") Work Experience
|
||||
| - #{profile.experience}
|
||||
|
|
||||
|
|
||||
span(data-i18n=profile.experience == 1 ? "units.year" : "units.years")
|
||||
each job in profile.work
|
||||
if job.role && job.employer
|
||||
|
@ -454,9 +462,9 @@ block content
|
|||
else if user
|
||||
.public-profile-container
|
||||
h2
|
||||
span(data-i18n="account_profile.profile_for_prefix") Profile for
|
||||
span(data-i18n="account_profile.profile_for_prefix") Profile for
|
||||
span= user.get('name') || "Anonymous Wizard"
|
||||
span(data-i18n="account_profile.profile_for_suffix")
|
||||
span(data-i18n="account_profile.profile_for_suffix")
|
||||
|
||||
img.profile-photo(src=user.getPhotoURL(256))
|
||||
|
||||
|
@ -465,8 +473,8 @@ block content
|
|||
else
|
||||
.public-profile-container
|
||||
h2
|
||||
span(data-i18n="account_profile.profile_for_prefix") Profile for
|
||||
span(data-i18n="account_profile.profile_for_prefix") Profile for
|
||||
span= userID
|
||||
span(data-i18n="account_profile.profile_for_suffix")
|
||||
|
|
||||
span(data-i18n="account_profile.profile_for_suffix")
|
||||
|
|
||||
span(data-i18n="loading_error.not_found")
|
||||
|
|
|
@ -23,6 +23,8 @@ block content
|
|||
a(href="/admin/users", data-i18n="admin.av_entities_users_url") Users
|
||||
li
|
||||
a(href="/admin/level_sessions", data-i18n="admin.av_entities_active_instances_url") Active Instances
|
||||
li
|
||||
a(href="/admin/employer_list", data-i18n="admin.av_entities_employer_list_url") Employer List
|
||||
|
||||
h4(data-i18n="admin.av_other_sub_title") Other
|
||||
|
||||
|
@ -31,3 +33,11 @@ block content
|
|||
a(href="/admin/base", data-i18n="admin.av_other_debug_base_url") Base (for debugging base.jade)
|
||||
li
|
||||
a(href="/admin/clas", data-i18n="admin.clas") CLAs
|
||||
|
||||
hr
|
||||
|
||||
h3 Achievements
|
||||
p This is just some stuff for temporary achievement testing. Should be replaced by a demo system.
|
||||
|
||||
input#increment-field(type="text")
|
||||
a.btn.btn-secondary#increment-button(href="#") Increment
|
||||
|
|
65
app/templates/admin/employer_list.jade
Normal file
65
app/templates/admin/employer_list.jade
Normal file
|
@ -0,0 +1,65 @@
|
|||
extends /templates/base
|
||||
|
||||
block content
|
||||
|
||||
if !me.isAdmin()
|
||||
h1 Admin Only
|
||||
else
|
||||
h1(data-i18n="admin.av_entities_employer_list_url") Employer List
|
||||
|
||||
p
|
||||
| We currently have
|
||||
if employers.length
|
||||
| #{employers.length}
|
||||
else
|
||||
| ...
|
||||
| employers in the system.
|
||||
|
||||
if employers.length
|
||||
table.table.table-condensed.table-hover.table-responsive.tablesorter
|
||||
thead
|
||||
tr
|
||||
th(data-i18n="general.name") Name
|
||||
th Company
|
||||
th(data-i18n="general.email") Email
|
||||
th Logins
|
||||
th Candidates Viewed
|
||||
th Candidates Contacted
|
||||
th Signed Up
|
||||
|
||||
tbody
|
||||
for employer, index in employers
|
||||
- var activity = employer.get('activity') || {};
|
||||
- var linkedIn = employer.get('signedEmployerAgreement').data
|
||||
tr(data-employer-id=employer.id)
|
||||
td
|
||||
img(src=employer.getPhotoURL(50), height=50)
|
||||
p
|
||||
if employer.get('firstName')
|
||||
span= employer.get('firstName') + ' ' + employer.get('lastName')
|
||||
if employer.get('name')
|
||||
| -
|
||||
else if linkedIn.firstName
|
||||
span= linkedIn.firstName + ' ' + linkedIn.lastName
|
||||
if employer.get('name')
|
||||
| -
|
||||
if employer.get('name')
|
||||
span= employer.get('name')
|
||||
if !employer.get('firstName') && !linkedIn.firstName && !employer.get('name')
|
||||
| Anoner
|
||||
td
|
||||
a(href=employer.get('signedEmployerAgreement').data.publicProfileUrl)= employer.get('employerAt')
|
||||
td= employer.get('email')
|
||||
for a in ['login', 'view_candidate', 'contact_candidate']
|
||||
- var act = activity[a];
|
||||
if act
|
||||
td
|
||||
strong= act.count
|
||||
|
|
||||
br
|
||||
span= moment(act.first).fromNow()
|
||||
br
|
||||
span= moment(act.last).fromNow()
|
||||
else
|
||||
td 0
|
||||
td(data-employer-age=(new Date() - new Date(employer.get('signedEmployerAgreement').date)) / 86400 / 1000)= moment(employer.get('signedEmployerAgreement').date).fromNow()
|
|
@ -11,19 +11,21 @@ block content
|
|||
li.active
|
||||
| #{achievement.attributes.name}
|
||||
|
||||
button(data-i18n="common.save", disabled=authorized === true ? undefined : "true").btn.btn-primary#save-button Save
|
||||
button(data-i18n="", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#recalculate-button Recalculate
|
||||
button(data-i18n="common.save", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#save-button Save
|
||||
|
||||
h3(data-i18n="achievement.edit_achievement_title") Edit Achievement
|
||||
span
|
||||
|: "#{achievement.attributes.name}"
|
||||
h3(data-i18n="achievement.edit_achievement_title") Edit Achievement
|
||||
span
|
||||
|: "#{achievement.attributes.name}"
|
||||
|
||||
#achievement-treema
|
||||
#achievement-treema
|
||||
|
||||
#achievement-view
|
||||
#achievement-view
|
||||
|
||||
hr
|
||||
hr
|
||||
|
||||
div#error-view
|
||||
|
||||
div#error-view
|
||||
else
|
||||
.alert.alert-danger
|
||||
span Admin only. Turn around.
|
||||
|
|
|
@ -2,66 +2,117 @@ extends /templates/base
|
|||
|
||||
block content
|
||||
|
||||
h1(data-i18n="employers.want_to_hire_our_players") Want to hire expert CodeCombat players?
|
||||
h1(data-i18n="employers.want_to_hire_our_players") Hire CodeCombat Players
|
||||
|
||||
div#info_wrapper
|
||||
|
||||
div#leftside
|
||||
|
||||
div.information_row
|
||||
|
||||
img(class="employer_icon" src="/images/pages/employer/employer_icon1.png")
|
||||
|
||||
h2(data-i18n="employers.what") What is CodeCombat?
|
||||
|
||||
p(data-i18n="employers.what_blurb") CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. We support JavaScript, Python, Lua, Clojure, CoffeeScript, and Io.
|
||||
|
||||
div.information_row
|
||||
|
||||
img(class="employer_icon" src="/images/pages/employer/employer_icon3.png")
|
||||
|
||||
h2(data-i18n="employers.who") Who Are the Players?
|
||||
|
||||
p(data-i18n="employers.who_blurb") CodeCombateers are software developers who enjoy using their programming skills to play games. They range from college seniors at top 20 engineering programs to 20-year industry veterans.
|
||||
|
||||
div#rightside
|
||||
|
||||
div.information_row
|
||||
|
||||
img(class="employer_icon" src="/images/pages/employer/employer_icon2.png")
|
||||
|
||||
h2(data-i18n="employers.how") How Do We Find Developers?
|
||||
|
||||
p(data-i18n="employers.how_blurb") We host competitive tournaments to attract competitive software engieneers. We then use in-house algorithms to identify the best players among the top 5% of tournament winners.
|
||||
|
||||
div.information_row
|
||||
|
||||
img(class="employer_icon" src="/images/pages/employer/employer_icon4.png")
|
||||
|
||||
h2(data-i18n="employers.why") Why Hire Through Us?
|
||||
|
||||
p
|
||||
span(data-i18n="employers.why_blurb_1") We will save you time. Every CodeCombateer we feaure is
|
||||
strong(data-i18n="employers.why_blurb_2") looking for work
|
||||
span(data-i18n="employers.why_blurb_3") , has
|
||||
strong(data-i18n="employers.why_blurb_4") demonstrated top notch technical skills
|
||||
span(data-i18n="employers.why_blurb_5") , and has been
|
||||
strong(data-i18n="employers.why_blurb_6") personally screened by us
|
||||
span(data-i18n="employers.why_blurb_7") . Stop screening and start hiring.
|
||||
|
||||
if !isEmployer && !me.isAdmin()
|
||||
h3.see-candidates-header
|
||||
a#see-candidates(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/employer_signup", data-i18n="employers.see_candidates") Click here to see our candidates
|
||||
|
||||
p
|
||||
span(data-i18n="employers.candidates_count_prefix") We currently have
|
||||
if candidates.length
|
||||
| #{candidates.length}
|
||||
else
|
||||
span(data-i18n="employers.candidates_count_many") many
|
||||
|
|
||||
span(data-i18n="employers.candidates_count_suffix") highly skilled and vetted developers looking for work.
|
||||
if !isEmployer
|
||||
|
||||
h3
|
||||
a#see-candidates(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/employer_signup", data-i18n="employers.see_candidates") Click here to see our candidates
|
||||
|
||||
if candidates.length
|
||||
table.table.table-condensed.table-hover.table-responsive.tablesorter
|
||||
thead
|
||||
tr
|
||||
th(data-i18n="general.name") Name
|
||||
th(data-i18n="employers.candidate_location") Location
|
||||
th(data-i18n="employers.candidate_looking_for") Looking For
|
||||
th(data-i18n="employers.candidate_role") Role
|
||||
th(data-i18n="employers.candidate_top_skills") Top Skills
|
||||
th(data-i18n="employers.candidate_years_experience") Yrs Exp
|
||||
th(data-i18n="employers.candidate_last_updated") Last Updated
|
||||
if me.isAdmin()
|
||||
th(data-i18n="employers.candidate_approved") Us?
|
||||
th(data-i18n="employers.candidate_active") Them?
|
||||
|
||||
tbody
|
||||
for candidate, index in candidates
|
||||
- var profile = candidate.get('jobProfile');
|
||||
- var authorized = candidate.id; // If we have the id, then we are authorized.
|
||||
tr(data-candidate-id=candidate.id, id=candidate.id)
|
||||
td
|
||||
if authorized
|
||||
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=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)
|
||||
p Developer ##{index + 1}
|
||||
if profile.country == 'USA'
|
||||
td= profile.city
|
||||
else
|
||||
td= profile.country
|
||||
td= profile.lookingFor
|
||||
td= profile.jobTitle
|
||||
td
|
||||
each skill in profile.skills.slice(0, 10)
|
||||
code= skill
|
||||
span
|
||||
td= profile.experience
|
||||
td(data-profile-age=(new Date() - new Date(profile.updated)) / 86400 / 1000)= moment(profile.updated).fromNow()
|
||||
if me.isAdmin()
|
||||
if candidate.get('jobProfileApproved')
|
||||
td ✓
|
||||
else
|
||||
td ✗
|
||||
if profile.active
|
||||
td ✓
|
||||
else
|
||||
td ✗
|
||||
|
||||
ul.nav.nav-pills
|
||||
li.active
|
||||
a(href="#featured-candidates", data-toggle="tab")
|
||||
span(data-i18n="employers.featured_developers") Featured Developers
|
||||
| (#{featuredCandidates.length})
|
||||
if otherCandidates.length
|
||||
li
|
||||
a(href="#other-candidates", data-toggle="tab")
|
||||
span(data-i18n="employers.other_developers") Other Developers
|
||||
| (#{otherCandidates.length})
|
||||
if me.isAdmin() && inactiveCandidates.length
|
||||
li
|
||||
a(href="#inactive-candidates", data-toggle="tab")
|
||||
span(data-i18n="employers.inactive_developers") Inactive Developers
|
||||
| (#{inactiveCandidates.length})
|
||||
|
||||
div.tab-content
|
||||
for area, tabIndex in [{id: "featured-candidates", candidates: featuredCandidates}, {id: "other-candidates", candidates: otherCandidates}, {id: "inactive-candidates", candidates: inactiveCandidates}]
|
||||
div(class="tab-pane well" + (tabIndex ? "" : " active"), id=area.id)
|
||||
table.table.table-condensed.table-hover.table-responsive.tablesorter
|
||||
thead
|
||||
tr
|
||||
th(data-i18n="general.name") Name
|
||||
th(data-i18n="employers.candidate_location") Location
|
||||
th(data-i18n="employers.candidate_looking_for") Looking For
|
||||
th(data-i18n="employers.candidate_role") Role
|
||||
th(data-i18n="employers.candidate_top_skills") Top Skills
|
||||
th(data-i18n="employers.candidate_years_experience") Yrs Exp
|
||||
th(data-i18n="employers.candidate_last_updated") Last Updated
|
||||
if me.isAdmin() && area.id == 'inactive-candidates'
|
||||
th ✓?
|
||||
|
||||
tbody
|
||||
for candidate, index in area.candidates
|
||||
- var profile = candidate.get('jobProfile');
|
||||
- var authorized = candidate.id; // If we have the id, then we are authorized.
|
||||
tr(data-candidate-id=candidate.id, id=candidate.id)
|
||||
td
|
||||
if authorized
|
||||
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=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)
|
||||
p Developer ##{index + 1 + (area.id == 'featured-candidates' ? 0 : featuredCandidates.length)}
|
||||
if profile.country == 'USA'
|
||||
td= profile.city
|
||||
else
|
||||
td= profile.country
|
||||
td= profile.lookingFor
|
||||
td= profile.jobTitle
|
||||
td
|
||||
each skill in profile.skills.slice(0, 10)
|
||||
code= skill
|
||||
span
|
||||
td= profile.experience
|
||||
td(data-profile-age=(new Date() - new Date(profile.updated)) / 86400 / 1000)= moment(profile.updated).fromNow()
|
||||
if me.isAdmin() && area.id == 'inactive-candidates'
|
||||
if candidate.get('jobProfileApproved')
|
||||
td ✓
|
||||
else
|
||||
td ✗
|
||||
|
|
|
@ -37,6 +37,7 @@ block content
|
|||
h3(data-i18n="play_level.tip_reticulating") Reticulating Splines...
|
||||
.progress.progress-striped.active
|
||||
.progress-bar
|
||||
|
||||
else
|
||||
.alert.alert-danger
|
||||
span Admin only. Turn around.
|
||||
|
|
11
app/templates/modal/confirm.jade
Normal file
11
app/templates/modal/confirm.jade
Normal file
|
@ -0,0 +1,11 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3 #{confirmTitle}
|
||||
|
||||
block modal-body-content
|
||||
p #{confirmBody}
|
||||
|
||||
block modal-footer-content
|
||||
button.btn.btn-secondary#decline-button(type="button", data-dismiss="modal") #{confirmDecline}
|
||||
button.btn.btn-primary#confirm-button(type="button", data-dismiss=closeOnConfirm === true ? "modal" : undefined) #{confirmConfirm}
|
|
@ -24,4 +24,4 @@
|
|||
block modal-footer
|
||||
.modal-footer
|
||||
block modal-footer-content
|
||||
button.btn.btn-primary(type="button", data-dismiss="modal", aria-hidden="true", data-i18n="modal.okay") Okay
|
||||
button.btn.btn-primary(type="button", data-dismiss="modal", aria-hidden="true", data-i18n="modal.okay") Okay
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@
|
|||
.level-content
|
||||
#control-bar-view
|
||||
#canvas-wrapper
|
||||
canvas(width=924, height=589)#surface
|
||||
canvas(width=1848, height=1178)#surface
|
||||
#canvas-left-gradient.gradient
|
||||
#canvas-top-gradient.gradient
|
||||
#gold-view.secret.expanded
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
View = require 'views/kinds/RootView'
|
||||
template = require 'templates/account/profile'
|
||||
User = require 'models/User'
|
||||
LevelSession = require 'models/LevelSession'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
{me} = require 'lib/auth'
|
||||
JobProfileContactView = require 'views/modal/job_profile_contact_modal'
|
||||
JobProfileView = require 'views/account/job_profile_view'
|
||||
forms = require 'lib/forms'
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
url: -> "/db/user/#{@userID}/level.sessions/employer"
|
||||
model: LevelSession
|
||||
constructor: (@userID) ->
|
||||
super()
|
||||
|
||||
module.exports = class ProfileView extends View
|
||||
id: "profile-view"
|
||||
template: template
|
||||
|
@ -42,9 +50,7 @@ module.exports = class ProfileView extends View
|
|||
if User.isObjectID @userID
|
||||
@finishInit()
|
||||
else
|
||||
console.log "getting", @userID
|
||||
$.ajax "/db/user/#{@userID}/nameToID", success: (@userID) =>
|
||||
console.log " got", @userID
|
||||
@finishInit() unless @destroyed
|
||||
@render()
|
||||
|
||||
|
@ -59,8 +65,11 @@ module.exports = class ProfileView extends View
|
|||
@user.fetch()
|
||||
@listenTo @user, "sync", =>
|
||||
@render()
|
||||
$.post "/db/user/#{me.id}/track/view_candidate"
|
||||
$.post "/db/user/#{@userID}/track/viewed_by_employer" unless me.isAdmin()
|
||||
else
|
||||
@user = User.getByID(@userID)
|
||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model
|
||||
|
||||
onLinkedInLoaded: =>
|
||||
@linkedinLoaded = true
|
||||
|
@ -78,11 +87,11 @@ module.exports = class ProfileView extends View
|
|||
@renderLinkedInButton()
|
||||
else
|
||||
@waitingForLinkedIn = true
|
||||
|
||||
importLinkedIn: =>
|
||||
overwriteConfirm = confirm("Importing LinkedIn data will overwrite your current work experience, skills, name, descriptions, and education. Continue?")
|
||||
unless overwriteConfirm then return
|
||||
application.linkedinHandler.getProfileData (err, profileData) =>
|
||||
console.log profileData
|
||||
@processLinkedInProfileData profileData
|
||||
jobProfileSchema: -> @user.schema().properties.jobProfile.properties
|
||||
|
||||
|
@ -113,7 +122,7 @@ module.exports = class ProfileView extends View
|
|||
for position in p["positions"]["values"]
|
||||
workObj = {}
|
||||
descriptionMaxLength = workSchema.description.maxLength
|
||||
|
||||
|
||||
workObj.description = position.summary?.slice(0,descriptionMaxLength)
|
||||
workObj.description ?= ""
|
||||
if position.startDate?.year?
|
||||
|
@ -215,6 +224,11 @@ module.exports = class ProfileView extends View
|
|||
links = ($.extend(true, {}, link) for link in links)
|
||||
link.icon = @iconForLink link for link in links
|
||||
context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first
|
||||
if @sessions
|
||||
context.sessions = (s.attributes for s in @sessions.models when (s.get('submitted') or s.get('level-id') is 'gridmancer'))
|
||||
context.sessions.sort (a, b) -> (b.playtime ? 0) - (a.playtime ? 0)
|
||||
else
|
||||
context.sessions = []
|
||||
context
|
||||
|
||||
afterRender: ->
|
||||
|
@ -301,7 +315,7 @@ module.exports = class ProfileView extends View
|
|||
errors = @user.validate()
|
||||
return @showErrors errors if errors
|
||||
jobProfile = @user.get('jobProfile')
|
||||
jobProfile.updated = (new Date()).toISOString()
|
||||
jobProfile.updated = (new Date()).toISOString() if @user is me
|
||||
@user.set 'jobProfile', jobProfile
|
||||
return unless res = @user.save()
|
||||
res.error =>
|
||||
|
|
|
@ -113,7 +113,7 @@ module.exports = class SettingsView extends View
|
|||
|
||||
return unless me.hasLocalChanges()
|
||||
|
||||
res = me.save()
|
||||
res = me.patch()
|
||||
return unless res
|
||||
save = $('#save-button', @$el).text($.i18n.t('common.saving', defaultValue: 'Saving...'))
|
||||
.removeClass('btn-danger').addClass('btn-success').show()
|
||||
|
|
160
app/views/admin/employer_list_view.coffee
Normal file
160
app/views/admin/employer_list_view.coffee
Normal file
|
@ -0,0 +1,160 @@
|
|||
View = require 'views/kinds/RootView'
|
||||
template = require 'templates/admin/employer_list'
|
||||
app = require 'application'
|
||||
User = require 'models/User'
|
||||
{me} = require 'lib/auth'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
ModelModal = require 'views/modal/model_modal'
|
||||
|
||||
class EmployersCollection extends CocoCollection
|
||||
url: '/db/user/x/employers'
|
||||
model: User
|
||||
|
||||
module.exports = class EmployersView extends View
|
||||
id: "employers-view"
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click tbody tr td:first-child': 'onEmployerClicked'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
@getEmployers()
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@sortTable() if @employers.models.length
|
||||
|
||||
getRenderData: ->
|
||||
ctx = super()
|
||||
ctx.employers = @employers.models
|
||||
ctx.moment = moment
|
||||
ctx
|
||||
|
||||
getEmployers: ->
|
||||
@employers = new EmployersCollection()
|
||||
@employers.fetch()
|
||||
# Re-render when we have fetched them, but don't wait and show a progress bar while loading.
|
||||
@listenToOnce @employers, 'all', => @render()
|
||||
|
||||
sortTable: ->
|
||||
# http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
|
||||
$.extend $.tablesorter.themes.bootstrap,
|
||||
# these classes are added to the table. To see other table classes available,
|
||||
# look here: http://twitter.github.com/bootstrap/base-css.html#tables
|
||||
table: "table table-bordered"
|
||||
caption: "caption"
|
||||
header: "bootstrap-header" # give the header a gradient background
|
||||
footerRow: ""
|
||||
footerCells: ""
|
||||
icons: "" # add "icon-white" to make them white; this icon class is added to the <i> in the header
|
||||
sortNone: "bootstrap-icon-unsorted"
|
||||
sortAsc: "icon-chevron-up" # glyphicon glyphicon-chevron-up" # we are still using v2 icons
|
||||
sortDesc: "icon-chevron-down" # glyphicon-chevron-down" # we are still using v2 icons
|
||||
active: "" # applied when column is sorted
|
||||
hover: "" # use custom css here - bootstrap class may not override it
|
||||
filterRow: "" # filter row class
|
||||
even: "" # odd row zebra striping
|
||||
odd: "" # even row zebra striping
|
||||
|
||||
|
||||
# e = exact text from cell
|
||||
# n = normalized value returned by the column parser
|
||||
# f = search filter input value
|
||||
# i = column index
|
||||
# $r = ???
|
||||
filterSelectExactMatch = (e, n, f, i, $r) -> e is f
|
||||
|
||||
# call the tablesorter plugin and apply the uitheme widget
|
||||
@$el.find(".tablesorter").tablesorter
|
||||
theme: "bootstrap"
|
||||
widthFixed: true
|
||||
headerTemplate: "{content} {icon}"
|
||||
textSorter:
|
||||
6: (a, b, direction, column, table) ->
|
||||
days = []
|
||||
for s in [a, b]
|
||||
n = parseInt s
|
||||
n = 0 unless _.isNumber n
|
||||
n = 1 if /^a/.test s
|
||||
for [duration, factor] in [
|
||||
[/second/i, 1 / (86400 * 1000)]
|
||||
[/minute/i, 1 / 1440]
|
||||
[/hour/i, 1 / 24]
|
||||
[/week/i, 7]
|
||||
[/month/i, 30.42]
|
||||
[/year/i, 365.2425]
|
||||
]
|
||||
if duration.test s
|
||||
n *= factor
|
||||
break
|
||||
if /^in /i.test s
|
||||
n *= -1
|
||||
days.push n
|
||||
days[0] - days[1]
|
||||
sortList: [[6, 0]]
|
||||
# widget code contained in the jquery.tablesorter.widgets.js file
|
||||
# use the zebra stripe widget if you plan on hiding any rows (filter widget)
|
||||
widgets: ["uitheme", "zebra", "filter"]
|
||||
widgetOptions:
|
||||
# using the default zebra striping class name, so it actually isn't included in the theme variable above
|
||||
# this is ONLY needed for bootstrap theming if you are using the filter widget, because rows are hidden
|
||||
zebra: ["even", "odd"]
|
||||
|
||||
# extra css class applied to the table row containing the filters & the inputs within that row
|
||||
filter_cssFilter: ""
|
||||
|
||||
# If there are child rows in the table (rows with class name from "cssChildRow" option)
|
||||
# and this option is true and a match is found anywhere in the child row, then it will make that row
|
||||
# visible; default is false
|
||||
filter_childRows: false
|
||||
|
||||
# if true, filters are collapsed initially, but can be revealed by hovering over the grey bar immediately
|
||||
# below the header row. Additionally, tabbing through the document will open the filter row when an input gets focus
|
||||
filter_hideFilters: false
|
||||
|
||||
# Set this option to false to make the searches case sensitive
|
||||
filter_ignoreCase: true
|
||||
|
||||
# jQuery selector string of an element used to reset the filters
|
||||
filter_reset: ".reset"
|
||||
|
||||
# Use the $.tablesorter.storage utility to save the most recent filters
|
||||
filter_saveFilters: true
|
||||
|
||||
# Delay in milliseconds before the filter widget starts searching; This option prevents searching for
|
||||
# every character while typing and should make searching large tables faster.
|
||||
filter_searchDelay: 150
|
||||
|
||||
# Set this option to true to use the filter to find text from the start of the column
|
||||
# So typing in "a" will find "albert" but not "frank", both have a's; default is false
|
||||
filter_startsWith: false
|
||||
|
||||
filter_functions:
|
||||
3:
|
||||
"0-1": (e, n, f, i, $r) -> parseInt(e) <= 1
|
||||
"2-5": (e, n, f, i, $r) -> 2 <= parseInt(e) <= 5
|
||||
"6+": (e, n, f, i, $r) -> 6 <= parseInt(e)
|
||||
4:
|
||||
"0-1": (e, n, f, i, $r) -> parseInt(e) <= 1
|
||||
"2-5": (e, n, f, i, $r) -> 2 <= parseInt(e) <= 5
|
||||
"6+": (e, n, f, i, $r) -> 6 <= parseInt(e)
|
||||
5:
|
||||
"0-1": (e, n, f, i, $r) -> parseInt(e) <= 1
|
||||
"2-5": (e, n, f, i, $r) -> 2 <= parseInt(e) <= 5
|
||||
"6+": (e, n, f, i, $r) -> 6 <= parseInt(e)
|
||||
6:
|
||||
"Last day": (e, n, f, i, $r) ->
|
||||
days = parseFloat $($r.find('td')[i]).data('employer-age')
|
||||
days <= 1
|
||||
"Last week": (e, n, f, i, $r) ->
|
||||
days = parseFloat $($r.find('td')[i]).data('employer-age')
|
||||
days <= 7
|
||||
"Last 4 weeks": (e, n, f, i, $r) ->
|
||||
days = parseFloat $($r.find('td')[i]).data('employer-age')
|
||||
days <= 28
|
||||
|
||||
onEmployerClicked: (e) ->
|
||||
return unless id = $(e.target).closest('tr').data('employer-id')
|
||||
employer = new User _id: id
|
||||
@openModalView new ModelModal models: [employer]
|
|
@ -8,6 +8,7 @@ module.exports = class AdminView extends View
|
|||
|
||||
events:
|
||||
'click #enter-espionage-mode': 'enterEspionageMode'
|
||||
'click #increment-button': 'incrementUserAttribute'
|
||||
|
||||
enterEspionageMode: ->
|
||||
userEmail = $("#user-email").val().toLowerCase()
|
||||
|
@ -29,3 +30,8 @@ module.exports = class AdminView extends View
|
|||
|
||||
espionageFailure: (jqxhr, status,error)->
|
||||
console.log "There was an error entering espionage mode: #{error}"
|
||||
|
||||
incrementUserAttribute: (e) ->
|
||||
val = $('#increment-field').val()
|
||||
me.set(val, me.get(val) + 1)
|
||||
me.save()
|
||||
|
|
|
@ -36,7 +36,7 @@ module.exports = class ContributeClassView extends View
|
|||
subscription = el.attr('name')
|
||||
|
||||
me.setEmailSubscription subscription+'News', checked
|
||||
me.save()
|
||||
me.patch()
|
||||
@openModalView new SignupModalView() if me.get 'anonymous'
|
||||
el.parent().find('.saved-notification').finish().show('fast').delay(3000).fadeOut(2000)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
View = require 'views/kinds/RootView'
|
||||
template = require 'templates/editor/achievement/edit'
|
||||
Achievement = require 'models/Achievement'
|
||||
ConfirmModal = require 'views/modal/confirm'
|
||||
|
||||
module.exports = class AchievementEditView extends View
|
||||
id: "editor-achievement-edit-view"
|
||||
|
@ -9,6 +10,7 @@ module.exports = class AchievementEditView extends View
|
|||
|
||||
events:
|
||||
'click #save-button': 'saveAchievement'
|
||||
'click #recalculate-button': 'confirmRecalculation'
|
||||
|
||||
subscriptions:
|
||||
'save-new': 'saveAchievement'
|
||||
|
@ -72,3 +74,34 @@ module.exports = class AchievementEditView extends View
|
|||
res.success =>
|
||||
url = "/editor/achievement/#{@achievement.get('slug') or @achievement.id}"
|
||||
document.location.href = url
|
||||
|
||||
confirmRecalculation: (e) ->
|
||||
renderData =
|
||||
'confirmTitle': "Are you really sure?"
|
||||
'confirmBody': "This will trigger recalculation of the achievement for all users. Are you really sure you want to go down this path?"
|
||||
'confirmDecline': "Not really"
|
||||
'confirmConfirm': "Definitely"
|
||||
|
||||
confirmModal = new ConfirmModal(renderData)
|
||||
confirmModal.onConfirm @recalculateAchievement
|
||||
@openModalView confirmModal
|
||||
|
||||
recalculateAchievement: =>
|
||||
$.ajax
|
||||
data: JSON.stringify(achievements: [@achievement.get('slug') or @achievement.get('_id')])
|
||||
success: (data, status, jqXHR) ->
|
||||
noty
|
||||
timeout: 5000
|
||||
text: 'Recalculation process started'
|
||||
type: 'success'
|
||||
layout: 'topCenter'
|
||||
error: (jqXHR, status, error) ->
|
||||
console.error jqXHR
|
||||
noty
|
||||
timeout: 5000
|
||||
text: "Starting recalculation process failed with error code #{jqXHR.status}"
|
||||
type: 'error'
|
||||
layout: 'topCenter'
|
||||
url: '/admin/earned.achievement/recalculate'
|
||||
type: 'POST'
|
||||
contentType: 'application/json'
|
||||
|
|
|
@ -4,7 +4,7 @@ ThangType = require 'models/ThangType'
|
|||
CocoCollection = require 'collections/CocoCollection'
|
||||
|
||||
class ThangTypeSearchCollection extends CocoCollection
|
||||
url: '/db/thang.type/search?project=true'
|
||||
url: '/db/thang.type?project=true'
|
||||
model: ThangType
|
||||
|
||||
addTerm: (term) ->
|
||||
|
@ -73,4 +73,4 @@ module.exports = class AddThangsView extends View
|
|||
|
||||
onEscapePressed: ->
|
||||
@$el.find('input#thang-search').val("")
|
||||
@runSearch
|
||||
@runSearch
|
||||
|
|
|
@ -8,7 +8,7 @@ SaveVersionModal = require 'views/modal/save_version_modal'
|
|||
module.exports = class LevelComponentEditView extends View
|
||||
id: "editor-level-component-edit-view"
|
||||
template: template
|
||||
editableSettings: ['name', 'description', 'system', 'language', 'dependencies', 'propertyDocumentation', 'i18n']
|
||||
editableSettings: ['name', 'description', 'system', 'codeLanguage', 'dependencies', 'propertyDocumentation', 'i18n']
|
||||
|
||||
events:
|
||||
'click #done-editing-component-button': 'endEditing'
|
||||
|
|
|
@ -5,7 +5,7 @@ LevelSystem = require 'models/LevelSystem'
|
|||
CocoCollection = require 'collections/CocoCollection'
|
||||
|
||||
class LevelSystemSearchCollection extends CocoCollection
|
||||
url: '/db/level_system/search'
|
||||
url: '/db/level_system'
|
||||
model: LevelSystem
|
||||
|
||||
module.exports = class LevelSystemAddView extends View
|
||||
|
|
|
@ -8,7 +8,7 @@ SaveVersionModal = require 'views/modal/save_version_modal'
|
|||
module.exports = class LevelSystemEditView extends View
|
||||
id: "editor-level-system-edit-view"
|
||||
template: template
|
||||
editableSettings: ['name', 'description', 'language', 'dependencies', 'propertyDocumentation', 'i18n']
|
||||
editableSettings: ['name', 'description', 'codeLanguage', 'dependencies', 'propertyDocumentation', 'i18n']
|
||||
|
||||
events:
|
||||
'click #done-editing-system-button': 'endEditing'
|
||||
|
|
|
@ -21,7 +21,7 @@ componentOriginals =
|
|||
"physics.Physical" : "524b75ad7fc0f6d519000001"
|
||||
|
||||
class ThangTypeSearchCollection extends CocoCollection
|
||||
url: '/db/thang.type/search?project=original,name,version,slug,kind,components'
|
||||
url: '/db/thang.type?project=original,name,version,slug,kind,components'
|
||||
model: ThangType
|
||||
|
||||
module.exports = class ThangsTabView extends View
|
||||
|
|
|
@ -20,10 +20,7 @@ module.exports = class EmployersView extends View
|
|||
constructor: (options) ->
|
||||
super options
|
||||
@getCandidates()
|
||||
checkForEmployerSignupHash: =>
|
||||
if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions"))
|
||||
@openModalView application.router.getView("modal/employer_signup","_modal")
|
||||
window.location.hash = ""
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
@sortTable() if @candidates.models.length
|
||||
|
@ -33,13 +30,20 @@ module.exports = class EmployersView extends View
|
|||
_.delay @checkForEmployerSignupHash, 500
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.candidates = @candidates.models
|
||||
userPermissions = me.get('permissions') ? []
|
||||
ctx = super()
|
||||
ctx.isEmployer = @isEmployer()
|
||||
ctx.candidates = _.sortBy @candidates.models, (c) -> c.get('jobProfile').updated
|
||||
ctx.activeCandidates = _.filter ctx.candidates, (c) -> c.get('jobProfile').active
|
||||
ctx.inactiveCandidates = _.reject ctx.candidates, (c) -> c.get('jobProfile').active
|
||||
ctx.featuredCandidates = _.filter ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
||||
ctx.otherCandidates = _.reject ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
||||
ctx.moment = moment
|
||||
ctx._ = _
|
||||
ctx
|
||||
|
||||
c.isEmployer = _.contains userPermissions, "employer"
|
||||
c.moment = moment
|
||||
c
|
||||
isEmployer: ->
|
||||
userPermissions = me.get('permissions') ? []
|
||||
_.contains userPermissions, "employer"
|
||||
|
||||
getCandidates: ->
|
||||
@candidates = new CandidatesCollection()
|
||||
|
@ -48,6 +52,7 @@ module.exports = class EmployersView extends View
|
|||
@listenToOnce @candidates, 'all', @renderCandidatesAndSetupScrolling
|
||||
|
||||
renderCandidatesAndSetupScrolling: =>
|
||||
|
||||
@render()
|
||||
$(".nano").nanoScroller()
|
||||
if window.history?.state?.lastViewedCandidateID
|
||||
|
@ -55,6 +60,11 @@ module.exports = class EmployersView extends View
|
|||
else if window.location.hash.length is 25
|
||||
$(".nano").nanoScroller({scrollTo:$(window.location.hash)})
|
||||
|
||||
checkForEmployerSignupHash: =>
|
||||
if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions"))
|
||||
@openModalView application.router.getView("modal/employer_signup","_modal")
|
||||
window.location.hash = ""
|
||||
|
||||
sortTable: ->
|
||||
# http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
|
||||
$.extend $.tablesorter.themes.bootstrap,
|
||||
|
@ -110,7 +120,7 @@ module.exports = class EmployersView extends View
|
|||
n *= -1
|
||||
days.push n
|
||||
days[0] - days[1]
|
||||
sortList: [[6, 0]]
|
||||
sortList: if @isEmployer() or me.isAdmin() then [[6, 0]] else [[0, 1]]
|
||||
# widget code contained in the jquery.tablesorter.widgets.js file
|
||||
# use the zebra stripe widget if you plan on hiding any rows (filter widget)
|
||||
widgets: ["uitheme", "zebra", "filter"]
|
||||
|
@ -172,9 +182,6 @@ module.exports = class EmployersView extends View
|
|||
7:
|
||||
"✓": filterSelectExactMatch
|
||||
"✗": filterSelectExactMatch
|
||||
8:
|
||||
"✓": filterSelectExactMatch
|
||||
"✗": filterSelectExactMatch
|
||||
|
||||
onCandidateClicked: (e) ->
|
||||
id = $(e.target).closest('tr').data('candidate-id')
|
||||
|
|
|
@ -8,6 +8,7 @@ locale = require 'locale/locale'
|
|||
|
||||
Achievement = require '../../models/Achievement'
|
||||
User = require '../../models/User'
|
||||
# TODO remove
|
||||
|
||||
filterKeyboardEvents = (allowedEvents, func) ->
|
||||
return (splat...) ->
|
||||
|
@ -25,26 +26,24 @@ module.exports = class RootView extends CocoView
|
|||
subscriptions:
|
||||
'achievements:new': 'handleNewAchievements'
|
||||
|
||||
initialize: ->
|
||||
$ =>
|
||||
# TODO Ruben remove this. Allows for easy testing right now though
|
||||
#test = new Achievement(_id:'537ce4855c91b8d1dda7fda8')
|
||||
#test.fetch(success:@showNewAchievement)
|
||||
|
||||
showNewAchievement: (achievement) ->
|
||||
showNewAchievement: (achievement, earnedAchievement) ->
|
||||
currentLevel = me.level()
|
||||
nextLevel = currentLevel + 1
|
||||
currentLevelExp = User.expForLevel(currentLevel)
|
||||
nextLevelExp = User.expForLevel(nextLevel)
|
||||
totalExpNeeded = nextLevelExp - currentLevelExp
|
||||
expFunction = achievement.getExpFunction()
|
||||
currentExp = me.get('points')
|
||||
worth = achievement.get('worth')
|
||||
leveledUp = currentExp - worth < currentLevelExp
|
||||
alreadyAchievedPercentage = 100 * (currentExp - currentLevelExp - worth) / totalExpNeeded
|
||||
newlyAchievedPercentage = if currentLevelExp is currentExp then 0 else 100 * worth / totalExpNeeded
|
||||
previousExp = currentExp - achievement.get('worth')
|
||||
previousExp = expFunction(earnedAchievement.get('previouslyAchievedAmount')) * achievement.get('worth') if achievement.isRepeatable()
|
||||
achievedExp = currentExp - previousExp
|
||||
leveledUp = currentExp - achievedExp < currentLevelExp
|
||||
alreadyAchievedPercentage = 100 * (previousExp - currentLevelExp) / totalExpNeeded
|
||||
newlyAchievedPercentage = if leveledUp then 100 * (currentExp - currentLevelExp) / totalExpNeeded else 100 * achievedExp / totalExpNeeded
|
||||
|
||||
console.debug "Current level is #{currentLevel} (#{currentLevelExp} xp), next level is #{nextLevel} (#{nextLevelExp} xp)."
|
||||
console.debug "Need a total of #{nextLevelExp - currentLevelExp}, already had #{currentExp - currentLevelExp - worth} and just now earned #{worth} totalling on #{currentExp}"
|
||||
console.debug "Need a total of #{nextLevelExp - currentLevelExp}, already had #{previousExp} and just now earned #{achievedExp} totalling on #{currentExp}"
|
||||
|
||||
alreadyAchievedBar = $("<div class='progress-bar progress-bar-warning' style='width:#{alreadyAchievedPercentage}%'></div>")
|
||||
newlyAchievedBar = $("<div data-toggle='tooltip' class='progress-bar progress-bar-success' style='width:#{newlyAchievedPercentage}%'></div>")
|
||||
|
@ -53,7 +52,7 @@ module.exports = class RootView extends CocoView
|
|||
message = if (currentLevel isnt 1) and leveledUp then "Reached level #{currentLevel}!" else null
|
||||
|
||||
alreadyAchievedBar.tooltip(title: "#{currentExp} XP in total")
|
||||
newlyAchievedBar.tooltip(title: "#{worth} XP earned")
|
||||
newlyAchievedBar.tooltip(title: "#{achievedExp} XP earned")
|
||||
emptyBar.tooltip(title: "#{nextLevelExp - currentExp} XP until level #{nextLevel}")
|
||||
|
||||
# TODO a default should be linked here
|
||||
|
@ -63,7 +62,7 @@ module.exports = class RootView extends CocoView
|
|||
image: $("<img src='#{imageURL}' />")
|
||||
description: achievement.get('description')
|
||||
progressBar: progressBar
|
||||
earnedExp: "+ #{worth} XP"
|
||||
earnedExp: "+ #{achievedExp} XP"
|
||||
message: message
|
||||
|
||||
options =
|
||||
|
@ -77,13 +76,11 @@ module.exports = class RootView extends CocoView
|
|||
$.notify( data, options )
|
||||
|
||||
handleNewAchievements: (earnedAchievements) ->
|
||||
console.debug 'Got new earned achievements'
|
||||
# TODO performance?
|
||||
_.each(earnedAchievements.models, (earnedAchievement) =>
|
||||
achievement = new Achievement(_id: earnedAchievement.get('achievement'))
|
||||
console.log achievement
|
||||
achievement.fetch(
|
||||
success: @showNewAchievement
|
||||
success: (achievement) => @showNewAchievement(achievement, earnedAchievement)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -150,7 +147,7 @@ module.exports = class RootView extends CocoView
|
|||
|
||||
saveLanguage: (newLang) ->
|
||||
me.set('preferredLanguage', newLang)
|
||||
res = me.save()
|
||||
res = me.patch()
|
||||
return unless res
|
||||
res.error ->
|
||||
errors = JSON.parse(res.responseText)
|
||||
|
|
|
@ -5,7 +5,7 @@ app = require('application')
|
|||
|
||||
class SearchCollection extends Backbone.Collection
|
||||
initialize: (modelURL, @model, @term, @projection) ->
|
||||
@url = "#{modelURL}/search?project="
|
||||
@url = "#{modelURL}?project="
|
||||
if @projection? and not (@projection == [])
|
||||
@url += projection[0]
|
||||
@url += ',' + projected for projected in projection[1..]
|
||||
|
|
30
app/views/modal/confirm.coffee
Normal file
30
app/views/modal/confirm.coffee
Normal file
|
@ -0,0 +1,30 @@
|
|||
ModalView = require '../kinds/ModalView'
|
||||
template = require 'templates/modal/confirm'
|
||||
|
||||
module.exports = class ConfirmModal extends ModalView
|
||||
id: "confirm-modal"
|
||||
template: template
|
||||
closeButton: true
|
||||
closeOnConfirm: true
|
||||
|
||||
events:
|
||||
'click #decline-button': 'doDecline'
|
||||
'click #confirm-button': 'doConfirm'
|
||||
|
||||
constructor: (@renderData={}, options={}) ->
|
||||
super(options)
|
||||
|
||||
getRenderData: ->
|
||||
context = super()
|
||||
context.closeOnConfirm = @closeOnConfirm
|
||||
_.extend context, @renderData
|
||||
|
||||
setRenderData: (@renderData) ->
|
||||
|
||||
onDecline: (@decline) ->
|
||||
|
||||
onConfirm: (@confirm) ->
|
||||
|
||||
doConfirm: -> @confirm() if @confirm
|
||||
|
||||
doDecline: -> @decline() if @decline
|
|
@ -33,3 +33,4 @@ module.exports = class ContactView extends View
|
|||
return forms.applyErrorsToForm @$el, res.errors unless res.valid
|
||||
window.tracker?.trackEvent 'Sent Feedback', message: contactMessage
|
||||
sendContactMessage contactMessage, @$el
|
||||
$.post "/db/user/#{me.id}/track/contact_codecombat"
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports = class DiplomatSuggestionView extends View
|
|||
|
||||
subscribeAsDiplomat: ->
|
||||
me.setEmailSubscription 'diplomatNews', true
|
||||
me.save()
|
||||
me.patch()
|
||||
$("#email_translator").prop("checked", 1)
|
||||
@hide()
|
||||
return
|
||||
|
|
|
@ -39,3 +39,5 @@ module.exports = class JobProfileContactView extends ContactView
|
|||
contactMessage.message += '\n\n\n\n[CodeCombat says: please let us know if you end up accepting this job. Thanks!]'
|
||||
window.tracker?.trackEvent 'Sent Job Profile Message', message: contactMessage
|
||||
sendContactMessage contactMessage, @$el
|
||||
$.post "/db/user/#{me.id}/track/contact_candidate"
|
||||
$.post "/db/user/#{@options.recipientID}/track/contacted_by_employer" unless me.isAdmin()
|
||||
|
|
|
@ -40,7 +40,7 @@ module.exports = class WizardSettingsModal extends View
|
|||
forms.applyErrorsToForm(@$el, res)
|
||||
return
|
||||
|
||||
res = me.save()
|
||||
res = me.patch()
|
||||
return unless res
|
||||
save = $('#save-button', @$el).text($.i18n.t('common.saving', defaultValue: 'Saving...'))
|
||||
.addClass('btn-info').show().removeClass('btn-danger')
|
||||
|
|
|
@ -10,14 +10,6 @@ ModelModal = require 'views/modal/model_modal'
|
|||
|
||||
HIGHEST_SCORE = 1000000
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
url: ''
|
||||
model: LevelSession
|
||||
|
||||
constructor: (levelID) ->
|
||||
super()
|
||||
@url = "/db/level/#{levelID}/all_sessions"
|
||||
|
||||
module.exports = class LadderTabView extends CocoView
|
||||
id: 'ladder-tab-view'
|
||||
template: require 'templates/play/ladder/ladder_tab'
|
||||
|
|
|
@ -43,7 +43,7 @@ module.exports = class LadderView extends RootView
|
|||
|
||||
onLoaded: ->
|
||||
@teams = teamDataFromLevel @level
|
||||
@render()
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
ctx = super()
|
||||
|
@ -54,6 +54,7 @@ module.exports = class LadderView extends RootView
|
|||
ctx.levelDescription = marked(@level.get('description')) if @level.get('description')
|
||||
ctx._ = _
|
||||
ctx.tournamentTimeLeft = moment(new Date(1402444800000)).fromNow()
|
||||
ctx.winners = require('views/play/ladder/tournament_results')[@levelID]
|
||||
ctx
|
||||
|
||||
afterRender: ->
|
||||
|
|
552
app/views/play/ladder/tournament_results.coffee
Normal file
552
app/views/play/ladder/tournament_results.coffee
Normal file
|
@ -0,0 +1,552 @@
|
|||
module.exports = results = greed: {}
|
||||
|
||||
results.greed.humans = [
|
||||
{team: "humans", rank: 1, sessionID: "5381e3537585483905a829c1", name: "Wizard Dude", playtime: 63184, wins: 363, losses: 0, score: 363}
|
||||
{team: "humans", rank: 2, sessionID: "537cf76184c54c6e05c05415", name: "Vettax", playtime: 96757, wins: 365, losses: 9, score: 356}
|
||||
{team: "humans", rank: 3, sessionID: "53836824c85c223a05f4a1dd", name: "HighSea", playtime: 98996, wins: 354, losses: 7, score: 347}
|
||||
{team: "humans", rank: 4, sessionID: "537c5cf614aaabe80c69fc8d", name: "BubbleDragon", playtime: 136876, wins: 352, losses: 12, score: 340}
|
||||
{team: "humans", rank: 5, sessionID: "537bad0cb0d477e005347fb5", name: "Bakanio", playtime: 103933, wins: 348, losses: 11, score: 337}
|
||||
{team: "humans", rank: 6, sessionID: "537cbf86264b3a7d12eb9d55", name: "zero_degrees", playtime: 4236, wins: 346, losses: 17, score: 329}
|
||||
{team: "humans", rank: 7, sessionID: "538915d2d06c503805fe40d2", name: "Transistor", playtime: 742, wins: 347, losses: 19, score: 328}
|
||||
{team: "humans", rank: 8, sessionID: "537bbc56831db4ca0526ced3", name: "Chrc", playtime: 2105, wins: 339, losses: 15, score: 324}
|
||||
{team: "humans", rank: 9, sessionID: "5381d7f87585483905a825fc", name: "nemoyatpeace", playtime: 121202, wins: 344, losses: 20, score: 324}
|
||||
{team: "humans", rank: 10, sessionID: "53928ff24ca25c6205e290c0", name: "Catalina", playtime: 239, wins: 342, losses: 27, score: 315}
|
||||
{team: "humans", rank: 11, sessionID: "5383f8162757353805a97454", name: "Zzadded", playtime: 53485, wins: 334, losses: 28, score: 306}
|
||||
{team: "humans", rank: 12, sessionID: "537d047084c54c6e05c05ab9", name: "Moojo", playtime: 83687, wins: 331, losses: 27, score: 304}
|
||||
{team: "humans", rank: 13, sessionID: "537bab02f5b6a9d405ec5107", name: "Pentiado", playtime: 70424, wins: 336, losses: 33, score: 303}
|
||||
{team: "humans", rank: 14, sessionID: "537d11947e1e10b705bbc4a6", name: "Banadux", playtime: 141292, wins: 333, losses: 32, score: 301}
|
||||
{team: "humans", rank: 15, sessionID: "538181fd7585483905a801e1", name: "chadnickbok", playtime: 922, wins: 334, losses: 33, score: 301}
|
||||
{team: "humans", rank: 16, sessionID: "537bc4990de0a02c07e8799a", name: "Mepath", playtime: 94421, wins: 315, losses: 28, score: 287}
|
||||
{team: "humans", rank: 17, sessionID: "53826025c85c223a05f42c5c", name: "Frederick the Great", playtime: 24696, wins: 325, losses: 42, score: 283}
|
||||
{team: "humans", rank: 18, sessionID: "5387d070b924da39051331a5", name: "NoMan", playtime: 279296, wins: 320, losses: 46, score: 274}
|
||||
{team: "humans", rank: 19, sessionID: "535e50c1ba35914a07a308c9", name: "Patogeno", playtime: 69601, wins: 318, losses: 44, score: 274}
|
||||
{team: "humans", rank: 20, sessionID: "537b9b023803a287057583dd", name: "avv", playtime: 85418, wins: 316, losses: 50, score: 266}
|
||||
{team: "humans", rank: 21, sessionID: "537c89d814aaabe80c6a1139", name: "Foosvald", playtime: 3197, wins: 307, losses: 41, score: 266}
|
||||
{team: "humans", rank: 22, sessionID: "538350c778171d3d057eb1e4", name: "Ticaj", playtime: 29249, wins: 316, losses: 52, score: 264}
|
||||
{team: "humans", rank: 23, sessionID: "537b7d9a5bc02238050d1450", name: "DrMonky", playtime: 14815, wins: 315, losses: 55, score: 260}
|
||||
{team: "humans", rank: 24, sessionID: "537c7d8526529de30cca4310", name: "imkat", playtime: 14870, wins: 292, losses: 38, score: 254}
|
||||
{team: "humans", rank: 25, sessionID: "5392283b2446a44105387cbb", name: "AKA", playtime: 134724, wins: 312, losses: 58, score: 254}
|
||||
{team: "humans", rank: 26, sessionID: "537b7ff9e91b4d3b05525db2", name: "UltraNagog", playtime: 113091, wins: 296, losses: 46, score: 250}
|
||||
{team: "humans", rank: 27, sessionID: "537c1b0e0ff88b2c06288354", name: "Master J", playtime: 32859, wins: 305, losses: 57, score: 248}
|
||||
{team: "humans", rank: 28, sessionID: "537c551814aaabe80c69f8e9", name: "texastoast", playtime: 75930, wins: 300, losses: 54, score: 246}
|
||||
{team: "humans", rank: 29, sessionID: "537b9f2551e98aa705b60500", name: "Otsix", playtime: 2270, wins: 302, losses: 58, score: 244}
|
||||
{team: "humans", rank: 30, sessionID: "537bb4b88698e13805226bb9", name: "asselinpaul", playtime: 22992, wins: 306, losses: 64, score: 242}
|
||||
{team: "humans", rank: 31, sessionID: "537b87c6e91b4d3b0552600f", name: "tedshot", playtime: 22872, wins: 306, losses: 65, score: 241}
|
||||
{team: "humans", rank: 32, sessionID: "537bae76ec57a3e805cbf5b3", name: "Aeter", playtime: 18224, wins: 307, losses: 66, score: 241}
|
||||
{team: "humans", rank: 33, sessionID: "537b9e8a51e98aa705b604ab", name: "bxp", playtime: 17385, wins: 304, losses: 67, score: 237}
|
||||
{team: "humans", rank: 34, sessionID: "537bdbe4a41b6b3a059befd0", name: "princeben", playtime: 52246, wins: 290, losses: 56, score: 234}
|
||||
{team: "humans", rank: 35, sessionID: "537bdf1d375835400576a207", name: "Mal Keshar", playtime: 985, wins: 295, losses: 68, score: 227}
|
||||
{team: "humans", rank: 36, sessionID: "5383f2ea2757353805a972d3", name: "Mergen", playtime: 37792, wins: 297, losses: 71, score: 226}
|
||||
{team: "humans", rank: 37, sessionID: "537cec6a9cce053a05c04385", name: "Simulatorboy", playtime: 15925, wins: 295, losses: 75, score: 220}
|
||||
{team: "humans", rank: 38, sessionID: "537b977d556db17605be76a2", name: "shoebane", playtime: 89060, wins: 287, losses: 68, score: 219}
|
||||
{team: "humans", rank: 39, sessionID: "538757328ca8b1120b8c0bb5", name: "ProvençalLeGaulois", playtime: 183850, wins: 289, losses: 71, score: 218}
|
||||
{team: "humans", rank: 40, sessionID: "5384b9803e0daa3905188225", name: "Rincewind the Wizard", playtime: 49014, wins: 280, losses: 64, score: 216}
|
||||
{team: "humans", rank: 41, sessionID: "53805c227585483905a77c38", name: "guuuuuuuuuuu", playtime: 40835, wins: 290, losses: 76, score: 214}
|
||||
{team: "humans", rank: 42, sessionID: "537bc0060b070d6b0691fd47", name: "toothpaste", playtime: 116438, wins: 289, losses: 78, score: 211}
|
||||
{team: "humans", rank: 43, sessionID: "538bc7d05572d43b0520ede9", name: "MaxF", playtime: 16012, wins: 271, losses: 62, score: 209}
|
||||
{team: "humans", rank: 44, sessionID: "537ca06126529de30cca58a1", name: "firemanphil", playtime: 58857, wins: 287, losses: 81, score: 206}
|
||||
{team: "humans", rank: 45, sessionID: "537b895ee91b4d3b0552606a", name: "Supaku", playtime: 23623, wins: 281, losses: 79, score: 202}
|
||||
{team: "humans", rank: 46, sessionID: "537ba1d7903fd2b805155298", name: "Greediest", playtime: 32390, wins: 286, losses: 87, score: 199}
|
||||
{team: "humans", rank: 47, sessionID: "537ba398903fd2b805155376", name: "RapTorS", playtime: 30828, wins: 280, losses: 83, score: 197}
|
||||
{team: "humans", rank: 48, sessionID: "537bbb371aaa69c405267714", name: "PIptastic", playtime: 14165, wins: 282, losses: 85, score: 197}
|
||||
{team: "humans", rank: 49, sessionID: "537fd2f62a5a5acd08dbbe90", name: "aldezar", playtime: 55511, wins: 260, losses: 64, score: 196}
|
||||
{team: "humans", rank: 50, sessionID: "537c0f440ff88b2c06287c31", name: "yes", playtime: 42677, wins: 251, losses: 55, score: 196}
|
||||
{team: "humans", rank: 51, sessionID: "537fb985c1a6b99109171054", name: "IamTesting", playtime: 242, wins: 280, losses: 90, score: 190}
|
||||
{team: "humans", rank: 52, sessionID: "537cdd63665bde1b13ffdede", name: "wiggles", playtime: 9574, wins: 278, losses: 94, score: 184}
|
||||
{team: "humans", rank: 53, sessionID: "537cda44665bde1b13ffdcb2", name: "Nullable", playtime: 21602, wins: 275, losses: 93, score: 182}
|
||||
{team: "humans", rank: 54, sessionID: "537bf012b72b2bbe053c9173", name: "hyn", playtime: 5688, wins: 278, losses: 97, score: 181}
|
||||
{team: "humans", rank: 55, sessionID: "537bda813dd7d35105f5fec2", name: "Rinomon", playtime: 19811, wins: 272, losses: 96, score: 176}
|
||||
{team: "humans", rank: 56, sessionID: "537b9e7251e98aa705b604a2", name: "stuntman_fx", playtime: 12496, wins: 258, losses: 86, score: 172}
|
||||
{team: "humans", rank: 57, sessionID: "537d1def7e1e10b705bbcbc4", name: "WizBit", playtime: 35790, wins: 270, losses: 98, score: 172}
|
||||
{team: "humans", rank: 58, sessionID: "537b8a93e91b4d3b055260f3", name: "Korla March", playtime: 13093, wins: 265, losses: 94, score: 171}
|
||||
{team: "humans", rank: 59, sessionID: "53873bc17d99a7390561afd2", name: "VicksC", playtime: 65582, wins: 262, losses: 93, score: 169}
|
||||
{team: "humans", rank: 60, sessionID: "537b907d5bc02238050d1b22", name: "Jonanin", playtime: 60888, wins: 272, losses: 103, score: 169}
|
||||
{team: "humans", rank: 61, sessionID: "537b9345c74f237005ecc475", name: "AdrianoKF", playtime: 8880, wins: 267, losses: 100, score: 167}
|
||||
{team: "humans", rank: 62, sessionID: "537ba08651e98aa705b605a8", name: "frickinjason", playtime: 311295, wins: 266, losses: 99, score: 167}
|
||||
{team: "humans", rank: 63, sessionID: "536076104c5ed51d05284aeb", name: "会打电脑的狼", playtime: 180932, wins: 262, losses: 96, score: 166}
|
||||
{team: "humans", rank: 64, sessionID: "537fb41bc1a6b99109170daf", name: "avatar652", playtime: 23943, wins: 260, losses: 95, score: 165}
|
||||
{team: "humans", rank: 65, sessionID: "537bb34a8698e13805226ae1", name: "Superice", playtime: 8561, wins: 267, losses: 103, score: 164}
|
||||
{team: "humans", rank: 66, sessionID: "537b8f285bc02238050d1a91", name: "renner96", playtime: 8962, wins: 265, losses: 103, score: 162}
|
||||
{team: "humans", rank: 67, sessionID: "537b97ba556db17605be76bc", name: "howsiwei", playtime: 37865, wins: 249, losses: 90, score: 159}
|
||||
{team: "humans", rank: 68, sessionID: "537d6e997e6f2dba0510649c", name: "Brainoutoforder", playtime: 79551, wins: 263, losses: 104, score: 159}
|
||||
{team: "humans", rank: 69, sessionID: "537bbe24d9644630065c90f4", name: "cc", playtime: 27244, wins: 247, losses: 94, score: 153}
|
||||
{team: "humans", rank: 70, sessionID: "538f055b7558763705258211", name: "Klee", playtime: 29269, wins: 264, losses: 111, score: 153}
|
||||
{team: "humans", rank: 71, sessionID: "537c3a51e8ea6e790a7cceb2", name: "NovaHorizon", playtime: 72951, wins: 254, losses: 103, score: 151}
|
||||
{team: "humans", rank: 72, sessionID: "537c3e0dd08a96e40a64f01c", name: "Arnfrid", playtime: 13133, wins: 261, losses: 111, score: 150}
|
||||
{team: "humans", rank: 73, sessionID: "537b7cf65bc02238050d141f", name: "rawpower", playtime: 60808, wins: 256, losses: 110, score: 146}
|
||||
{team: "humans", rank: 74, sessionID: "537bcc75c57303a5070c2e9a", name: "dhimdis", playtime: 43092, wins: 256, losses: 111, score: 145}
|
||||
{team: "humans", rank: 75, sessionID: "538bc1a15572d43b0520e8ae", name: "rednek", playtime: 38220, wins: 250, losses: 106, score: 144}
|
||||
{team: "humans", rank: 76, sessionID: "5380c8ed7585483905a7ad55", name: "Kungfury", playtime: 628, wins: 254, losses: 113, score: 141}
|
||||
{team: "humans", rank: 77, sessionID: "537c37dff1d9cfe4096ba9c9", name: "Auralien", playtime: 24844, wins: 255, losses: 115, score: 140}
|
||||
{team: "humans", rank: 78, sessionID: "539234c52446a441053881ad", name: "Szalami", playtime: 45304, wins: 243, losses: 108, score: 135}
|
||||
{team: "humans", rank: 79, sessionID: "537c15910ff88b2c06287fd5", name: "Ahrimen", playtime: 24541, wins: 253, losses: 120, score: 133}
|
||||
{team: "humans", rank: 80, sessionID: "537ff34f4cd8023705770b31", name: "ColtYolo", playtime: 18704, wins: 244, losses: 115, score: 129}
|
||||
{team: "humans", rank: 81, sessionID: "538ceadc56c3613905300df1", name: "Teshynil", playtime: 59986, wins: 233, losses: 105, score: 128}
|
||||
{team: "humans", rank: 82, sessionID: "538f174df3691038051651f1", name: "Leas", playtime: 11670, wins: 251, losses: 126, score: 125}
|
||||
{team: "humans", rank: 83, sessionID: "537d8cae13add33a051be70c", name: "Jamar", playtime: 9358, wins: 245, losses: 123, score: 122}
|
||||
{team: "humans", rank: 84, sessionID: "53877f428ca8b1120b8c2ba8", name: "madcoder", playtime: 58824, wins: 241, losses: 120, score: 121}
|
||||
{team: "humans", rank: 85, sessionID: "5391f1f282f0bc4705242218", name: "RedRudeBoy", playtime: 13356, wins: 230, losses: 110, score: 120}
|
||||
{team: "humans", rank: 86, sessionID: "537bdb1c6b018e5505b9d5ae", name: "Ralkarin", playtime: 16137, wins: 245, losses: 128, score: 117}
|
||||
{team: "humans", rank: 87, sessionID: "537bc9efa968548907de6dc5", name: "scrumlock", playtime: 43716, wins: 238, losses: 122, score: 116}
|
||||
{team: "humans", rank: 88, sessionID: "53973dc02546283905a3d603", name: "Olivier_A", playtime: 5903, wins: 246, losses: 131, score: 115}
|
||||
{team: "humans", rank: 89, sessionID: "537d3fffe20e956205f0da0c", name: "Lecky", playtime: 28974, wins: 242, losses: 127, score: 115}
|
||||
{team: "humans", rank: 90, sessionID: "537b9edc7c89ec9805f4de89", name: "Cemiv", playtime: 5632, wins: 241, losses: 134, score: 107}
|
||||
{team: "humans", rank: 91, sessionID: "537b8bede91b4d3b05526151", name: "Witchy", playtime: 29809, wins: 214, losses: 110, score: 104}
|
||||
{team: "humans", rank: 92, sessionID: "535d728c30f061020b8f9893", name: "ZeoNFrosT", playtime: 0, wins: 233, losses: 130, score: 103}
|
||||
{team: "humans", rank: 93, sessionID: "537b9c4b16613c8405155abd", name: "JD557", playtime: 17456, wins: 236, losses: 134, score: 102}
|
||||
{team: "humans", rank: 94, sessionID: "537bdb396b018e5505b9d5ba", name: "devast8a", playtime: 89013, wins: 233, losses: 133, score: 100}
|
||||
{team: "humans", rank: 95, sessionID: "537b7fbc5bc02238050d14ee", name: "jojman272", playtime: 859, wins: 232, losses: 132, score: 100}
|
||||
{team: "humans", rank: 96, sessionID: "537cc552e4523d0113ba4eb2", name: "Sir Coward", playtime: 26839, wins: 235, losses: 135, score: 100}
|
||||
{team: "humans", rank: 97, sessionID: "537b8abde91b4d3b05526103", name: "Jef", playtime: 10311, wins: 236, losses: 139, score: 97}
|
||||
{team: "humans", rank: 98, sessionID: "537ed4db14bb1d38053b5b72", name: "ModernBarbershop", playtime: 33894, wins: 221, losses: 129, score: 92}
|
||||
{team: "humans", rank: 99, sessionID: "537b8ba6e91b4d3b0552613c", name: "Wiz", playtime: 1655, wins: 227, losses: 137, score: 90}
|
||||
{team: "humans", rank: 100, sessionID: "537bad3396ee90f605f2b0f9", name: "Rnq", playtime: 14853, wins: 226, losses: 138, score: 88}
|
||||
{team: "humans", rank: 101, sessionID: "537f9d5ba7d2578f083d69b4", name: "BLACKORP", playtime: 2869, wins: 225, losses: 138, score: 87}
|
||||
{team: "humans", rank: 102, sessionID: "537ba00e7c89ec9805f4defc", name: "xoko814", playtime: 869, wins: 225, losses: 139, score: 86}
|
||||
{team: "humans", rank: 103, sessionID: "5391f83082f0bc47052424c7", name: "tarasiu", playtime: 228, wins: 225, losses: 139, score: 86}
|
||||
{team: "humans", rank: 104, sessionID: "537d26d77e1e10b705bbd0d5", name: "Traitor", playtime: 8900, wins: 222, losses: 137, score: 85}
|
||||
{team: "humans", rank: 105, sessionID: "537bbb0a1aaa69c4052676f5", name: "TROGDOR BURNINATE", playtime: 6630, wins: 231, losses: 146, score: 85}
|
||||
{team: "humans", rank: 106, sessionID: "5387a8a3d06c503805fda60d", name: "masanorinyo", playtime: 68753, wins: 226, losses: 142, score: 84}
|
||||
{team: "humans", rank: 107, sessionID: "538e8593f369103805160d76", name: "Aggar", playtime: 12492, wins: 228, losses: 144, score: 84}
|
||||
{team: "humans", rank: 108, sessionID: "537e7eac63734c630505be27", name: "TheRealThrall", playtime: 587, wins: 224, losses: 141, score: 83}
|
||||
{team: "humans", rank: 109, sessionID: "537c8dfa26529de30cca4c43", name: "xeno", playtime: 15394, wins: 222, losses: 142, score: 80}
|
||||
{team: "humans", rank: 110, sessionID: "537bef0b8c297aa0055d1184", name: "Floogle", playtime: 36828, wins: 224, losses: 145, score: 79}
|
||||
{team: "humans", rank: 111, sessionID: "537c666826529de30cca38c2", name: "Jerson Otzoy", playtime: 46519, wins: 201, losses: 122, score: 79}
|
||||
{team: "humans", rank: 112, sessionID: "537cb6b2a3cb63ea103c8000", name: "phisixersai", playtime: 8170, wins: 224, losses: 146, score: 78}
|
||||
{team: "humans", rank: 113, sessionID: "537b9ba716613c8405155a73", name: "Beerdroid", playtime: 2547, wins: 226, losses: 150, score: 76}
|
||||
{team: "humans", rank: 114, sessionID: "537c9bcd26529de30cca54e0", name: "Dood", playtime: 1121, wins: 219, losses: 145, score: 74}
|
||||
{team: "humans", rank: 115, sessionID: "537c5b7c26529de30cca3439", name: "Markoth", playtime: 787, wins: 220, losses: 147, score: 73}
|
||||
{team: "humans", rank: 116, sessionID: "537d1c297e1e10b705bbca7d", name: "chotic", playtime: 1292, wins: 218, losses: 146, score: 72}
|
||||
{team: "humans", rank: 117, sessionID: "538484a53e0daa39051863e4", name: "Drago", playtime: 465, wins: 217, losses: 147, score: 70}
|
||||
{team: "humans", rank: 118, sessionID: "537baaab03ff8dc005b8436c", name: "Petteri", playtime: 15235, wins: 219, losses: 149, score: 70}
|
||||
{team: "humans", rank: 119, sessionID: "537ca0aa26529de30cca58c8", name: "3ng3l", playtime: 1703, wins: 217, losses: 147, score: 70}
|
||||
{team: "humans", rank: 120, sessionID: "537b897f5bc02238050d181c", name: "Jremz", playtime: 8386, wins: 221, losses: 152, score: 69}
|
||||
{team: "humans", rank: 121, sessionID: "537ba85554a7b1d5053bb366", name: "Taters", playtime: 9664, wins: 193, losses: 126, score: 67}
|
||||
{team: "humans", rank: 122, sessionID: "537b9220e91b4d3b055263ea", name: "Listr", playtime: 34000, wins: 202, losses: 136, score: 66}
|
||||
{team: "humans", rank: 123, sessionID: "537cadbd2f6e3aee0ed581f0", name: "satefa", playtime: 10106, wins: 220, losses: 156, score: 64}
|
||||
{team: "humans", rank: 124, sessionID: "537d0a8c84c54c6e05c05db7", name: "redWizzard", playtime: 53180, wins: 183, losses: 120, score: 63}
|
||||
{team: "humans", rank: 125, sessionID: "536c6d1c68b5258d0c4b7da8", name: "Tober", playtime: 452, wins: 216, losses: 153, score: 63}
|
||||
{team: "humans", rank: 126, sessionID: "535ee1e023f09c2c0836a2a7", name: "(ノಠ益ಠ)ノ彡┻━┻", playtime: 3229, wins: 218, losses: 158, score: 60}
|
||||
{team: "humans", rank: 127, sessionID: "5371626351ce9b3a05d95d5c", name: "Perrekus", playtime: 9047, wins: 215, losses: 158, score: 57}
|
||||
{team: "humans", rank: 128, sessionID: "53968372e1b8fd0c08c693d5", name: "leoTest", playtime: 10739, wins: 215, losses: 158, score: 57}
|
||||
{team: "humans", rank: 129, sessionID: "537cfcd69cce053a05c04ce1", name: "Soulnai", playtime: 22641, wins: 210, losses: 154, score: 56}
|
||||
{team: "humans", rank: 130, sessionID: "537bf57795356a43065f7403", name: "Mordecai", playtime: 11262, wins: 215, losses: 159, score: 56}
|
||||
{team: "humans", rank: 131, sessionID: "5377aabf05e1483905cb99d5", name: "Umaris", playtime: 23418, wins: 211, losses: 156, score: 55}
|
||||
{team: "humans", rank: 132, sessionID: "537c93ce26529de30cca5029", name: "Willybe", playtime: 4772, wins: 212, losses: 158, score: 54}
|
||||
{team: "humans", rank: 133, sessionID: "537babf403838cf0050ace06", name: "Brian Humphrey", playtime: 7300, wins: 212, losses: 158, score: 54}
|
||||
{team: "humans", rank: 134, sessionID: "537e19e30efa6a37059e0b4f", name: "Aqrrc", playtime: 5003, wins: 210, losses: 163, score: 47}
|
||||
{team: "humans", rank: 135, sessionID: "5395d19622ca0e39054ea5b1", name: "anykey", playtime: 29278, wins: 201, losses: 155, score: 46}
|
||||
{team: "humans", rank: 136, sessionID: "537b7fd6e91b4d3b05525da3", name: "Gily", playtime: 17673, wins: 205, losses: 163, score: 42}
|
||||
{team: "humans", rank: 137, sessionID: "537bbbcb3dc5f3c3055c3040", name: "roseaboveit", playtime: 12398, wins: 205, losses: 168, score: 37}
|
||||
{team: "humans", rank: 138, sessionID: "538757897d99a7390561bb7f", name: "Jeremy", playtime: 6842, wins: 199, losses: 166, score: 33}
|
||||
{team: "humans", rank: 139, sessionID: "537b8b845bc02238050d18e8", name: "Abel Soares Siqueira", playtime: 4945, wins: 204, losses: 171, score: 33}
|
||||
{team: "humans", rank: 140, sessionID: "537b8a37e91b4d3b055260c9", name: "mattmatt", playtime: 77241, wins: 198, losses: 166, score: 32}
|
||||
{team: "humans", rank: 141, sessionID: "537fc26d2a5a5acd08dbb0a5", name: "Melrakal", playtime: 2393, wins: 200, losses: 173, score: 27}
|
||||
{team: "humans", rank: 142, sessionID: "537bd8a73dd7d35105f5fd6a", name: "drakiac", playtime: 14601, wins: 196, losses: 169, score: 27}
|
||||
{team: "humans", rank: 143, sessionID: "537cea3d9cce053a05c04226", name: "CNKLC", playtime: 11663, wins: 200, losses: 175, score: 25}
|
||||
{team: "humans", rank: 144, sessionID: "537bf9c20ff88b2c06286e7c", name: "Jotipalo", playtime: 4124, wins: 199, losses: 176, score: 23}
|
||||
{team: "humans", rank: 145, sessionID: "53807d9405e52a3305de99f5", name: "Booya", playtime: 118149, wins: 173, losses: 152, score: 21}
|
||||
{team: "humans", rank: 146, sessionID: "537bf291d3443b2b068c1056", name: "Penguin", playtime: 7688, wins: 196, losses: 176, score: 20}
|
||||
{team: "humans", rank: 147, sessionID: "5380b82005e52a3305deb679", name: "TheWrightDev", playtime: 26967, wins: 194, losses: 176, score: 18}
|
||||
{team: "humans", rank: 148, sessionID: "537cf2aa98a1be440545d878", name: "Kipernicus", playtime: 11906, wins: 189, losses: 181, score: 8}
|
||||
{team: "humans", rank: 149, sessionID: "535e1f1187ab8481075b8d95", name: "freek", playtime: 0, wins: 190, losses: 183, score: 7}
|
||||
{team: "humans", rank: 150, sessionID: "535f0911d42bda62085e40fc", name: "heated", playtime: 65, wins: 188, losses: 182, score: 6}
|
||||
{team: "humans", rank: 151, sessionID: "539120d882f0bc470523cd6f", name: "Fitbos", playtime: 1622, wins: 0, losses: 0, score: 0}
|
||||
{team: "humans", rank: 152, sessionID: "539875130599fa3a05ca7293", name: "jeimmy", playtime: 663, wins: 0, losses: 0, score: 0}
|
||||
{team: "humans", rank: 153, sessionID: "537b7ccce91b4d3b05525cdc", name: "Bart2121", playtime: 4177, wins: 184, losses: 187, score: -3}
|
||||
{team: "humans", rank: 154, sessionID: "53866ed58ca8b1120b8b816d", name: "Nikolai", playtime: 26320, wins: 184, losses: 187, score: -3}
|
||||
{team: "humans", rank: 155, sessionID: "5385610f3e0daa390518e2f6", name: "Stravinsky", playtime: 8870, wins: 182, losses: 185, score: -3}
|
||||
{team: "humans", rank: 156, sessionID: "537b94956c13497e05de816e", name: "Maix", playtime: 3163, wins: 183, losses: 186, score: -3}
|
||||
{team: "humans", rank: 157, sessionID: "537187dcce8e453b05c9d21c", name: "NasytToast", playtime: 0, wins: 183, losses: 188, score: -5}
|
||||
{team: "humans", rank: 158, sessionID: "537bb696dd932f6b05d370fd", name: "HandmadeMercury", playtime: 5539, wins: 169, losses: 175, score: -6}
|
||||
{team: "humans", rank: 159, sessionID: "537b7f605bc02238050d14c9", name: "Jaden", playtime: 10547, wins: 182, losses: 192, score: -10}
|
||||
{team: "humans", rank: 160, sessionID: "537c489314aaabe80c69f413", name: "HiddEnigma", playtime: 5850, wins: 181, losses: 191, score: -10}
|
||||
{team: "humans", rank: 161, sessionID: "537bb7cd1e8dd17a054c1044", name: "Alexander the Grape", playtime: 30398, wins: 178, losses: 189, score: -11}
|
||||
{team: "humans", rank: 162, sessionID: "538eada37558763705255a0c", name: "Evran", playtime: 22253, wins: 179, losses: 192, score: -13}
|
||||
{team: "humans", rank: 163, sessionID: "5386aedf7d99a7390561802a", name: "Reclusiarch", playtime: 3281, wins: 178, losses: 192, score: -14}
|
||||
{team: "humans", rank: 164, sessionID: "538b7202b924da3905157e07", name: "Mlatic", playtime: 723, wins: 176, losses: 190, score: -14}
|
||||
{team: "humans", rank: 165, sessionID: "537c4411c209bbd60c16a3d8", name: "liorst1", playtime: 14571, wins: 178, losses: 193, score: -15}
|
||||
{team: "humans", rank: 166, sessionID: "537fcaee2a5a5acd08dbb79c", name: "Booya2nd", playtime: 9598, wins: 153, losses: 168, score: -15}
|
||||
{team: "humans", rank: 167, sessionID: "538ae84fb924da3905154172", name: "WAAW", playtime: 3668, wins: 177, losses: 194, score: -17}
|
||||
{team: "humans", rank: 168, sessionID: "538751b78ca8b1120b8c0792", name: "DZC", playtime: 5512, wins: 170, losses: 188, score: -18}
|
||||
{team: "humans", rank: 169, sessionID: "537c0ab50ff88b2c0628792e", name: "maxily", playtime: 18792, wins: 174, losses: 192, score: -18}
|
||||
{team: "humans", rank: 170, sessionID: "537ba1347c89ec9805f4df76", name: "qkhhly", playtime: 9518, wins: 176, losses: 196, score: -20}
|
||||
{team: "humans", rank: 171, sessionID: "538b4bbdd06c503805ff3b8a", name: "iamcodewar", playtime: 10939, wins: 178, losses: 198, score: -20}
|
||||
{team: "humans", rank: 172, sessionID: "537f14e18fe881f1055df20a", name: "Alanor", playtime: 20437, wins: 150, losses: 174, score: -24}
|
||||
{team: "humans", rank: 173, sessionID: "537f57ff3282d7a507695039", name: "Navi' Dendi", playtime: 4382, wins: 172, losses: 197, score: -25}
|
||||
{team: "humans", rank: 174, sessionID: "537c14950ff88b2c06287f22", name: "lolka", playtime: 3820, wins: 172, losses: 200, score: -28}
|
||||
{team: "humans", rank: 175, sessionID: "53570b7a1bfa9bba14b5e045", name: "Scott", playtime: 6228, wins: 173, losses: 202, score: -29}
|
||||
{team: "humans", rank: 176, sessionID: "537bbd0f3cd816fa05a48401", name: "DonutBaron", playtime: 9716, wins: 165, losses: 195, score: -30}
|
||||
{team: "humans", rank: 177, sessionID: "5381726d7585483905a7f978", name: "armlol", playtime: 5149, wins: 171, losses: 204, score: -33}
|
||||
{team: "humans", rank: 178, sessionID: "538c0bfb56c36139052fa076", name: "Aura Temple Network", playtime: 7489, wins: 169, losses: 205, score: -36}
|
||||
{team: "humans", rank: 179, sessionID: "538ec77af3691038051629c3", name: "BI", playtime: 3870, wins: 164, losses: 200, score: -36}
|
||||
{team: "humans", rank: 180, sessionID: "537b889fe91b4d3b0552603e", name: "McDerp", playtime: 3415, wins: 161, losses: 203, score: -42}
|
||||
{team: "humans", rank: 181, sessionID: "537d169a7e1e10b705bbc736", name: "Nitor", playtime: 7036, wins: 159, losses: 205, score: -46}
|
||||
{team: "humans", rank: 182, sessionID: "53837eee6f3bea3a05faf5fb", name: "HeadCrusher", playtime: 22806, wins: 133, losses: 182, score: -49}
|
||||
{team: "humans", rank: 183, sessionID: "537ba4887c89ec9805f4e10d", name: "Geralt", playtime: 2353, wins: 158, losses: 208, score: -50}
|
||||
{team: "humans", rank: 184, sessionID: "53802aab05e52a3305de797e", name: "micblayo", playtime: 14726, wins: 159, losses: 209, score: -50}
|
||||
{team: "humans", rank: 185, sessionID: "538b60bdb924da39051576e2", name: "mydoom", playtime: 9270, wins: 159, losses: 209, score: -50}
|
||||
{team: "humans", rank: 186, sessionID: "5380f3917585483905a7c0b3", name: "Lalaland1125", playtime: 689, wins: 160, losses: 211, score: -51}
|
||||
{team: "humans", rank: 187, sessionID: "537b8125e91b4d3b05525e1e", name: "Garrett", playtime: 1833, wins: 157, losses: 212, score: -55}
|
||||
{team: "humans", rank: 188, sessionID: "537b8c60e91b4d3b05526181", name: "Usopp", playtime: 8340, wins: 156, losses: 217, score: -61}
|
||||
{team: "humans", rank: 189, sessionID: "537b9b4116613c8405155a41", name: "Y0DA", playtime: 5351, wins: 154, losses: 216, score: -62}
|
||||
{team: "humans", rank: 190, sessionID: "5387f127d06c503805fdcd97", name: "Hexadecimage", playtime: 89476, wins: 151, losses: 222, score: -71}
|
||||
{team: "humans", rank: 191, sessionID: "539265012446a44105389a8c", name: "odeakihumi", playtime: 23819, wins: 143, losses: 219, score: -76}
|
||||
{team: "humans", rank: 192, sessionID: "537ba73a980cfcba051f19c5", name: "Torg", playtime: 7045, wins: 145, losses: 221, score: -76}
|
||||
{team: "humans", rank: 193, sessionID: "5392bbc0e04ba13805ed4c0f", name: "iownspace", playtime: 51659, wins: 146, losses: 223, score: -77}
|
||||
{team: "humans", rank: 194, sessionID: "537bf14bf8b46fbd0544fc18", name: "danshou", playtime: 22590, wins: 148, losses: 226, score: -78}
|
||||
{team: "humans", rank: 195, sessionID: "537b212dfe0ec03905fcd712", name: "ThunderClan", playtime: 766, wins: 144, losses: 228, score: -84}
|
||||
{team: "humans", rank: 196, sessionID: "536540d51415c79e648b1de5", name: "Nick04 Bubonic", playtime: 12, wins: 138, losses: 222, score: -84}
|
||||
{team: "humans", rank: 197, sessionID: "537fb0792a5a5acd08dba76f", name: "Slackus", playtime: 49736, wins: 141, losses: 226, score: -85}
|
||||
{team: "humans", rank: 198, sessionID: "537d44911333605305550411", name: "tehowner", playtime: 2969, wins: 138, losses: 223, score: -85}
|
||||
{team: "humans", rank: 199, sessionID: "537df429933d99860613ab2d", name: "Farafonoff", playtime: 4315, wins: 142, losses: 228, score: -86}
|
||||
{team: "humans", rank: 200, sessionID: "538501137d99a7390560db54", name: "Joodoc", playtime: 6042, wins: 144, losses: 231, score: -87}
|
||||
{team: "humans", rank: 201, sessionID: "537b8a58e91b4d3b055260d8", name: "Terebijoke", playtime: 85680, wins: 122, losses: 210, score: -88}
|
||||
{team: "humans", rank: 202, sessionID: "537c110195356a43065f8450", name: "Chen Yu LIu", playtime: 843, wins: 140, losses: 232, score: -92}
|
||||
{team: "humans", rank: 203, sessionID: "537dba4613add33a051bf680", name: "Bobbybaby", playtime: 1509, wins: 140, losses: 232, score: -92}
|
||||
{team: "humans", rank: 204, sessionID: "537b9003e91b4d3b05526329", name: "Coreth", playtime: 11677, wins: 131, losses: 224, score: -93}
|
||||
{team: "humans", rank: 205, sessionID: "538b618bd06c503805ff4210", name: "robat", playtime: 5776, wins: 138, losses: 234, score: -96}
|
||||
{team: "humans", rank: 206, sessionID: "5383b7196f3bea3a05fb1472", name: "lilos", playtime: 2464, wins: 135, losses: 232, score: -97}
|
||||
{team: "humans", rank: 207, sessionID: "537f8672d409ac270861c842", name: "ThatOtherPerson", playtime: 2018, wins: 137, losses: 236, score: -99}
|
||||
{team: "humans", rank: 208, sessionID: "53809c2c7585483905a795f1", name: "都比", playtime: 28855, wins: 136, losses: 235, score: -99}
|
||||
{team: "humans", rank: 209, sessionID: "537c866f14aaabe80c6a0f90", name: "Energy", playtime: 1276, wins: 130, losses: 229, score: -99}
|
||||
{team: "humans", rank: 210, sessionID: "538e4af0755876370525291c", name: "commando Tech", playtime: 3725, wins: 136, losses: 236, score: -100}
|
||||
{team: "humans", rank: 211, sessionID: "537b9da67c89ec9805f4de0b", name: "tembelu", playtime: 9298, wins: 129, losses: 230, score: -101}
|
||||
{team: "humans", rank: 212, sessionID: "53972a5f2546283905a3bdc5", name: "holyKoT", playtime: 2171, wins: 131, losses: 241, score: -110}
|
||||
{team: "humans", rank: 213, sessionID: "537ba6dd980cfcba051f199d", name: "Aaron1011", playtime: 3449, wins: 130, losses: 240, score: -110}
|
||||
{team: "humans", rank: 214, sessionID: "537c68bf26529de30cca39cb", name: "ESWAT", playtime: 893, wins: 128, losses: 239, score: -111}
|
||||
{team: "humans", rank: 215, sessionID: "537d5fdb3dcf67c40571fb13", name: "JustTurrable", playtime: 264, wins: 125, losses: 240, score: -115}
|
||||
{team: "humans", rank: 216, sessionID: "537e4268e1489fe206667e26", name: "EvanK", playtime: 668, wins: 125, losses: 245, score: -120}
|
||||
{team: "humans", rank: 217, sessionID: "537be834a3b60b390500e0a3", name: "gilxa1226", playtime: 394, wins: 125, losses: 245, score: -120}
|
||||
{team: "humans", rank: 218, sessionID: "537bbcfd9e1bf5f905926ebf", name: "Qin Shi Huang", playtime: 4691, wins: 125, losses: 246, score: -121}
|
||||
{team: "humans", rank: 219, sessionID: "537b9bd016613c8405155a8b", name: "WaffleFries", playtime: 2944, wins: 121, losses: 246, score: -125}
|
||||
{team: "humans", rank: 220, sessionID: "537b8a65e91b4d3b055260e0", name: "Gurra", playtime: 6295, wins: 107, losses: 233, score: -126}
|
||||
{team: "humans", rank: 221, sessionID: "537e2025933d99860613c614", name: "Encosia", playtime: 2025, wins: 118, losses: 250, score: -132}
|
||||
{team: "humans", rank: 222, sessionID: "537bb694dd932f6b05d370fc", name: "Kaboomm", playtime: 4333, wins: 116, losses: 253, score: -137}
|
||||
{team: "humans", rank: 223, sessionID: "538001aebf8ae33a0501b98e", name: "taichi_kunnn", playtime: 3524, wins: 112, losses: 254, score: -142}
|
||||
{team: "humans", rank: 224, sessionID: "53630b6573bdb4f7045a772c", name: "Lonib", playtime: 0, wins: 113, losses: 257, score: -144}
|
||||
{team: "humans", rank: 225, sessionID: "5360f83b67c29a0609ddceb4", name: "Readper", playtime: 0, wins: 109, losses: 264, score: -155}
|
||||
{team: "humans", rank: 226, sessionID: "53717f4551ce9b3a05d96043", name: "cpkenn09y", playtime: 0, wins: 106, losses: 263, score: -157}
|
||||
{team: "humans", rank: 227, sessionID: "537b9b9416613c8405155a6b", name: "Rubini", playtime: 6763, wins: 103, losses: 271, score: -168}
|
||||
{team: "humans", rank: 228, sessionID: "53902ad775587637052615d9", name: "Loxk", playtime: 32690, wins: 89, losses: 265, score: -176}
|
||||
{team: "humans", rank: 229, sessionID: "537b93886c13497e05de80a6", name: "Klomnar", playtime: 405, wins: 98, losses: 274, score: -176}
|
||||
{team: "humans", rank: 230, sessionID: "537b9c7c16613c8405155ae0", name: "dpen2000", playtime: 4313, wins: 93, losses: 273, score: -180}
|
||||
{team: "humans", rank: 231, sessionID: "53692c2d84e82a3a0553305e", name: "rnprdk", playtime: 0, wins: 94, losses: 278, score: -184}
|
||||
{team: "humans", rank: 232, sessionID: "537be99f20a501380564e764", name: "rizend", playtime: 3017, wins: 92, losses: 279, score: -187}
|
||||
{team: "humans", rank: 233, sessionID: "537ba94d54a7b1d5053bb426", name: "Rokner", playtime: 3911, wins: 90, losses: 282, score: -192}
|
||||
{team: "humans", rank: 234, sessionID: "537b949e556db17605be74ff", name: "baldeagle", playtime: 7698, wins: 91, losses: 284, score: -193}
|
||||
{team: "humans", rank: 235, sessionID: "535f0cdfc2e83ad9048faef0", name: "Mobius", playtime: 0, wins: 87, losses: 288, score: -201}
|
||||
{team: "humans", rank: 236, sessionID: "537bbe446d5f9f2f06e0c674", name: "Lakk", playtime: 12072, wins: 76, losses: 296, score: -220}
|
||||
{team: "humans", rank: 237, sessionID: "535ac395d83daa1a052494c1", name: "Michael S.", playtime: 304, wins: 68, losses: 304, score: -236}
|
||||
{team: "humans", rank: 238, sessionID: "53718c6cce8e453b05c9d298", name: "Blitz", playtime: 0, wins: 68, losses: 306, score: -238}
|
||||
{team: "humans", rank: 239, sessionID: "536310848e22980605aa58c3", name: "sjarvie", playtime: 0, wins: 66, losses: 308, score: -242}
|
||||
{team: "humans", rank: 240, sessionID: "537ba10e51e98aa705b605df", name: "Deleu", playtime: 7241, wins: 61, losses: 307, score: -246}
|
||||
{team: "humans", rank: 241, sessionID: "537b92765bc02238050d1bf0", name: "Deneim", playtime: 13791, wins: 62, losses: 312, score: -250}
|
||||
{team: "humans", rank: 242, sessionID: "538e609af36910380515f8d6", name: "Volgax", playtime: 6774, wins: 59, losses: 310, score: -251}
|
||||
{team: "humans", rank: 243, sessionID: "537ba62557494fc405a6faac", name: "Zandrasco", playtime: 4193, wins: 60, losses: 315, score: -255}
|
||||
{team: "humans", rank: 244, sessionID: "537ecf5414bb1d38053b58bb", name: "Sir Mouse", playtime: 16021, wins: 52, losses: 321, score: -269}
|
||||
{team: "humans", rank: 245, sessionID: "538c8faf5572d43b05214e3b", name: "AceWizard", playtime: 54, wins: 45, losses: 315, score: -270}
|
||||
{team: "humans", rank: 246, sessionID: "537deb820efa6a37059df268", name: "MadMan30", playtime: 316, wins: 46, losses: 319, score: -273}
|
||||
{team: "humans", rank: 247, sessionID: "537bf38495356a43065f7291", name: "NicRio", playtime: 130, wins: 43, losses: 316, score: -273}
|
||||
{team: "humans", rank: 248, sessionID: "537cd876665bde1b13ffdad4", name: "Is_G", playtime: 776, wins: 44, losses: 319, score: -275}
|
||||
{team: "humans", rank: 249, sessionID: "537bb14b4f81f53805b6366a", name: "jeromeASF", playtime: 335, wins: 41, losses: 318, score: -277}
|
||||
{team: "humans", rank: 250, sessionID: "5381745005e52a3305df1c23", name: "El Psy Congr00", playtime: 1032, wins: 41, losses: 319, score: -278}
|
||||
{team: "humans", rank: 251, sessionID: "538451183e0daa39051845a0", name: "loquele", playtime: 549, wins: 43, losses: 322, score: -279}
|
||||
{team: "humans", rank: 252, sessionID: "537b606a2daeeb3905a9292f", name: "DeathStalker", playtime: 166, wins: 38, losses: 319, score: -281}
|
||||
{team: "humans", rank: 253, sessionID: "537bd56ab0d1766d05243002", name: "thelion", playtime: 338, wins: 40, losses: 323, score: -283}
|
||||
{team: "humans", rank: 254, sessionID: "537d15d37e1e10b705bbc6ef", name: "Diegobrp", playtime: 2132, wins: 37, losses: 321, score: -284}
|
||||
{team: "humans", rank: 255, sessionID: "537caa102f6e3aee0ed57f84", name: "Sakares Saengkaew", playtime: 34, wins: 37, losses: 321, score: -284}
|
||||
{team: "humans", rank: 256, sessionID: "53627e2fca5c6f3c11ebc9b1", name: "Animex", playtime: 0, wins: 38, losses: 324, score: -286}
|
||||
{team: "humans", rank: 257, sessionID: "537bc0ad1c8dfa820699fcb9", name: "Black Mage Wizard Guy", playtime: 691, wins: 37, losses: 323, score: -286}
|
||||
{team: "humans", rank: 258, sessionID: "535f07d39894af8f7fd84e85", name: "Maksym", playtime: 0, wins: 38, losses: 327, score: -289}
|
||||
{team: "humans", rank: 259, sessionID: "537b98e33803a287057582a8", name: "Angeland", playtime: 1758, wins: 41, losses: 330, score: -289}
|
||||
{team: "humans", rank: 260, sessionID: "537c63f426529de30cca37ba", name: "Dmitry", playtime: 181, wins: 35, losses: 325, score: -290}
|
||||
{team: "humans", rank: 261, sessionID: "537ceb1798a1be440545d40e", name: "jaba", playtime: 572, wins: 35, losses: 325, score: -290}
|
||||
{team: "humans", rank: 262, sessionID: "537c0f3f0ff88b2c06287c2b", name: "Quan Pham", playtime: 4353, wins: 40, losses: 332, score: -292}
|
||||
{team: "humans", rank: 263, sessionID: "537d60467e6f2dba051060b6", name: "rhall", playtime: 67548, wins: 11, losses: 316, score: -305}
|
||||
{team: "humans", rank: 264, sessionID: "5384c9de7d99a7390560bfd7", name: "Secathor", playtime: 16404, wins: 28, losses: 345, score: -317}
|
||||
{team: "humans", rank: 265, sessionID: "538a08bed06c503805feb6b0", name: "Nemoy", playtime: 1643, wins: 0, losses: 319, score: -319}
|
||||
{team: "humans", rank: 266, sessionID: "537c3806f1d9cfe4096ba9d8", name: "Hannofcart", playtime: 17397, wins: 0, losses: 323, score: -323}
|
||||
{team: "humans", rank: 267, sessionID: "537c4d5f26529de30cca2e68", name: "Morphumax", playtime: 58395, wins: 0, losses: 323, score: -323}
|
||||
{team: "humans", rank: 268, sessionID: "53864aa37d99a73905615dda", name: "shoetest", playtime: 14876, wins: 0, losses: 324, score: -324}
|
||||
{team: "humans", rank: 269, sessionID: "537b97cd556db17605be76c3", name: "domrein", playtime: 12339, wins: 0, losses: 324, score: -324}
|
||||
{team: "humans", rank: 270, sessionID: "53835f1fc85c223a05f49ddb", name: "hace", playtime: 9175, wins: 0, losses: 325, score: -325}
|
||||
{team: "humans", rank: 271, sessionID: "53666cc75af8b2c71dc017e8", name: "Bonesdog", playtime: 0, wins: 0, losses: 326, score: -326}
|
||||
{team: "humans", rank: 272, sessionID: "537be26d20a501380564e359", name: "Cinnamon Scrolls", playtime: 6619, wins: 0, losses: 330, score: -330}
|
||||
{team: "humans", rank: 273, sessionID: "537b8f3ce91b4d3b055262d7", name: "asdasd", playtime: 242330, wins: 0, losses: 335, score: -335}
|
||||
{team: "humans", rank: 274, sessionID: "5383551cc85c223a05f49992", name: "marthyi", playtime: 30008, wins: 325, losses: 43, score: 282}
|
||||
{team: "humans", rank: 275, sessionID: "538f5334f369103805167613", name: "Leshka", playtime: 10409, wins: 93, losses: 282, score: -189}
|
||||
]
|
||||
|
||||
results.greed.ogres = [
|
||||
{team: "ogres", rank: 1, sessionID: "537b958e6c13497e05de81f2", name: "Bellardia", playtime: 189111, wins: 387, losses: 7, score: 380}
|
||||
{team: "ogres", rank: 2, sessionID: "537c11df95356a43065f84c9", name: "blinkingTore", playtime: 38360, wins: 381, losses: 9, score: 372}
|
||||
{team: "ogres", rank: 3, sessionID: "537c09ee95356a43065f801c", name: "Eye", playtime: 172960, wins: 370, losses: 18, score: 352}
|
||||
{team: "ogres", rank: 4, sessionID: "537b7d475bc02238050d1439", name: "Cripi", playtime: 61966, wins: 373, losses: 23, score: 350}
|
||||
{team: "ogres", rank: 5, sessionID: "537e317450d1673a054b7dd2", name: "Pop-up", playtime: 39939, wins: 369, losses: 26, score: 343}
|
||||
{team: "ogres", rank: 6, sessionID: "537e364a50d1673a054b8322", name: "Ravenclaw", playtime: 4579, wins: 367, losses: 24, score: 343}
|
||||
{team: "ogres", rank: 7, sessionID: "537cb51fa0d7a5cc10992b11", name: "JerryP", playtime: 52872, wins: 368, losses: 33, score: 335}
|
||||
{team: "ogres", rank: 8, sessionID: "537bd37888a86e67053f9d61", name: "Mickydtron", playtime: 38533, wins: 368, losses: 35, score: 333}
|
||||
{team: "ogres", rank: 9, sessionID: "5384a3f63e0daa390518765d", name: "ProfBoesch", playtime: 10366, wins: 365, losses: 34, score: 331}
|
||||
{team: "ogres", rank: 10, sessionID: "538064d27585483905a77f9f", name: "KaosWalking", playtime: 88663, wins: 359, losses: 35, score: 324}
|
||||
{team: "ogres", rank: 11, sessionID: "53892a98d06c503805fe522b", name: "Urdaris", playtime: 87750, wins: 353, losses: 32, score: 321}
|
||||
{team: "ogres", rank: 12, sessionID: "53668d64c6ab10ef1ea9a10d", name: "no_login_found", playtime: 11313, wins: 355, losses: 46, score: 309}
|
||||
{team: "ogres", rank: 13, sessionID: "537f68bc14f08dec07950945", name: "Take it easy", playtime: 2839, wins: 348, losses: 47, score: 301}
|
||||
{team: "ogres", rank: 14, sessionID: "537bac56b0d477e005347f67", name: "gosunero", playtime: 41429, wins: 346, losses: 54, score: 292}
|
||||
{team: "ogres", rank: 15, sessionID: "536d258f68b5258d0c4b96ed", name: "Jex", playtime: 4910, wins: 337, losses: 48, score: 289}
|
||||
{team: "ogres", rank: 16, sessionID: "537bcba8a797656f07c93db5", name: "Durbination", playtime: 13465, wins: 337, losses: 49, score: 288}
|
||||
{team: "ogres", rank: 17, sessionID: "5381e48a7585483905a82a2d", name: "Edoardo Morandi", playtime: 96844, wins: 330, losses: 49, score: 281}
|
||||
{team: "ogres", rank: 18, sessionID: "538471737d99a73905608fb4", name: "Artraxus", playtime: 61114, wins: 336, losses: 60, score: 276}
|
||||
{team: "ogres", rank: 19, sessionID: "537ba9a154a7b1d5053bb45a", name: "skeltoac", playtime: 39087, wins: 330, losses: 55, score: 275}
|
||||
{team: "ogres", rank: 20, sessionID: "537be145a3b60b390500dcc3", name: "ReyO", playtime: 204112, wins: 328, losses: 55, score: 273}
|
||||
{team: "ogres", rank: 21, sessionID: "537cc939665bde1b13ffd197", name: "Orson Peters", playtime: 24821, wins: 333, losses: 60, score: 273}
|
||||
{team: "ogres", rank: 22, sessionID: "5395cf0b7362c439054f7c3a", name: "nino48", playtime: 33541, wins: 327, losses: 62, score: 265}
|
||||
{team: "ogres", rank: 23, sessionID: "537d541e3dcf67c40571f792", name: "pbd", playtime: 4062, wins: 319, losses: 84, score: 235}
|
||||
{team: "ogres", rank: 24, sessionID: "537e284650d1673a054b7602", name: "Tech", playtime: 13208, wins: 306, losses: 71, score: 235}
|
||||
{team: "ogres", rank: 25, sessionID: "537d025184c54c6e05c059b7", name: "Storm0x2a", playtime: 1026, wins: 306, losses: 71, score: 235}
|
||||
{team: "ogres", rank: 26, sessionID: "537bed83f575b482052f03a0", name: "Blindfold", playtime: 45865, wins: 303, losses: 69, score: 234}
|
||||
{team: "ogres", rank: 27, sessionID: "537bc4750de0a02c07e8797f", name: "Walter Danilo Galante", playtime: 24476, wins: 313, losses: 84, score: 229}
|
||||
{team: "ogres", rank: 28, sessionID: "538d0a4356c3613905301e50", name: "Fedux", playtime: 1862, wins: 300, losses: 79, score: 221}
|
||||
{team: "ogres", rank: 29, sessionID: "537b8cbee91b4d3b0552619e", name: "Nazywam", playtime: 6395, wins: 303, losses: 83, score: 220}
|
||||
{team: "ogres", rank: 30, sessionID: "5382502a7585483905a85e42", name: "vlizard", playtime: 803, wins: 308, losses: 89, score: 219}
|
||||
{team: "ogres", rank: 31, sessionID: "5385d1cf3e0daa3905191e57", name: "olu", playtime: 65635, wins: 301, losses: 86, score: 215}
|
||||
{team: "ogres", rank: 32, sessionID: "537babd003838cf0050acdf2", name: "Pentar", playtime: 36006, wins: 309, losses: 95, score: 214}
|
||||
{team: "ogres", rank: 33, sessionID: "537c31112b08c344082e22de", name: "Agathanar", playtime: 41371, wins: 308, losses: 94, score: 214}
|
||||
{team: "ogres", rank: 34, sessionID: "537cd98ae4523d0113ba5ac7", name: "Tehvudgaw", playtime: 81681, wins: 298, losses: 94, score: 204}
|
||||
{team: "ogres", rank: 35, sessionID: "537b803ae91b4d3b05525dc7", name: "Forsaken", playtime: 50237, wins: 294, losses: 91, score: 203}
|
||||
{team: "ogres", rank: 36, sessionID: "537b7e44e91b4d3b05525d38", name: "COGSMITH", playtime: 284674, wins: 300, losses: 98, score: 202}
|
||||
{team: "ogres", rank: 37, sessionID: "537ba3e0903fd2b80515539d", name: "Statik", playtime: 64062, wins: 294, losses: 98, score: 196}
|
||||
{team: "ogres", rank: 38, sessionID: "537b85e15bc02238050d16d4", name: "Cuef", playtime: 81666, wins: 286, losses: 90, score: 196}
|
||||
{team: "ogres", rank: 39, sessionID: "5392f7b1304ab93805efa3d2", name: "Cracker", playtime: 2576, wins: 282, losses: 90, score: 192}
|
||||
{team: "ogres", rank: 40, sessionID: "537b9c42ffeaa29e051b2657", name: "JamesJNadeau.com", playtime: 28164, wins: 295, losses: 110, score: 185}
|
||||
{team: "ogres", rank: 41, sessionID: "537ce37be9c4e97c05e3ea66", name: "Quasar", playtime: 21773, wins: 287, losses: 104, score: 183}
|
||||
{team: "ogres", rank: 42, sessionID: "537baa2403ff8dc005b8433e", name: "Almatia", playtime: 15387, wins: 291, losses: 109, score: 182}
|
||||
{team: "ogres", rank: 43, sessionID: "537b87f55bc02238050d1786", name: "mordonne", playtime: 71830, wins: 277, losses: 103, score: 174}
|
||||
{team: "ogres", rank: 44, sessionID: "537e56129008f87b0541cd03", name: "O'Connor", playtime: 55869, wins: 281, losses: 109, score: 172}
|
||||
{team: "ogres", rank: 45, sessionID: "537ba9e57b9ffadb05476784", name: "timmox", playtime: 13280, wins: 256, losses: 86, score: 170}
|
||||
{team: "ogres", rank: 46, sessionID: "537b86e75bc02238050d1721", name: "Tomas", playtime: 21845, wins: 275, losses: 106, score: 169}
|
||||
{team: "ogres", rank: 47, sessionID: "537bebbea3b60b390500e280", name: "Buge", playtime: 3506, wins: 281, losses: 118, score: 163}
|
||||
{team: "ogres", rank: 48, sessionID: "53854c0b7d99a7390560f9f4", name: "MatBot", playtime: 15049, wins: 281, losses: 119, score: 162}
|
||||
{team: "ogres", rank: 49, sessionID: "5380a9bb7585483905a79dff", name: "salesman", playtime: 60290, wins: 277, losses: 118, score: 159}
|
||||
{team: "ogres", rank: 50, sessionID: "53949f635009fe5b075bb584", name: "Dematerial", playtime: 4661, wins: 273, losses: 116, score: 157}
|
||||
{team: "ogres", rank: 51, sessionID: "53832a3ec85c223a05f48736", name: "Popey", playtime: 37593, wins: 256, losses: 104, score: 152}
|
||||
{team: "ogres", rank: 52, sessionID: "537b89a2e91b4d3b05526082", name: "Ryemane", playtime: 20671, wins: 276, losses: 125, score: 151}
|
||||
{team: "ogres", rank: 53, sessionID: "537cd542e4523d0113ba5782", name: "schups", playtime: 20886, wins: 277, losses: 127, score: 150}
|
||||
{team: "ogres", rank: 54, sessionID: "537be1cca3b60b390500dd24", name: "ohsnap", playtime: 3574, wins: 273, losses: 127, score: 146}
|
||||
{team: "ogres", rank: 55, sessionID: "538bef7356c36139052f8c80", name: "Hephaestian", playtime: 9626, wins: 272, losses: 131, score: 141}
|
||||
{team: "ogres", rank: 56, sessionID: "537c527026529de30cca302f", name: "Jinrai", playtime: 23726, wins: 269, losses: 129, score: 140}
|
||||
{team: "ogres", rank: 57, sessionID: "538471087d99a73905608f84", name: "Basque", playtime: 37986, wins: 269, losses: 130, score: 139}
|
||||
{team: "ogres", rank: 58, sessionID: "537cd3c3665bde1b13ffd74c", name: "Stormaggedon Dark Lord of All", playtime: 27471, wins: 261, losses: 123, score: 138}
|
||||
{team: "ogres", rank: 59, sessionID: "537b984f3803a2870575824f", name: "Cody", playtime: 85426, wins: 259, losses: 138, score: 121}
|
||||
{team: "ogres", rank: 60, sessionID: "5383ead92757353805a96ff4", name: "hotdogeater", playtime: 55657, wins: 258, losses: 137, score: 121}
|
||||
{team: "ogres", rank: 61, sessionID: "537d2a397e1e10b705bbd2c8", name: "PatchworkKnight", playtime: 23663, wins: 257, losses: 138, score: 119}
|
||||
{team: "ogres", rank: 62, sessionID: "537b8185e91b4d3b05525e3c", name: "FlameFrost", playtime: 29939, wins: 251, losses: 142, score: 109}
|
||||
{team: "ogres", rank: 63, sessionID: "537bb4168623bc410575f208", name: "NitrousDave", playtime: 29420, wins: 252, losses: 143, score: 109}
|
||||
{team: "ogres", rank: 64, sessionID: "537f4fa1c3067a7b07ba7786", name: "Zodd", playtime: 8820, wins: 248, losses: 140, score: 108}
|
||||
{team: "ogres", rank: 65, sessionID: "538358b978171d3d057eb471", name: "Lololala", playtime: 39892, wins: 252, losses: 144, score: 108}
|
||||
{team: "ogres", rank: 66, sessionID: "537f224c8fe881f1055dfb7e", name: "Artoemius", playtime: 1470, wins: 251, losses: 150, score: 101}
|
||||
{team: "ogres", rank: 67, sessionID: "537b7b25e91b4d3b05525b61", name: "Makaze", playtime: 21714, wins: 248, losses: 149, score: 99}
|
||||
{team: "ogres", rank: 68, sessionID: "537cf18c9cce053a05c0467f", name: "CodeBane", playtime: 39749, wins: 233, losses: 137, score: 96}
|
||||
{team: "ogres", rank: 69, sessionID: "537baac910c8a6e405b9cf92", name: "cooler", playtime: 49558, wins: 229, losses: 134, score: 95}
|
||||
{team: "ogres", rank: 70, sessionID: "5380d0a405e52a3305dec328", name: "DoctorTacoPhD", playtime: 9723, wins: 249, losses: 155, score: 94}
|
||||
{team: "ogres", rank: 71, sessionID: "53948cfc5009fe5b075ba92d", name: "zeus1200", playtime: 236, wins: 246, losses: 152, score: 94}
|
||||
{team: "ogres", rank: 72, sessionID: "537c66d114aaabe80c6a0072", name: "Vratislav", playtime: 21203, wins: 237, losses: 144, score: 93}
|
||||
{team: "ogres", rank: 73, sessionID: "537b996016613c8405155922", name: "Dafe", playtime: 701, wins: 232, losses: 140, score: 92}
|
||||
{team: "ogres", rank: 74, sessionID: "537b8271e91b4d3b05525e8e", name: "@billyvg", playtime: 20844, wins: 243, losses: 154, score: 89}
|
||||
{team: "ogres", rank: 75, sessionID: "537caafc2f6e3aee0ed58007", name: "Sakares", playtime: 1257, wins: 237, losses: 151, score: 86}
|
||||
{team: "ogres", rank: 76, sessionID: "538142de05e52a3305df037d", name: "Meowth", playtime: 12054, wins: 241, losses: 155, score: 86}
|
||||
{team: "ogres", rank: 77, sessionID: "537155a1ee35af3905987a87", name: "Lanner", playtime: 3658, wins: 236, losses: 152, score: 84}
|
||||
{team: "ogres", rank: 78, sessionID: "537b99573803a287057582e3", name: "DavyWong", playtime: 16467, wins: 242, losses: 161, score: 81}
|
||||
{team: "ogres", rank: 79, sessionID: "537be8fda3b60b390500e105", name: "BeAsT MoDe", playtime: 2097, wins: 234, losses: 153, score: 81}
|
||||
{team: "ogres", rank: 80, sessionID: "537b96696c13497e05de8271", name: "vkeg", playtime: 1883, wins: 236, losses: 157, score: 79}
|
||||
{team: "ogres", rank: 81, sessionID: "537ca60cb128a1850e083077", name: "SPAMR", playtime: 19978, wins: 233, losses: 154, score: 79}
|
||||
{team: "ogres", rank: 82, sessionID: "537b5662fe0ec03905fcdcd4", name: "pages", playtime: 22679, wins: 231, losses: 155, score: 76}
|
||||
{team: "ogres", rank: 83, sessionID: "537bf90295356a43065f7640", name: "", playtime: 167, wins: 218, losses: 144, score: 74}
|
||||
{team: "ogres", rank: 84, sessionID: "535de130c969efa7053345ab", name: "Racksickle", playtime: 319, wins: 231, losses: 157, score: 74}
|
||||
{team: "ogres", rank: 85, sessionID: "537c2facf67b6b1c08af376f", name: "greyworm", playtime: 22755, wins: 234, losses: 160, score: 74}
|
||||
{team: "ogres", rank: 86, sessionID: "537eef8c8fe881f1055dddb6", name: "huang123", playtime: 2590, wins: 234, losses: 161, score: 73}
|
||||
{team: "ogres", rank: 87, sessionID: "53934430304ab93805efcf4f", name: "LilDooda", playtime: 16603, wins: 229, losses: 156, score: 73}
|
||||
{team: "ogres", rank: 88, sessionID: "5389c83fb924da39051485d2", name: "nineties", playtime: 58607, wins: 183, losses: 113, score: 70}
|
||||
{team: "ogres", rank: 89, sessionID: "537b760f1ed81a3b05c4fbfe", name: "Xavion", playtime: 3593, wins: 229, losses: 159, score: 70}
|
||||
{team: "ogres", rank: 90, sessionID: "5383ec74087dc139054d8658", name: "cattycat", playtime: 384, wins: 228, losses: 160, score: 68}
|
||||
{team: "ogres", rank: 91, sessionID: "538375bb78171d3d057ebdb6", name: "Johnwg7", playtime: 65297, wins: 233, losses: 165, score: 68}
|
||||
{team: "ogres", rank: 92, sessionID: "537b99063803a287057582c1", name: "Simba", playtime: 16847, wins: 230, losses: 163, score: 67}
|
||||
{team: "ogres", rank: 93, sessionID: "53929b482446a4410538b59d", name: "Buh", playtime: 28766, wins: 230, losses: 165, score: 65}
|
||||
{team: "ogres", rank: 94, sessionID: "537bf9410ff88b2c06286e43", name: "Ulfberht", playtime: 26046, wins: 232, losses: 171, score: 61}
|
||||
{team: "ogres", rank: 95, sessionID: "537bc6e24add491607deaaa1", name: "Victor Hugo", playtime: 31094, wins: 221, losses: 163, score: 58}
|
||||
{team: "ogres", rank: 96, sessionID: "53809a807585483905a79529", name: "stderr", playtime: 20568, wins: 229, losses: 173, score: 56}
|
||||
{team: "ogres", rank: 97, sessionID: "537b8643e91b4d3b05525f83", name: "Austinh100", playtime: 12405, wins: 225, losses: 176, score: 49}
|
||||
{team: "ogres", rank: 98, sessionID: "537c7fad26529de30cca440d", name: "efraglebagga", playtime: 22417, wins: 219, losses: 172, score: 47}
|
||||
{team: "ogres", rank: 99, sessionID: "537dde5d933d99860613a256", name: "Meojifo", playtime: 50047, wins: 222, losses: 177, score: 45}
|
||||
{team: "ogres", rank: 100, sessionID: "537bc0eb467df184064bb865", name: "Diginaut", playtime: 8029, wins: 225, losses: 180, score: 45}
|
||||
{team: "ogres", rank: 101, sessionID: "538390336f3bea3a05faff49", name: "Ghostly_Cookie", playtime: 5804, wins: 221, losses: 177, score: 44}
|
||||
{team: "ogres", rank: 102, sessionID: "537f2cb8fdacc2fa050231bf", name: "crazydiv", playtime: 12170, wins: 212, losses: 170, score: 42}
|
||||
{team: "ogres", rank: 103, sessionID: "537ef0e78fe881f1055dde46", name: "Æ", playtime: 97439, wins: 204, losses: 163, score: 41}
|
||||
{team: "ogres", rank: 104, sessionID: "537b96f216613c84051557f1", name: "mda", playtime: 11544, wins: 222, losses: 181, score: 41}
|
||||
{team: "ogres", rank: 105, sessionID: "537b8231e91b4d3b05525e7e", name: "BobFranz", playtime: 632, wins: 222, losses: 184, score: 38}
|
||||
{team: "ogres", rank: 106, sessionID: "537b9a1d3803a2870575835f", name: "pvande", playtime: 39177, wins: 216, losses: 179, score: 37}
|
||||
{team: "ogres", rank: 107, sessionID: "537c23fffa0d80a106b10eb4", name: "Nylan", playtime: 1236, wins: 204, losses: 174, score: 30}
|
||||
{team: "ogres", rank: 108, sessionID: "537b91795bc02238050d1b80", name: "Orange!", playtime: 22940, wins: 210, losses: 181, score: 29}
|
||||
{team: "ogres", rank: 109, sessionID: "537b8cfde91b4d3b055261b6", name: "Thumb", playtime: 22271, wins: 212, losses: 185, score: 27}
|
||||
{team: "ogres", rank: 110, sessionID: "53978487888ab73905184003", name: "Nick2", playtime: 5539, wins: 197, losses: 173, score: 24}
|
||||
{team: "ogres", rank: 111, sessionID: "5386313f8ca8b1120b8b58a3", name: "fudgy", playtime: 2744, wins: 213, losses: 193, score: 20}
|
||||
{team: "ogres", rank: 112, sessionID: "537cbcc062dea6b811f109c7", name: "Kirstin", playtime: 23151, wins: 211, losses: 192, score: 19}
|
||||
{team: "ogres", rank: 113, sessionID: "53814d4605e52a3305df086c", name: "jsut", playtime: 21961, wins: 208, losses: 189, score: 19}
|
||||
{team: "ogres", rank: 114, sessionID: "5384c51f7d99a7390560bce1", name: "Xhuy", playtime: 4562, wins: 204, losses: 188, score: 16}
|
||||
{team: "ogres", rank: 115, sessionID: "536259c5fc1acf300b2ebcb7", name: "DarthNato", playtime: 26611, wins: 206, losses: 193, score: 13}
|
||||
{team: "ogres", rank: 116, sessionID: "538db7f65572d43b0521cf9c", name: "rehashed", playtime: 12008, wins: 201, losses: 188, score: 13}
|
||||
{team: "ogres", rank: 117, sessionID: "5361946c801ef0010d3a3369", name: "DeathScythe", playtime: 0, wins: 209, losses: 197, score: 12}
|
||||
{team: "ogres", rank: 118, sessionID: "537f5d073282d7a5076952e6", name: "kraxor", playtime: 14420, wins: 191, losses: 179, score: 12}
|
||||
{team: "ogres", rank: 119, sessionID: "537bc98ba968548907de6dad", name: "Huragok", playtime: 325, wins: 207, losses: 197, score: 10}
|
||||
{team: "ogres", rank: 120, sessionID: "53718545d0d9b1370555448b", name: "SuchNoob", playtime: 0, wins: 196, losses: 188, score: 8}
|
||||
{team: "ogres", rank: 121, sessionID: "538a1888b924da390514c2d6", name: "Lomidrevo", playtime: 9470, wins: 207, losses: 199, score: 8}
|
||||
{team: "ogres", rank: 122, sessionID: "537b92265bc02238050d1bc3", name: "Drew", playtime: 21829, wins: 199, losses: 192, score: 7}
|
||||
{team: "ogres", rank: 123, sessionID: "537b976e556db17605be769e", name: "Drak", playtime: 9554, wins: 202, losses: 197, score: 5}
|
||||
{team: "ogres", rank: 124, sessionID: "5380b07205e52a3305deb2ea", name: "LinaLin", playtime: 1852, wins: 204, losses: 199, score: 5}
|
||||
{team: "ogres", rank: 125, sessionID: "537b84de5bc02238050d1699", name: "WoLfulus", playtime: 9762, wins: 204, losses: 200, score: 4}
|
||||
{team: "ogres", rank: 126, sessionID: "537b7f945bc02238050d14d8", name: "Shack", playtime: 16108, wins: 199, losses: 197, score: 2}
|
||||
{team: "ogres", rank: 127, sessionID: "537badf8ec57a3e805cbf577", name: "borreltijd", playtime: 29749, wins: 202, losses: 203, score: -1}
|
||||
{team: "ogres", rank: 128, sessionID: "537f8306ead05fd3075d1d39", name: "icoderz", playtime: 5382, wins: 202, losses: 204, score: -2}
|
||||
{team: "ogres", rank: 129, sessionID: "537b92b55bc02238050d1c18", name: "Bullcity", playtime: 7478, wins: 197, losses: 204, score: -7}
|
||||
{team: "ogres", rank: 130, sessionID: "537ba0937c89ec9805f4df2f", name: "Pavlov", playtime: 15761, wins: 198, losses: 205, score: -7}
|
||||
{team: "ogres", rank: 131, sessionID: "537b85055bc02238050d16a6", name: "Drunk McLovin", playtime: 10225, wins: 194, losses: 204, score: -10}
|
||||
{team: "ogres", rank: 132, sessionID: "537cbb38a0d7a5cc10992ee9", name: "Aion Crane", playtime: 9616, wins: 195, losses: 206, score: -11}
|
||||
{team: "ogres", rank: 133, sessionID: "537be31fa3b60b390500ddc5", name: "antkim003", playtime: 19059, wins: 195, losses: 206, score: -11}
|
||||
{team: "ogres", rank: 134, sessionID: "537d20d97e1e10b705bbcd58", name: "Tain", playtime: 28374, wins: 173, losses: 189, score: -16}
|
||||
{team: "ogres", rank: 135, sessionID: "537bb6d6386abb6e05a3facf", name: "RTN", playtime: 4108, wins: 194, losses: 211, score: -17}
|
||||
{team: "ogres", rank: 136, sessionID: "537b86b95bc02238050d1706", name: "Luogbelnu", playtime: 24526, wins: 191, losses: 208, score: -17}
|
||||
{team: "ogres", rank: 137, sessionID: "537338f73108bc3905f7528d", name: "chess", playtime: 321, wins: 192, losses: 213, score: -21}
|
||||
{team: "ogres", rank: 138, sessionID: "537df0950efa6a37059df463", name: "Rury", playtime: 14371, wins: 187, losses: 215, score: -28}
|
||||
{team: "ogres", rank: 139, sessionID: "537c11290ff88b2c06287d29", name: "Crustopher", playtime: 15401, wins: 167, losses: 195, score: -28}
|
||||
{team: "ogres", rank: 140, sessionID: "537df96a0efa6a37059df853", name: "HuangSY", playtime: 34229, wins: 178, losses: 209, score: -31}
|
||||
{team: "ogres", rank: 141, sessionID: "537b909f5bc02238050d1b32", name: "ArthurDent", playtime: 63903, wins: 173, losses: 204, score: -31}
|
||||
{team: "ogres", rank: 142, sessionID: "537e901b9008f87b0541fc83", name: "Mawox", playtime: 15961, wins: 186, losses: 218, score: -32}
|
||||
{team: "ogres", rank: 143, sessionID: "537fa33bf56c5874086896cc", name: "Urg", playtime: 1760, wins: 182, losses: 218, score: -36}
|
||||
{team: "ogres", rank: 144, sessionID: "53854e7d7d99a7390560fadd", name: "Dodrithard", playtime: 4087, wins: 160, losses: 196, score: -36}
|
||||
{team: "ogres", rank: 145, sessionID: "537bfa3395356a43065f76bd", name: "Cicir", playtime: 7369, wins: 183, losses: 221, score: -38}
|
||||
{team: "ogres", rank: 146, sessionID: "537ba4f3d60bb0b405d852b2", name: "Dubastot", playtime: 17312, wins: 160, losses: 201, score: -41}
|
||||
{team: "ogres", rank: 147, sessionID: "537b8dbbe91b4d3b05526226", name: "Raetsel", playtime: 11005, wins: 180, losses: 223, score: -43}
|
||||
{team: "ogres", rank: 148, sessionID: "537bc0b31c8dfa820699fcc2", name: "Source Error", playtime: 1731, wins: 171, losses: 214, score: -43}
|
||||
{team: "ogres", rank: 149, sessionID: "537b92dde91b4d3b05526442", name: "Script Pimpkin", playtime: 18711, wins: 180, losses: 225, score: -45}
|
||||
{team: "ogres", rank: 150, sessionID: "538f33d0755876370525988f", name: "Rigamortis", playtime: 23232, wins: 176, losses: 221, score: -45}
|
||||
{team: "ogres", rank: 151, sessionID: "537c8bb826529de30cca4b02", name: "Static", playtime: 673, wins: 167, losses: 216, score: -49}
|
||||
{team: "ogres", rank: 152, sessionID: "537bdd5ed3f3bb3305bd997a", name: "Tuna", playtime: 4854, wins: 177, losses: 226, score: -49}
|
||||
{team: "ogres", rank: 153, sessionID: "537b945d556db17605be74d0", name: "Dino", playtime: 5413, wins: 177, losses: 227, score: -50}
|
||||
{team: "ogres", rank: 154, sessionID: "537bcda2c57303a5070c2f3a", name: "LaughingMan", playtime: 52476, wins: 170, losses: 222, score: -52}
|
||||
{team: "ogres", rank: 155, sessionID: "53825ebf78171d3d057e4e48", name: "Lord Azrael", playtime: 25968, wins: 175, losses: 227, score: -52}
|
||||
{team: "ogres", rank: 156, sessionID: "537d19307e1e10b705bbc877", name: "Naoki", playtime: 7851, wins: 172, losses: 226, score: -54}
|
||||
{team: "ogres", rank: 157, sessionID: "537b95526c13497e05de81d2", name: "Gromliqk", playtime: 15566, wins: 174, losses: 230, score: -56}
|
||||
{team: "ogres", rank: 158, sessionID: "537bacbc03838cf0050ace6f", name: "cameltoe", playtime: 53128, wins: 171, losses: 230, score: -59}
|
||||
{team: "ogres", rank: 159, sessionID: "537b82d75bc02238050d160d", name: "Kithid", playtime: 14756, wins: 169, losses: 229, score: -60}
|
||||
{team: "ogres", rank: 160, sessionID: "537d4e5d3dcf67c40571f5c3", name: "bonnnie", playtime: 25945, wins: 173, losses: 233, score: -60}
|
||||
{team: "ogres", rank: 161, sessionID: "537e4d7a63734c6305059374", name: "kotowlos", playtime: 6498, wins: 172, losses: 233, score: -61}
|
||||
{team: "ogres", rank: 162, sessionID: "537b80425bc02238050d152c", name: "mdz", playtime: 12720, wins: 167, losses: 229, score: -62}
|
||||
{team: "ogres", rank: 163, sessionID: "537bb50218bd7f4705b9d459", name: "Claros", playtime: 1250, wins: 170, losses: 236, score: -66}
|
||||
{team: "ogres", rank: 164, sessionID: "537c8a5626529de30cca4a2f", name: "nulo", playtime: 5264, wins: 168, losses: 236, score: -68}
|
||||
{team: "ogres", rank: 165, sessionID: "537bb4598698e13805226b77", name: "JojoTheGreat", playtime: 1733, wins: 162, losses: 235, score: -73}
|
||||
{team: "ogres", rank: 166, sessionID: "537bab9b89a8aeea05970d0b", name: "gameloop.io", playtime: 2823, wins: 163, losses: 237, score: -74}
|
||||
{team: "ogres", rank: 167, sessionID: "5382411905e52a3305df893b", name: "Richard Adleta", playtime: 3272, wins: 162, losses: 240, score: -78}
|
||||
{team: "ogres", rank: 168, sessionID: "537c4408a56c78cb0cb4f353", name: "lichens", playtime: 59782, wins: 163, losses: 241, score: -78}
|
||||
{team: "ogres", rank: 169, sessionID: "537e1ab60efa6a37059e0bf0", name: "Scnoobi", playtime: 3430, wins: 159, losses: 239, score: -80}
|
||||
{team: "ogres", rank: 170, sessionID: "537f6adc14f08dec07950ab2", name: "Ralphy282", playtime: 42208, wins: 155, losses: 235, score: -80}
|
||||
{team: "ogres", rank: 171, sessionID: "537be8d820a501380564e6e7", name: "gandalfStormcrow", playtime: 435, wins: 162, losses: 242, score: -80}
|
||||
{team: "ogres", rank: 172, sessionID: "537bc4b10de0a02c07e879a8", name: "", playtime: 872, wins: 161, losses: 242, score: -81}
|
||||
{team: "ogres", rank: 173, sessionID: "537e581863734c6305059a53", name: "taz", playtime: 24420, wins: 160, losses: 242, score: -82}
|
||||
{team: "ogres", rank: 174, sessionID: "537ce331e9c4e97c05e3ea34", name: "bb", playtime: 391, wins: 159, losses: 245, score: -86}
|
||||
{team: "ogres", rank: 175, sessionID: "537c5f4f14aaabe80c69fd70", name: "@ESWAT", playtime: 13389, wins: 152, losses: 239, score: -87}
|
||||
{team: "ogres", rank: 176, sessionID: "537b8a515bc02238050d1873", name: "joshuacarley", playtime: 23663, wins: 156, losses: 244, score: -88}
|
||||
{team: "ogres", rank: 177, sessionID: "537d550d3dcf67c40571f7dc", name: "J'Son", playtime: 5290, wins: 156, losses: 246, score: -90}
|
||||
{team: "ogres", rank: 178, sessionID: "537c05ef95356a43065f7e1c", name: "Cerbi", playtime: 9095, wins: 151, losses: 250, score: -99}
|
||||
{team: "ogres", rank: 179, sessionID: "537c532126529de30cca3067", name: "warrned", playtime: 3870, wins: 149, losses: 254, score: -105}
|
||||
{team: "ogres", rank: 180, sessionID: "537fc780c1a6b99109171791", name: "OWalerys", playtime: 18624, wins: 146, losses: 251, score: -105}
|
||||
{team: "ogres", rank: 181, sessionID: "537efa7e8fe881f1055de25e", name: "Smaug", playtime: 14526, wins: 146, losses: 253, score: -107}
|
||||
{team: "ogres", rank: 182, sessionID: "537bf37d95356a43065f7286", name: "cokaroach", playtime: 47117, wins: 124, losses: 237, score: -113}
|
||||
{team: "ogres", rank: 183, sessionID: "537e304e64659f3a0577248a", name: "Plak87", playtime: 5459, wins: 144, losses: 259, score: -115}
|
||||
{team: "ogres", rank: 184, sessionID: "537cfe4d9cce053a05c04dc2", name: "xzores", playtime: 9686, wins: 145, losses: 260, score: -115}
|
||||
{team: "ogres", rank: 185, sessionID: "537bb0ad2323353a05bd57ef", name: "Wicked", playtime: 4520, wins: 140, losses: 258, score: -118}
|
||||
{team: "ogres", rank: 186, sessionID: "537cd1c4665bde1b13ffd635", name: "Delforas", playtime: 3970, wins: 138, losses: 258, score: -120}
|
||||
{team: "ogres", rank: 187, sessionID: "53806a8405e52a3305de92fa", name: "Pabelo", playtime: 4629, wins: 141, losses: 262, score: -121}
|
||||
{team: "ogres", rank: 188, sessionID: "537fcc57c1a6b99109171ced", name: "jhoie", playtime: 1045, wins: 137, losses: 259, score: -122}
|
||||
{team: "ogres", rank: 189, sessionID: "5395d1ba7362c439054f7e6e", name: "JenJen", playtime: 151, wins: 137, losses: 259, score: -122}
|
||||
{team: "ogres", rank: 190, sessionID: "537b9dc4ffeaa29e051b2738", name: "Kevin", playtime: 9970, wins: 136, losses: 263, score: -127}
|
||||
{team: "ogres", rank: 191, sessionID: "537b9c09ffeaa29e051b2637", name: "Tuefekci", playtime: 10790, wins: 131, losses: 259, score: -128}
|
||||
{team: "ogres", rank: 192, sessionID: "537c5b3526529de30cca340c", name: "patchnotes", playtime: 31167, wins: 119, losses: 252, score: -133}
|
||||
{team: "ogres", rank: 193, sessionID: "5380fdb47585483905a7c753", name: "null0pointer", playtime: 9524, wins: 131, losses: 266, score: -135}
|
||||
{team: "ogres", rank: 194, sessionID: "537b9f4751e98aa705b60515", name: "Sawyer", playtime: 9450, wins: 136, losses: 271, score: -135}
|
||||
{team: "ogres", rank: 195, sessionID: "5380bd747585483905a7a707", name: "Lobo", playtime: 5280, wins: 132, losses: 269, score: -137}
|
||||
{team: "ogres", rank: 196, sessionID: "5382593bc85c223a05f429d9", name: "squidlarkin", playtime: 2036, wins: 130, losses: 267, score: -137}
|
||||
{team: "ogres", rank: 197, sessionID: "537cd5fee4523d0113ba57ea", name: "Borlak", playtime: 14470, wins: 133, losses: 271, score: -138}
|
||||
{team: "ogres", rank: 198, sessionID: "537bbb201aaa69c4052676fd", name: "jMerliN", playtime: 3292, wins: 129, losses: 270, score: -141}
|
||||
{team: "ogres", rank: 199, sessionID: "537be3c7a3b60b390500de0e", name: "Dragon DM", playtime: 17848, wins: 131, losses: 274, score: -143}
|
||||
{team: "ogres", rank: 200, sessionID: "537b90295bc02238050d1af5", name: "octopushugs", playtime: 706, wins: 125, losses: 270, score: -145}
|
||||
{team: "ogres", rank: 201, sessionID: "5380d5be7585483905a7b1e1", name: "Quaritch", playtime: 12711, wins: 128, losses: 274, score: -146}
|
||||
{team: "ogres", rank: 202, sessionID: "5397732542cf7d3905ed7233", name: "BloodJohn", playtime: 5178, wins: 127, losses: 276, score: -149}
|
||||
{team: "ogres", rank: 203, sessionID: "537cab3d0e905d000fbfad57", name: "Xor", playtime: 19480, wins: 126, losses: 278, score: -152}
|
||||
{team: "ogres", rank: 204, sessionID: "537b88f85bc02238050d17e2", name: "Jojas", playtime: 9328, wins: 126, losses: 278, score: -152}
|
||||
{team: "ogres", rank: 205, sessionID: "539436745009fe5b075b70a7", name: "Vhr", playtime: 3065, wins: 122, losses: 274, score: -152}
|
||||
{team: "ogres", rank: 206, sessionID: "535f0c4b11c0ebd2049d1664", name: "Jebso", playtime: 0, wins: 125, losses: 278, score: -153}
|
||||
{team: "ogres", rank: 207, sessionID: "537b9d3cffeaa29e051b26eb", name: "", playtime: 784, wins: 125, losses: 278, score: -153}
|
||||
{team: "ogres", rank: 208, sessionID: "537c3bdb54bc23770a21e166", name: "seaclair", playtime: 385, wins: 122, losses: 279, score: -157}
|
||||
{team: "ogres", rank: 209, sessionID: "537bf147f8b46fbd0544fc15", name: "", playtime: 16376, wins: 109, losses: 269, score: -160}
|
||||
{team: "ogres", rank: 210, sessionID: "537bd2e0be90aa5605fb2ebd", name: "educavalcanti", playtime: 50086, wins: 121, losses: 282, score: -161}
|
||||
{team: "ogres", rank: 211, sessionID: "537cd0e0665bde1b13ffd5ca", name: "itsbth", playtime: 1299, wins: 104, losses: 265, score: -161}
|
||||
{team: "ogres", rank: 212, sessionID: "537b8e1ee91b4d3b05526274", name: "Jorge", playtime: 4728, wins: 118, losses: 280, score: -162}
|
||||
{team: "ogres", rank: 213, sessionID: "537b88f6e91b4d3b05526048", name: "CzonI", playtime: 3033, wins: 120, losses: 283, score: -163}
|
||||
{team: "ogres", rank: 214, sessionID: "537b7c26e91b4d3b05525c6a", name: "TTSS", playtime: 1132, wins: 120, losses: 283, score: -163}
|
||||
{team: "ogres", rank: 215, sessionID: "5389d73bb924da3905149015", name: "oli-f", playtime: 10824, wins: 101, losses: 266, score: -165}
|
||||
{team: "ogres", rank: 216, sessionID: "537b8c21e91b4d3b0552616d", name: "Luke Young", playtime: 10713, wins: 117, losses: 285, score: -168}
|
||||
{team: "ogres", rank: 217, sessionID: "537b84e15bc02238050d169c", name: "", playtime: 359, wins: 116, losses: 284, score: -168}
|
||||
{team: "ogres", rank: 218, sessionID: "537b845fe91b4d3b05525f03", name: "walesmd", playtime: 1630, wins: 116, losses: 285, score: -169}
|
||||
{team: "ogres", rank: 219, sessionID: "538515a73e0daa390518ba45", name: "Azerroth", playtime: 19862, wins: 114, losses: 285, score: -171}
|
||||
{team: "ogres", rank: 220, sessionID: "537bd660142ee637052420e3", name: "tkl", playtime: 8276, wins: 102, losses: 278, score: -176}
|
||||
{team: "ogres", rank: 221, sessionID: "538a9449b924da3905151926", name: "cdaaar", playtime: 14955, wins: 45, losses: 222, score: -177}
|
||||
{team: "ogres", rank: 222, sessionID: "538345b078171d3d057eae61", name: "Ikrus", playtime: 13687, wins: 111, losses: 295, score: -184}
|
||||
{team: "ogres", rank: 223, sessionID: "537b8e26e91b4d3b05526277", name: "Zairja", playtime: 10077, wins: 101, losses: 293, score: -192}
|
||||
{team: "ogres", rank: 224, sessionID: "537b97f53803a28705758218", name: "kookieblues", playtime: 2400, wins: 104, losses: 303, score: -199}
|
||||
{team: "ogres", rank: 225, sessionID: "537d06bd7e1e10b705bbbe83", name: "llcossette", playtime: 2648, wins: 95, losses: 302, score: -207}
|
||||
{team: "ogres", rank: 226, sessionID: "537b800de91b4d3b05525db8", name: "Merlin Gough", playtime: 8942, wins: 90, losses: 303, score: -213}
|
||||
{team: "ogres", rank: 227, sessionID: "538382db86de19c31c1ce893", name: "Nick05 Testinator", playtime: 1454, wins: 90, losses: 311, score: -221}
|
||||
{team: "ogres", rank: 228, sessionID: "537bcd7ec57303a5070c2f1e", name: "hedint", playtime: 8881, wins: 92, losses: 314, score: -222}
|
||||
{team: "ogres", rank: 229, sessionID: "537cc425665bde1b13ffce89", name: "dotnetjohn", playtime: 1304, wins: 87, losses: 315, score: -228}
|
||||
{team: "ogres", rank: 230, sessionID: "537c3c1454bc23770a21e187", name: "Prelude", playtime: 2351, wins: 85, losses: 313, score: -228}
|
||||
{team: "ogres", rank: 231, sessionID: "538925b4d06c503805fe4ff7", name: "Perenolder", playtime: 21235, wins: 79, losses: 322, score: -243}
|
||||
{team: "ogres", rank: 232, sessionID: "538a26cdd06c503805fec706", name: "the-k-man", playtime: 10321, wins: 78, losses: 327, score: -249}
|
||||
{team: "ogres", rank: 233, sessionID: "537c531d26529de30cca3065", name: "masashi", playtime: 17871, wins: 75, losses: 330, score: -255}
|
||||
{team: "ogres", rank: 234, sessionID: "5371861fd4491339051c3b11", name: "asdlk;fj asd fas", playtime: 0, wins: 65, losses: 333, score: -268}
|
||||
{team: "ogres", rank: 235, sessionID: "537b8429e91b4d3b05525ef5", name: "Missblit", playtime: 28639, wins: 59, losses: 346, score: -287}
|
||||
{team: "ogres", rank: 236, sessionID: "538b1322d06c503805ff299f", name: "judar1o", playtime: 5891, wins: 59, losses: 347, score: -288}
|
||||
{team: "ogres", rank: 237, sessionID: "53583ab57962157d05b398f8", name: "makertech81", playtime: 170, wins: 55, losses: 344, score: -289}
|
||||
{team: "ogres", rank: 238, sessionID: "539723388376eb3805dc2d4e", name: "immersion", playtime: 6471, wins: 54, losses: 348, score: -294}
|
||||
{team: "ogres", rank: 239, sessionID: "537c99aa14aaabe80c6a1a44", name: "werewolf", playtime: 167, wins: 46, losses: 343, score: -297}
|
||||
{team: "ogres", rank: 240, sessionID: "539085aaf369103805172236", name: "Kabbi", playtime: 6873, wins: 43, losses: 344, score: -301}
|
||||
{team: "ogres", rank: 241, sessionID: "537bd587b0d1766d05243016", name: "Casey", playtime: 1229, wins: 44, losses: 346, score: -302}
|
||||
{team: "ogres", rank: 242, sessionID: "537e2bd864659f3a05772075", name: "", playtime: 322, wins: 42, losses: 349, score: -307}
|
||||
{team: "ogres", rank: 243, sessionID: "5385c7503e0daa39051919db", name: "Zack", playtime: 66, wins: 40, losses: 348, score: -308}
|
||||
{team: "ogres", rank: 244, sessionID: "537ba0a551e98aa705b605b2", name: "", playtime: 232, wins: 39, losses: 349, score: -310}
|
||||
{team: "ogres", rank: 245, sessionID: "535fdebe5c7324a80702cb3b", name: "mich55", playtime: 0, wins: 38, losses: 349, score: -311}
|
||||
{team: "ogres", rank: 246, sessionID: "5390823e7558763705263cc8", name: "Duchess", playtime: 460, wins: 37, losses: 349, score: -312}
|
||||
{team: "ogres", rank: 247, sessionID: "5360a43d9859fefb0673aefa", name: "daruba", playtime: 0, wins: 34, losses: 351, score: -317}
|
||||
{team: "ogres", rank: 248, sessionID: "537bab4f6e54cbda057ee565", name: "Pajamas", playtime: 27043, wins: 14, losses: 338, score: -324}
|
||||
{team: "ogres", rank: 249, sessionID: "537bf053f8b46fbd0544fb8c", name: "Fusspawn", playtime: 9524, wins: 37, losses: 368, score: -331}
|
||||
{team: "ogres", rank: 250, sessionID: "5382f069c85c223a05f47200", name: "ferrak", playtime: 7015, wins: 33, losses: 373, score: -340}
|
||||
{team: "ogres", rank: 251, sessionID: "5380a3737585483905a799e1", name: "Dark Pikachu", playtime: 1373, wins: 29, losses: 377, score: -348}
|
||||
{team: "ogres", rank: 252, sessionID: "538711898ca8b1120b8bdb3f", name: "A", playtime: 4272, wins: 24, losses: 380, score: -356}
|
||||
{team: "ogres", rank: 253, sessionID: "5384af823e0daa3905187cb1", name: "Macguffin", playtime: 837, wins: 18, losses: 384, score: -366}
|
||||
{team: "ogres", rank: 254, sessionID: "537db76b13add33a051bf575", name: "Luyalve", playtime: 1404, wins: 3, losses: 372, score: -369}
|
||||
{team: "ogres", rank: 255, sessionID: "537b9bac16613c8405155a79", name: "solarian", playtime: 24889, wins: 0, losses: 371, score: -371}
|
||||
{team: "ogres", rank: 256, sessionID: "537ba09951e98aa705b605ae", name: "Potato", playtime: 61777, wins: 0, losses: 371, score: -371}
|
||||
{team: "ogres", rank: 257, sessionID: "537d24db84c54c6e05c06ac4", name: "terriblesarcasm", playtime: 39553, wins: 0, losses: 371, score: -371}
|
||||
{team: "ogres", rank: 258, sessionID: "537c2abc224747bb0761634f", name: "chicones", playtime: 9831, wins: 0, losses: 371, score: -371}
|
||||
{team: "ogres", rank: 259, sessionID: "538381a5c83e563705a06fdb", name: "diddly-dum", playtime: 8077, wins: 0, losses: 372, score: -372}
|
||||
{team: "ogres", rank: 260, sessionID: "5388a785b924da3905139f46", name: "AWESOMEHACKER", playtime: 564, wins: 0, losses: 372, score: -372}
|
||||
{team: "ogres", rank: 261, sessionID: "537bb6d2386abb6e05a3facc", name: "chrm", playtime: 213307, wins: 0, losses: 375, score: -375}
|
||||
{team: "ogres", rank: 262, sessionID: "537bc26e8fe668b406d4c019", name: "Sapid", playtime: 11917, wins: 0, losses: 376, score: -376}
|
||||
{team: "ogres", rank: 263, sessionID: "5357127a1bfa9bba14b5e048", name: "dcm</script><script>alert('XSS')</script>", playtime: 5380, wins: 0, losses: 376, score: -376}
|
||||
{team: "ogres", rank: 264, sessionID: "537aee4cfb4c173805cf26f7", name: "basicer", playtime: 10407, wins: 0, losses: 376, score: -376}
|
||||
{team: "ogres", rank: 265, sessionID: "5382cbb078171d3d057e804f", name: "vvv", playtime: 719, wins: 0, losses: 376, score: -376}
|
||||
{team: "ogres", rank: 266, sessionID: "537ba40a903fd2b8051553b0", name: "ElderTale", playtime: 13984, wins: 0, losses: 376, score: -376}
|
||||
{team: "ogres", rank: 267, sessionID: "53839e256f3bea3a05fb09b3", name: "Gondolfs", playtime: 29985, wins: 0, losses: 378, score: -378}
|
||||
{team: "ogres", rank: 268, sessionID: "537a73a6e488a7380545affd", name: "Galvan", playtime: 514, wins: 0, losses: 378, score: -378}
|
||||
{team: "ogres", rank: 269, sessionID: "537b96b16c13497e05de82a8", name: "Krris", playtime: 2618, wins: 0, losses: 379, score: -379}
|
||||
{team: "ogres", rank: 270, sessionID: "537bc1b81db8c8ac063a3b7b", name: "jpiasetz", playtime: 14565, wins: 0, losses: 380, score: -380}
|
||||
]
|
|
@ -79,7 +79,7 @@ module.exports = class EditorConfigModal extends View
|
|||
Backbone.Mediator.publish 'tome:change-config'
|
||||
Backbone.Mediator.publish 'tome:change-language', language: newLanguage unless newLanguage is oldLanguage
|
||||
@session.save() unless newLanguage is oldLanguage
|
||||
me.save()
|
||||
me.patch()
|
||||
|
||||
destroy: ->
|
||||
super()
|
||||
|
|
|
@ -81,7 +81,7 @@ module.exports = class VictoryModal extends View
|
|||
if enough and not me.get('hourOfCodeComplete')
|
||||
$('body').append($("<img src='http://code.org/api/hour/finish_codecombat.png' style='visibility: hidden;'>"))
|
||||
me.set 'hourOfCodeComplete', true
|
||||
me.save()
|
||||
me.patch()
|
||||
window.tracker?.trackEvent 'Hour of Code Finish', {}
|
||||
# Show the "I'm done" button if they get to the end, unless it's been over two hours
|
||||
tooMuch = elapsed >= 120 * 60 * 1000
|
||||
|
|
|
@ -355,7 +355,7 @@ module.exports = class PlaybackView extends View
|
|||
onToggleMusic: (e) ->
|
||||
e?.preventDefault()
|
||||
me.set('music', not me.get('music'))
|
||||
me.save()
|
||||
me.patch()
|
||||
$(document.activeElement).blur()
|
||||
|
||||
destroy: ->
|
||||
|
|
|
@ -97,7 +97,7 @@ module.exports = class CastButtonView extends View
|
|||
return unless delay
|
||||
@autocastDelay = delay = parseInt delay
|
||||
me.set('autocastDelay', delay)
|
||||
me.save()
|
||||
me.patch()
|
||||
spell.view.setAutocastDelay delay for spellKey, spell of @spells
|
||||
@castOptions.find('a').each ->
|
||||
$(@).toggleClass('selected', parseInt($(@).attr('data-delay')) is delay)
|
||||
|
|
|
@ -24,7 +24,7 @@ module.exports = class Spell
|
|||
@permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams
|
||||
teamSpells = @session.get('teamSpells')
|
||||
team = @session.get('team') ? 'humans'
|
||||
@useTranspiledCode = @permissions.readwrite.length and ((teamSpells and not _.contains(teamSpells[team], @spellKey)) or (@session.get('creator') isnt me.id) or @spectateView)
|
||||
@useTranspiledCode = @permissions.readwrite.length and ((teamSpells and not _.contains(teamSpells[team], @spellKey)) or (@session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))) or @spectateView)
|
||||
#console.log @spellKey, "using transpiled code?", @useTranspiledCode
|
||||
@source = @originalSource = p.source
|
||||
@parameters = p.parameters
|
||||
|
|
|
@ -93,7 +93,7 @@ module.exports = class PlayLevelView extends View
|
|||
|
||||
setUpHourOfCode: ->
|
||||
me.set 'hourOfCode', true
|
||||
me.save()
|
||||
me.patch()
|
||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
|
||||
|
|
|
@ -211,14 +211,21 @@ module.exports = class PlayView extends View
|
|||
difficulty: 3
|
||||
id: 'bubble-sort-bootcamp-battle'
|
||||
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
|
||||
description: "Write a bubble sort to organize your soldiers. - by Alexandru"
|
||||
description: "Write a bubble sort to organize your soldiers. - by Alexandru Caciulescu"
|
||||
}
|
||||
{
|
||||
name: 'Ogres of Hanoi'
|
||||
difficulty: 3
|
||||
id: 'ogres-of-hanoi'
|
||||
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
|
||||
description: "Transfer a stack of ogres while preserving their honor. - by Alexandru"
|
||||
description: "Transfer a stack of ogres while preserving their honor. - by Alexandru Caciulescu"
|
||||
}
|
||||
{
|
||||
name: 'Danger! Minefield'
|
||||
difficulty: 3
|
||||
id: 'danger-minefield'
|
||||
image: '/file/db/level/526bda3fe79aefde2a003e36/mobile_artillery_icon.png'
|
||||
description: "Learn how to find prime numbers while defusing mines! - by Alexandru Caciulescu"
|
||||
}
|
||||
{
|
||||
name: 'Find the Spy'
|
||||
|
@ -234,15 +241,6 @@ module.exports = class PlayView extends View
|
|||
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
|
||||
description: "Collect a hundred mushrooms in just five lines of code - by Nathan Gossett"
|
||||
}
|
||||
|
||||
#{
|
||||
# name: 'Enemy Artillery'
|
||||
# difficulty: 1
|
||||
# id: 'enemy-artillery'
|
||||
# image: '/file/db/level/526dba94a188322044000a40/mobile_artillery_icon.png'
|
||||
# description: "Take cover while shells fly, then strike! - by mcdavid1991"
|
||||
# disabled: true
|
||||
#}
|
||||
]
|
||||
|
||||
context.campaigns = [
|
||||
|
|
|
@ -107,6 +107,7 @@ module.exports = TestView = class TestView extends CocoView
|
|||
# TODO Stubbify more things
|
||||
# * document.location
|
||||
# * firebase
|
||||
# * all the services that load in main.html
|
||||
|
||||
afterEach ->
|
||||
# TODO Clean up more things
|
||||
|
|
|
@ -88,5 +88,8 @@ mongo_db_path = os.path.abspath(os.path.join(current_directory,os.pardir)) + os.
|
|||
if not os.path.exists(mongo_db_path):
|
||||
os.mkdir(mongo_db_path)
|
||||
mongo_arguments = [mongo_executable + u" --setParameter textSearchEnabled=true --dbpath=" + mongo_db_path]
|
||||
|
||||
if 'fork' in sys.argv: mongo_arguments[0] += " --fork --logpath ./mongodb.log"
|
||||
|
||||
call(mongo_arguments,shell=True)
|
||||
|
||||
|
|
|
@ -3,14 +3,10 @@ startsWith = (string, substring) ->
|
|||
string.lastIndexOf(substring, 0) is 0
|
||||
|
||||
exports.config =
|
||||
server:
|
||||
path: 'server.coffee'
|
||||
paths:
|
||||
'public': 'public'
|
||||
conventions:
|
||||
ignored: (path) -> startsWith(sysPath.basename(path), '_')
|
||||
workers:
|
||||
enabled: false # turned out to be much, much slower than without workers
|
||||
sourceMaps: true
|
||||
files:
|
||||
javascripts:
|
||||
|
@ -55,7 +51,6 @@ exports.config =
|
|||
'vendor/scripts/movieclip-NEXT.min.js'
|
||||
# Validated Backbone Mediator dependencies
|
||||
'bower_components/tv4/tv4.js'
|
||||
|
||||
# Aether before box2d for some strange Object.defineProperty thing
|
||||
'bower_components/aether/build/aether.js'
|
||||
'bower_components/d3/d3.min.js'
|
||||
|
@ -77,7 +72,7 @@ exports.config =
|
|||
|
||||
plugins:
|
||||
autoReload:
|
||||
delay: 300 # for race conditions, particularly waiting for onCompile to do its thing
|
||||
delay: 300
|
||||
coffeelint:
|
||||
pattern: /^app\/.*\.coffee$/
|
||||
options:
|
||||
|
|
|
@ -7,9 +7,10 @@ async = require 'async'
|
|||
|
||||
serverSetup = require '../server_setup'
|
||||
sendwithus = require '../server/sendwithus'
|
||||
User = require '../server/users/User.coffee'
|
||||
Level = require '../server/levels/Level.coffee'
|
||||
LevelSession = require '../server/levels/sessions/LevelSession.coffee'
|
||||
User = require '../server/users/User'
|
||||
Level = require '../server/levels/Level'
|
||||
LevelSession = require '../server/levels/sessions/LevelSession'
|
||||
tournamentResults = require '../app/views/play/ladder/tournament_results'
|
||||
|
||||
alreadyEmailed = []
|
||||
|
||||
|
@ -27,7 +28,7 @@ sendInitialRecruitingEmail = ->
|
|||
async.waterfall [
|
||||
(callback) -> async.map leaderboards, grabSessions, callback
|
||||
(sessionLists, callback) -> async.map collapseSessions(sessionLists), grabUser, callback
|
||||
(users, callback) -> async.map users, emailUser, callback
|
||||
(users, callback) -> async.map users, emailUserInitialRecruiting, callback
|
||||
], (err, results) ->
|
||||
return console.log "Error:", err if err
|
||||
console.log "Looked at sending to #{results.length} users; sent to #{_.filter(results).length}."
|
||||
|
@ -77,7 +78,7 @@ grabUser = (session, callback) ->
|
|||
callback null, user
|
||||
|
||||
totalEmailsSent = 0
|
||||
emailUser = (user, callback) ->
|
||||
emailUserInitialRecruiting = (user, callback) ->
|
||||
#return callback null, false if user.emails?.anyNotes?.enabled is false # TODO: later, uncomment to obey also "anyNotes" when that's untangled
|
||||
return callback null, false if user.emails?.recruitNotes?.enabled is false
|
||||
return callback null, false if user.email in alreadyEmailed
|
||||
|
@ -102,5 +103,64 @@ emailUser = (user, callback) ->
|
|||
return callback err if err
|
||||
callback null, user
|
||||
|
||||
|
||||
sendTournamentResultsEmail = ->
|
||||
winners = tournamentResults.greed.humans.concat tournamentResults.greed.ogres
|
||||
async.waterfall [
|
||||
(callback) -> async.map winners, grabSession, callback
|
||||
(winners, callback) -> async.map winners, grabEmail, callback
|
||||
(winners, callback) -> async.map winners, emailUserTournamentResults, callback
|
||||
], (err, results) ->
|
||||
return console.log "Error:", err if err
|
||||
console.log "Looked at sending to #{results.length} users; sent to #{_.filter(results).length}."
|
||||
console.log "Sent to: ['#{(user.email for user in results when user).join('\', \'')}']"
|
||||
|
||||
grabSession = (winner, callback) ->
|
||||
LevelSession.findOne(_id: winner.sessionID).select('creator').lean().exec (err, session) ->
|
||||
return callback err if err
|
||||
winner.userID = session.creator
|
||||
callback null, winner
|
||||
|
||||
grabEmail = (winner, callback) ->
|
||||
User.findOne(_id: winner.userID).select('email').lean().exec (err, user) ->
|
||||
return callback err if err
|
||||
winner.email = user.email
|
||||
callback null, winner
|
||||
|
||||
emailUserTournamentResults = (winner, callback) ->
|
||||
return callback null, false if DEBUGGING and (winner.team is 'humans' or totalEmailsSent > 1)
|
||||
++totalEmailsSent
|
||||
name = winner.name
|
||||
team = winner.team.substr(0, winner.team.length - 1)
|
||||
context =
|
||||
email_id: sendwithus.templates.greed_tournament_rank
|
||||
recipient:
|
||||
address: if DEBUGGING then 'nick@codecombat.com' else winner.email
|
||||
name: name
|
||||
email_data:
|
||||
userID: winner.userID
|
||||
name: name
|
||||
level_name: "Greed"
|
||||
wins: winner.wins
|
||||
ties: {humans: 377, ogres: 407}[winner.team] - winner.wins - winner.losses
|
||||
losses: winner.losses
|
||||
rank: winner.rank
|
||||
team_name: team
|
||||
ladder_url: "http://codecombat.com/play/ladder/greed#winners"
|
||||
top3: winner.rank <= 3
|
||||
top5: winner.rank <= 5
|
||||
top10: winner.rank <= 10
|
||||
top40: winner.rank <= 40
|
||||
top100: winner.rank <= 100
|
||||
sendwithus.api.send context, (err, result) ->
|
||||
return callback err if err
|
||||
callback null, winner
|
||||
|
||||
|
||||
serverSetup.connectToDatabase()
|
||||
sendInitialRecruitingEmail()
|
||||
|
||||
fn = process.argv[2]
|
||||
try
|
||||
eval fn + '()'
|
||||
catch err
|
||||
console.log "Error running #{fn}", err
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
mongoose = require('mongoose')
|
||||
plugins = require('../plugins/plugins')
|
||||
jsonschema = require('../../app/schemas/models/achievement')
|
||||
log = require 'winston'
|
||||
util = require '../../app/lib/utils'
|
||||
plugins = require('../plugins/plugins')
|
||||
|
||||
# `pre` and `post` are not called for update operations executed directly on the database,
|
||||
# including `Model.update`,`.findByIdAndUpdate`,`.findOneAndUpdate`, `.findOneAndRemove`,and `.findByIdAndRemove`.order
|
||||
|
@ -12,16 +13,21 @@ AchievementSchema = new mongoose.Schema({
|
|||
userField: String
|
||||
}, {strict: false})
|
||||
|
||||
AchievementSchema.methods.objectifyQuery = () ->
|
||||
AchievementSchema.methods.objectifyQuery = ->
|
||||
try
|
||||
@set('query', JSON.parse(@get('query'))) if typeof @get('query') == "string"
|
||||
catch error
|
||||
log.error "Couldn't convert query string to object because of #{error}"
|
||||
@set('query', {})
|
||||
|
||||
AchievementSchema.methods.stringifyQuery = () ->
|
||||
AchievementSchema.methods.stringifyQuery = ->
|
||||
@set('query', JSON.stringify(@get('query'))) if typeof @get('query') != "string"
|
||||
|
||||
getExpFunction: ->
|
||||
kind = @get('function')?.kind or jsonschema.function.default.kind
|
||||
parameters = @get('function')?.parameters or jsonschema.function.default.parameters
|
||||
return utils.functionCreators[kind](parameters) if kind of utils.functionCreators
|
||||
|
||||
AchievementSchema.post('init', (doc) -> doc.objectifyQuery())
|
||||
|
||||
AchievementSchema.pre('save', (next) ->
|
||||
|
@ -33,3 +39,7 @@ AchievementSchema.plugin(plugins.NamedPlugin)
|
|||
AchievementSchema.plugin(plugins.SearchablePlugin, {searchable: ['name']})
|
||||
|
||||
module.exports = Achievement = mongoose.model('Achievement', AchievementSchema)
|
||||
|
||||
# Reload achievements upon save
|
||||
AchievablePlugin = require '../plugins/achievements'
|
||||
AchievementSchema.post 'save', (doc) -> AchievablePlugin.loadAchievements()
|
||||
|
|
|
@ -13,7 +13,15 @@ EarnedAchievementSchema = new mongoose.Schema({
|
|||
default: false
|
||||
}, {strict:false})
|
||||
|
||||
EarnedAchievementSchema.pre 'save', (next) ->
|
||||
@set('changed', Date.now())
|
||||
next()
|
||||
|
||||
EarnedAchievementSchema.index({user: 1, achievement: 1}, {unique: true, name: 'earned achievement index'})
|
||||
EarnedAchievementSchema.index({user: 1, changed: -1}, {name: 'latest '})
|
||||
|
||||
module.exports = EarnedAchievement = mongoose.model('EarnedAchievement', EarnedAchievementSchema)
|
||||
|
||||
module.exports = EarnedAchievement = mongoose.model('EarnedAchievement', EarnedAchievementSchema)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,17 +5,11 @@ class AchievementHandler extends Handler
|
|||
modelClass: Achievement
|
||||
|
||||
# Used to determine which properties requests may edit
|
||||
editableProperties: ['name', 'query', 'worth', 'collection', 'description', 'userField', 'proportionalTo', 'icon']
|
||||
editableProperties: ['name', 'query', 'worth', 'collection', 'description', 'userField', 'proportionalTo', 'icon', 'function']
|
||||
jsonSchema = require '../../app/schemas/models/achievement.coffee'
|
||||
|
||||
hasAccess: (req) ->
|
||||
req.method is 'GET' or req.user?.isAdmin()
|
||||
|
||||
get: (req, res) ->
|
||||
query = @modelClass.find({})
|
||||
query.exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (@formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
|
||||
module.exports = new AchievementHandler()
|
||||
|
|
|
@ -1,12 +1,115 @@
|
|||
mongoose = require('mongoose')
|
||||
log = require 'winston'
|
||||
mongoose = require 'mongoose'
|
||||
async = require 'async'
|
||||
Achievement = require './Achievement'
|
||||
EarnedAchievement = require './EarnedAchievement'
|
||||
User = require '../users/User'
|
||||
Handler = require '../commons/Handler'
|
||||
LocalMongo = require '../../app/lib/LocalMongo'
|
||||
|
||||
class EarnedAchievementHandler extends Handler
|
||||
modelClass: EarnedAchievement
|
||||
|
||||
# Don't allow POSTs or anything yet
|
||||
hasAccess: (req) ->
|
||||
req.method is 'GET'
|
||||
req.method is 'GET' # or req.user.isAdmin()
|
||||
|
||||
recalculate: (req, res) ->
|
||||
onSuccess = (data) => log.debug "Finished recalculating achievements"
|
||||
if 'achievements' of req.body # Support both slugs and IDs separated by commas
|
||||
achievementSlugsOrIDs = req.body.achievements
|
||||
EarnedAchievementHandler.recalculate achievementSlugsOrIDs, onSuccess
|
||||
else
|
||||
EarnedAchievementHandler.recalculate onSuccess
|
||||
@sendSuccess res, {}
|
||||
|
||||
# Returns success: boolean
|
||||
# TODO call onFinished
|
||||
@recalculate: (callbackOrSlugsOrIDs, onFinished) ->
|
||||
if _.isArray callbackOrSlugsOrIDs
|
||||
achievementSlugs = (thing for thing in callbackOrSlugsOrIDs when not Handler.isID(thing))
|
||||
achievementIDs = (thing for thing in callbackOrSlugsOrIDs when Handler.isID(thing))
|
||||
else
|
||||
onFinished = callbackOrSlugsOrIDs
|
||||
|
||||
filter = {}
|
||||
filter.$or = [
|
||||
{_id: $in: achievementIDs},
|
||||
{slug: $in: achievementSlugs}
|
||||
] if achievementSlugs? or achievementIDs?
|
||||
|
||||
# Fetch all relevant achievements
|
||||
Achievement.find filter, (err, achievements) ->
|
||||
return log.error err if err?
|
||||
|
||||
# Fetch every single user
|
||||
User.find {}, (err, users) ->
|
||||
_.each users, (user) ->
|
||||
# Keep track of a user's already achieved in order to set the notified values correctly
|
||||
userID = user.get('_id').toHexString()
|
||||
|
||||
# Fetch all of a user's earned achievements
|
||||
EarnedAchievement.find {user: userID}, (err, alreadyEarned) ->
|
||||
alreadyEarnedIDs = []
|
||||
previousPoints = 0
|
||||
_.each alreadyEarned, (earned) ->
|
||||
if (_.find achievements, (single) -> earned.get('achievement') is single.get('_id').toHexString())
|
||||
alreadyEarnedIDs.push earned.get('achievement')
|
||||
previousPoints += earned.get 'earnedPoints'
|
||||
|
||||
# TODO maybe also delete earned? Make sure you don't delete too many
|
||||
|
||||
newTotalPoints = 0
|
||||
|
||||
earnedAchievementSaverGenerator = (achievement) -> (callback) ->
|
||||
isRepeatable = achievement.get('proportionalTo')?
|
||||
model = mongoose.model(achievement.get('collection'))
|
||||
if not model?
|
||||
log.error "Model #{achievement.get 'collection'} doesn't even exist."
|
||||
return callback()
|
||||
|
||||
model.findOne achievement.query, (err, something) ->
|
||||
return callback() unless something
|
||||
|
||||
log.debug "Matched an achievement: #{achievement.get 'name'}"
|
||||
|
||||
earned =
|
||||
user: userID
|
||||
achievement: achievement._id.toHexString()
|
||||
achievementName: achievement.get 'name'
|
||||
notified: achievement._id in alreadyEarnedIDs
|
||||
|
||||
if isRepeatable
|
||||
earned.achievedAmount = something.get(achievement.get 'proportionalTo')
|
||||
earned.previouslyAchievedAmount = 0
|
||||
|
||||
expFunction = achievement.getExpFunction()
|
||||
newPoints = expFunction(earned.achievedAmount) * achievement.get('worth')
|
||||
else
|
||||
newPoints = achievement.get 'worth'
|
||||
|
||||
earned.earnedPoints = newPoints
|
||||
newTotalPoints += newPoints
|
||||
|
||||
EarnedAchievement.update {achievement:earned.achievement, user:earned.user}, earned, {upsert: true}, (err) ->
|
||||
log.error err if err?
|
||||
callback()
|
||||
|
||||
saveUserPoints = (callback) ->
|
||||
# In principle it is enough to deduct the old amount of points and add the new amount,
|
||||
# but just to be entirely safe let's start from 0 in case we're updating all of a user's achievements
|
||||
log.debug "Matched a total of #{newTotalPoints} new points"
|
||||
if _.isEmpty filter # Completely clean
|
||||
User.update {_id: userID}, {$set: points: newTotalPoints}, {}, (err) -> log.error err if err?
|
||||
else
|
||||
log.debug "Incrementing score for these achievements with #{newTotalPoints - previousPoints}"
|
||||
User.update {_id: userID}, {$inc: points: newTotalPoints - previousPoints}, {}, (err) -> log.error err if err?
|
||||
|
||||
earnedAchievementSavers = (earnedAchievementSaverGenerator(achievement) for achievement in achievements)
|
||||
earnedAchievementSavers.push saveUserPoints
|
||||
|
||||
# We need to have all these database updates chained so we know the final score
|
||||
async.series earnedAchievementSavers
|
||||
|
||||
|
||||
module.exports = new EarnedAchievementHandler()
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = class Handler
|
|||
postEditableProperties: []
|
||||
jsonSchema: {}
|
||||
waterfallFunctions: []
|
||||
allowedMethods: ['GET', 'POST', 'PUT', 'PATCH']
|
||||
|
||||
# subclasses should override these methods
|
||||
hasAccess: (req) -> true
|
||||
|
@ -63,26 +64,72 @@ module.exports = class Handler
|
|||
|
||||
# generic handlers
|
||||
get: (req, res) ->
|
||||
# by default, ordinary users never get unfettered access to the database
|
||||
return @sendUnauthorizedError(res) unless req.user?.isAdmin()
|
||||
@sendUnauthorizedError(res) if not @hasAccess(req)
|
||||
|
||||
# admins can send any sort of query down the wire, though
|
||||
conditions = JSON.parse(req.query.conditions || '[]')
|
||||
query = @modelClass.find()
|
||||
specialParameters = ['term', 'project', 'conditions']
|
||||
|
||||
try
|
||||
for condition in conditions
|
||||
name = condition[0]
|
||||
f = query[name]
|
||||
args = condition[1..]
|
||||
query = query[name](args...)
|
||||
catch e
|
||||
return @sendError(res, 422, 'Badly formed conditions.')
|
||||
# If the model uses coco search it's probably a text search
|
||||
if @modelClass.schema.uses_coco_search
|
||||
term = req.query.term
|
||||
matchedObjects = []
|
||||
filters = if @modelClass.schema.uses_coco_versions or @modelClass.schema.uses_coco_permissions then [filter: {index: true}] else [filter: {}]
|
||||
if @modelClass.schema.uses_coco_permissions and req.user
|
||||
filters.push {filter: {index: req.user.get('id')}}
|
||||
projection = null
|
||||
if req.query.project is 'true'
|
||||
projection = PROJECT
|
||||
else if req.query.project
|
||||
if @modelClass.className is 'User'
|
||||
projection = PROJECT
|
||||
log.warn "Whoa, we haven't yet thought about public properties for User projection yet."
|
||||
else
|
||||
projection = {}
|
||||
projection[field] = 1 for field in req.query.project.split(',')
|
||||
for filter in filters
|
||||
callback = (err, results) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
for r in results.results ? results
|
||||
obj = r.obj ? r
|
||||
continue if obj in matchedObjects # TODO: probably need a better equality check
|
||||
matchedObjects.push obj
|
||||
filters.pop() # doesn't matter which one
|
||||
unless filters.length
|
||||
res.send matchedObjects
|
||||
res.end()
|
||||
if term
|
||||
filter.project = projection
|
||||
@modelClass.textSearch term, filter, callback
|
||||
else
|
||||
args = [filter.filter]
|
||||
args.push projection if projection
|
||||
@modelClass.find(args...).limit(FETCH_LIMIT).exec callback
|
||||
# if it's not a text search but the user is an admin, let him try stuff anyway
|
||||
else if req.user?.isAdmin()
|
||||
# admins can send any sort of query down the wire
|
||||
filter = {}
|
||||
filter[key] = (val for own key, val of req.query.filter when key not in specialParameters) if 'filter' of req.query
|
||||
|
||||
query = @modelClass.find(filter)
|
||||
|
||||
# Conditions are chained query functions, for example: query.find().limit(20).sort('-dateCreated')
|
||||
conditions = JSON.parse(req.query.conditions || '[]')
|
||||
try
|
||||
for condition in conditions
|
||||
name = condition[0]
|
||||
f = query[name]
|
||||
args = condition[1..]
|
||||
query = query[name](args...)
|
||||
catch e
|
||||
return @sendError(res, 422, 'Badly formed conditions.')
|
||||
|
||||
query.exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (@formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
# regular users are only allowed text searches for now, without any additional filters or sorting
|
||||
else
|
||||
return @sendUnauthorizedError(res)
|
||||
|
||||
query.exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (@formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
|
||||
getById: (req, res, id) ->
|
||||
# return @sendNotFoundError(res) # for testing
|
||||
|
@ -153,44 +200,6 @@ module.exports = class Handler
|
|||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, document))
|
||||
|
||||
# project=true or project=name,description,slug for example
|
||||
search: (req, res) ->
|
||||
unless @modelClass.schema.uses_coco_search
|
||||
return @sendNotFoundError(res)
|
||||
term = req.query.term
|
||||
matchedObjects = []
|
||||
filters = if @modelClass.schema.uses_coco_versions or @modelClass.schema.uses_coco_permissions then [filter: {index: true}] else [filter: {}]
|
||||
if @modelClass.schema.uses_coco_permissions and req.user
|
||||
filters.push {filter: {index: req.user.get('id')}}
|
||||
projection = null
|
||||
if req.query.project is 'true'
|
||||
projection = PROJECT
|
||||
else if req.query.project
|
||||
if @modelClass.className is 'User'
|
||||
projection = PROJECT
|
||||
log.warn "Whoa, we haven't yet thought about public properties for User projection yet."
|
||||
else
|
||||
projection = {}
|
||||
projection[field] = 1 for field in req.query.project.split(',')
|
||||
for filter in filters
|
||||
callback = (err, results) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
for r in results.results ? results
|
||||
obj = r.obj ? r
|
||||
continue if obj in matchedObjects # TODO: probably need a better equality check
|
||||
matchedObjects.push obj
|
||||
filters.pop() # doesn't matter which one
|
||||
unless filters.length
|
||||
res.send matchedObjects
|
||||
res.end()
|
||||
if term
|
||||
filter.project = projection
|
||||
@modelClass.textSearch term, filter, callback
|
||||
else
|
||||
args = [filter.filter]
|
||||
args.push projection if projection
|
||||
@modelClass.find(args...).limit(FETCH_LIMIT).exec callback
|
||||
|
||||
versions: (req, res, id) ->
|
||||
# TODO: a flexible system for doing GAE-like cursors for these sort of paginating queries
|
||||
# Keeping it simple for now and just allowing access to the first FETCH_LIMIT results.
|
||||
|
@ -420,3 +429,7 @@ module.exports = class Handler
|
|||
dict[document.id] = document
|
||||
res.send dict
|
||||
res.end()
|
||||
|
||||
delete: (req, res) -> @sendMethodNotAllowed res, @allowedMethods, "DELETE not allowed."
|
||||
|
||||
head: (req, res) -> @sendMethodNotAllowed res, @allowedMethods, "HEAD not allowed."
|
||||
|
|
|
@ -17,8 +17,9 @@ module.exports.notFound = (res, message='Not found.') ->
|
|||
res.send 404, message
|
||||
res.end()
|
||||
|
||||
module.exports.badMethod = (res, message='Method Not Allowed') ->
|
||||
# TODO: The response MUST include an Allow header containing a list of valid methods for the requested resource
|
||||
module.exports.badMethod = (res, allowed=['GET', 'POST', 'PUT', 'PATCH'], message='Method Not Allowed') ->
|
||||
allowHeader = _.reduce allowed, ((str, current) -> str += ', ' + current)
|
||||
res.set 'Allow', allowHeader # TODO not sure if these are always the case
|
||||
res.send 405, message
|
||||
res.end()
|
||||
|
||||
|
@ -40,4 +41,4 @@ module.exports.gatewayTimeoutError = (res, message="Gateway timeout") ->
|
|||
|
||||
module.exports.clientTimeout = (res, message="The server did not recieve the client response in a timely manner") ->
|
||||
res.send 408, message
|
||||
res.end()
|
||||
res.end()
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports.handlers =
|
|||
|
||||
module.exports.routes =
|
||||
[
|
||||
'routes/admin'
|
||||
'routes/auth'
|
||||
'routes/contact'
|
||||
'routes/db'
|
||||
|
|
|
@ -9,7 +9,7 @@ LevelComponentHandler = class LevelComponentHandler extends Handler
|
|||
'description'
|
||||
'code'
|
||||
'js'
|
||||
'language'
|
||||
'codeLanguage'
|
||||
'dependencies'
|
||||
'propertyDocumentation'
|
||||
'configSchema'
|
||||
|
@ -25,4 +25,4 @@ LevelComponentHandler = class LevelComponentHandler extends Handler
|
|||
req.method is 'GET' or req.user?.isAdmin()
|
||||
|
||||
|
||||
module.exports = new LevelComponentHandler()
|
||||
module.exports = new LevelComponentHandler()
|
||||
|
|
|
@ -14,14 +14,14 @@ class LevelSessionHandler extends Handler
|
|||
getByRelationship: (req, res, args...) ->
|
||||
return @getActiveSessions req, res if args.length is 2 and args[1] is 'active'
|
||||
super(arguments...)
|
||||
|
||||
|
||||
formatEntity: (req, document) ->
|
||||
documentObject = super(req, document)
|
||||
if req.user.isAdmin() or req.user.id is document.creator
|
||||
if req.user.isAdmin() or req.user.id is document.creator or ('employer' in req.user.get('permissions'))
|
||||
return documentObject
|
||||
else
|
||||
return _.omit documentObject, ['submittedCode','code']
|
||||
|
||||
|
||||
getActiveSessions: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
||||
start = new Date()
|
||||
|
@ -34,6 +34,7 @@ class LevelSessionHandler extends Handler
|
|||
|
||||
hasAccessToDocument: (req, document, method=null) ->
|
||||
return true if req.method is 'GET' and document.get('totalScore')
|
||||
return true if ('employer' in req.user.get('permissions')) and (method ? req.method).toLowerCase() is 'get'
|
||||
super(arguments...)
|
||||
|
||||
module.exports = new LevelSessionHandler()
|
||||
|
|
|
@ -7,7 +7,7 @@ LevelSystemHandler = class LevelSystemHandler extends Handler
|
|||
'description'
|
||||
'code'
|
||||
'js'
|
||||
'language'
|
||||
'codeLanguage'
|
||||
'dependencies'
|
||||
'propertyDocumentation'
|
||||
'configSchema'
|
||||
|
|
|
@ -1,24 +1,15 @@
|
|||
mongoose = require('mongoose')
|
||||
Achievement = require('../achievements/Achievement')
|
||||
EarnedAchievement = require '../achievements/EarnedAchievement'
|
||||
User = require '../users/User'
|
||||
LocalMongo = require '../../app/lib/LocalMongo'
|
||||
util = require '../../app/lib/utils'
|
||||
log = require 'winston'
|
||||
|
||||
achievements = {}
|
||||
|
||||
loadAchievements = ->
|
||||
achievements = {}
|
||||
query = Achievement.find({})
|
||||
query.exec (err, docs) ->
|
||||
_.each docs, (achievement) ->
|
||||
category = achievement.get 'collection'
|
||||
achievements[category] = [] unless category of achievements
|
||||
achievements[category].push achievement
|
||||
loadAchievements()
|
||||
|
||||
module.exports = AchievablePlugin = (schema, options) ->
|
||||
User = require '../users/User' # Avoid mutual inclusion cycles
|
||||
Achievement = require('../achievements/Achievement')
|
||||
|
||||
checkForAchievement = (doc) ->
|
||||
collectionName = doc.constructor.modelName
|
||||
|
||||
|
@ -53,6 +44,8 @@ module.exports = AchievablePlugin = (schema, options) ->
|
|||
achievement: achievement._id.toHexString()
|
||||
achievementName: achievement.get 'name'
|
||||
}
|
||||
|
||||
worth = achievement.get('worth')
|
||||
earnedPoints = 0
|
||||
wrapUp = ->
|
||||
# Update user's experience points
|
||||
|
@ -67,23 +60,37 @@ module.exports = AchievablePlugin = (schema, options) ->
|
|||
newAmount = docObj[proportionalTo]
|
||||
|
||||
if originalAmount isnt newAmount
|
||||
expFunction = achievement.getExpFunction()
|
||||
earned.notified = false
|
||||
earned.achievedAmount = newAmount
|
||||
earned.changed = Date.now()
|
||||
EarnedAchievement.findOneAndUpdate({achievement:earned.achievement, user:earned.user}, earned, upsert:true, (err, docs) ->
|
||||
return log.debug err if err?
|
||||
)
|
||||
earned.earnedPoints = (expFunction(newAmount) - expFunction(originalAmount)) * worth
|
||||
earned.previouslyAchievedAmount = originalAmount
|
||||
EarnedAchievement.update {achievement:earned.achievement, user:earned.user}, earned, {upsert: true}, (err) ->
|
||||
return log.debug err if err?
|
||||
|
||||
earnedPoints = achievement.get('worth') * (newAmount - originalAmount)
|
||||
earnedPoints = earned.earnedPoints
|
||||
log.debug earnedPoints
|
||||
wrapUp()
|
||||
|
||||
else # not alreadyAchieved
|
||||
log.debug 'Creating a new earned achievement called \'' + (achievement.get 'name') + '\' for ' + userID
|
||||
earned.earnedPoints = worth
|
||||
(new EarnedAchievement(earned)).save (err, doc) ->
|
||||
return log.debug err if err?
|
||||
|
||||
earnedPoints = achievement.get('worth')
|
||||
earnedPoints = worth
|
||||
wrapUp()
|
||||
|
||||
delete before[doc.id] unless isNew # This assumes everything we patch has a _id
|
||||
return
|
||||
|
||||
module.exports.loadAchievements = ->
|
||||
achievements = {}
|
||||
Achievement = require('../achievements/Achievement')
|
||||
query = Achievement.find({})
|
||||
query.exec (err, docs) ->
|
||||
_.each docs, (achievement) ->
|
||||
category = achievement.get 'collection'
|
||||
achievements[category] = [] unless category of achievements
|
||||
achievements[category].push achievement
|
||||
|
||||
AchievablePlugin.loadAchievements()
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
mongoose = require('mongoose')
|
||||
User = require('../users/User')
|
||||
textSearch = require('mongoose-text-search')
|
||||
|
||||
module.exports.MigrationPlugin = (schema, migrations) ->
|
||||
# Property name migrations made EZ
|
||||
# This is for just when you want one property to be named differently
|
||||
|
||||
# 1. Change the schema and the client/server logic to use the new name
|
||||
# 2. Add this plugin to the target models, passing in a dictionary of old/new names.
|
||||
# 3. Check that tests still run, deploy to production.
|
||||
# 4. Run db.<collection>.update({}, { $rename: {'<oldname>':'<newname>'} }, { multi: true }) on the server
|
||||
# 5. Remove the names you added to the migrations dictionaries for the next deploy
|
||||
|
||||
schema.post 'init', ->
|
||||
for oldKey in _.keys migrations
|
||||
val = @get oldKey
|
||||
@set oldKey, undefined
|
||||
continue if val is undefined
|
||||
newKey = migrations[oldKey]
|
||||
@set newKey, val
|
||||
|
||||
module.exports.PatchablePlugin = (schema) ->
|
||||
schema.is_patchable = true
|
||||
schema.index({'target.original':1, 'status':'1', 'created':-1})
|
||||
|
||||
RESERVED_NAMES = ['search', 'names']
|
||||
RESERVED_NAMES = ['names']
|
||||
|
||||
module.exports.NamedPlugin = (schema) ->
|
||||
schema.uses_coco_names = true
|
||||
|
|
27
server/routes/admin.coffee
Normal file
27
server/routes/admin.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
log = require 'winston'
|
||||
errors = require '../commons/errors'
|
||||
handlers = require('../commons/mapping').handlers
|
||||
|
||||
mongoose = require('mongoose')
|
||||
|
||||
module.exports.setup = (app) ->
|
||||
app.post '/admin/*', (req, res) ->
|
||||
# TODO apparently I can leave this out as long as I use res.send
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
|
||||
module = req.path[7..]
|
||||
parts = module.split('/')
|
||||
module = parts[0]
|
||||
|
||||
return errors.unauthorized(res, 'Must be admin to access this area.') unless req.user?.isAdmin()
|
||||
|
||||
try
|
||||
moduleName = module.replace '.', '_'
|
||||
name = handlers[moduleName]
|
||||
handler = require('../' + name)
|
||||
|
||||
return handler[parts[1]](req, res, parts[2..]...) if parts[1] of handler
|
||||
|
||||
catch error
|
||||
log.error("Error trying db method '#{req.route.method}' route '#{parts}' from #{name}: #{error}")
|
||||
errors.notFound(res, "Route #{req.path} not found.")
|
|
@ -61,8 +61,11 @@ module.exports.setup = (app) ->
|
|||
|
||||
req.logIn(user, (err) ->
|
||||
return next(err) if (err)
|
||||
res.send(UserHandler.formatEntity(req, req.user))
|
||||
return res.end()
|
||||
activity = req.user.trackActivity 'login', 1
|
||||
user.update {activity: activity}, (err) ->
|
||||
return next(err) if (err)
|
||||
res.send(UserHandler.formatEntity(req, req.user))
|
||||
return res.end()
|
||||
)
|
||||
)(req, res, next)
|
||||
)
|
||||
|
@ -134,12 +137,12 @@ module.exports.setup = (app) ->
|
|||
|
||||
emails = _.clone(user.get('emails')) or {}
|
||||
msg = ''
|
||||
|
||||
|
||||
if req.query.recruitNotes
|
||||
emails.recruitNotes ?= {}
|
||||
emails.recruitNotes.enabled = false
|
||||
msg = "Unsubscribed #{req.query.email} from recruiting emails."
|
||||
|
||||
|
||||
else
|
||||
msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!"
|
||||
emailSettings.enabled = false for emailSettings in _.values(emails)
|
||||
|
@ -147,7 +150,7 @@ module.exports.setup = (app) ->
|
|||
emails.generalNews.enabled = false
|
||||
emails.anyNotes ?= {}
|
||||
emails.anyNotes.enabled = false
|
||||
|
||||
|
||||
user.update {$set: {emails: emails}}, {}, =>
|
||||
return errors.serverError res, 'Database failure.' if err
|
||||
res.send msg + "<p><a href='/account/settings'>Account settings</a></p>"
|
||||
|
@ -172,7 +175,7 @@ module.exports.makeNewUser = makeNewUser = (req) ->
|
|||
user = new User({anonymous:true})
|
||||
user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth
|
||||
user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages
|
||||
|
||||
|
||||
createMailOptions = (receiver, password) ->
|
||||
# TODO: use email templates here
|
||||
options =
|
||||
|
@ -181,4 +184,3 @@ createMailOptions = (receiver, password) ->
|
|||
replyTo: config.mail.username
|
||||
subject: "[CodeCombat] Password Reset"
|
||||
text: "You can log into your account with: #{password}"
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ module.exports.setup = (app) ->
|
|||
return handler.getLatestVersion(req, res, parts[1], parts[3]) if parts[2] is 'version'
|
||||
return handler.versions(req, res, parts[1]) if parts[2] is 'versions'
|
||||
return handler.files(req, res, parts[1]) if parts[2] is 'files'
|
||||
return handler.search(req, res) if req.route.method is 'get' and parts[1] is 'search'
|
||||
return handler.getNamesByIDs(req, res) if req.route.method in ['get', 'post'] and parts[1] is 'names'
|
||||
return handler.getByRelationship(req, res, parts[1..]...) if parts.length > 2
|
||||
return handler.getById(req, res, parts[1]) if req.route.method is 'get' and parts[1]?
|
||||
|
|
|
@ -8,7 +8,7 @@ module.exports.setup = (app) ->
|
|||
app.all '/file*', (req, res) ->
|
||||
return fileGet(req, res) if req.route.method is 'get'
|
||||
return filePost(req, res) if req.route.method is 'post'
|
||||
return errors.badMethod(res)
|
||||
return errors.badMethod(res, ['GET', 'POST'])
|
||||
|
||||
|
||||
fileGet = (req, res) ->
|
||||
|
|
|
@ -4,7 +4,7 @@ errors = require '../commons/errors'
|
|||
module.exports.setup = (app) ->
|
||||
app.all '/folder*', (req, res) ->
|
||||
return folderGet(req, res) if req.route.method is 'get'
|
||||
return errors.badMethod(res)
|
||||
return errors.badMethod(res, ['GET'])
|
||||
|
||||
folderGet = (req, res) ->
|
||||
folder = req.path[7..]
|
||||
|
@ -15,4 +15,4 @@ folderGet = (req, res) ->
|
|||
mongoose.connection.db.collection 'media.files', (errors, collection) ->
|
||||
collection.find({'metadata.path': folder}).toArray (err, results) ->
|
||||
res.send(results)
|
||||
res.end()
|
||||
res.end()
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports.setup = (app) ->
|
|||
|
||||
app.all '/languages', (req, res) ->
|
||||
# Now that these are in the client, not sure when we would use this, but hey
|
||||
return errors.badMethod(res) if req.route.method isnt 'get'
|
||||
return errors.badMethod(res, ['GET']) if req.route.method isnt 'get'
|
||||
res.send(languages)
|
||||
return res.end()
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ module.exports.setup = (app) ->
|
|||
|
||||
app.all '/queue/*', (req, res) ->
|
||||
setResponseHeaderToJSONContentType res
|
||||
|
||||
|
||||
queueName = getQueueNameFromPath req.path
|
||||
try
|
||||
handler = loadQueueHandler queueName
|
||||
|
@ -64,7 +64,7 @@ isHTTPMethodPost = (req) -> return req.route.method is 'post'
|
|||
isHTTPMethodPut = (req) -> return req.route.method is 'put'
|
||||
|
||||
|
||||
sendMethodNotSupportedError = (req, res) -> errors.badMethod(res,"Queues do not support the HTTP method used." )
|
||||
sendMethodNotSupportedError = (req, res) -> errors.badMethod(res, ['GET', 'POST', 'PUT'], "Queues do not support the HTTP method used." )
|
||||
|
||||
sendQueueError = (req,res, error) -> errors.serverError(res, "Route #{req.path} had a problem: #{error}")
|
||||
|
||||
|
|
|
@ -15,3 +15,4 @@ module.exports.templates =
|
|||
patch_created: 'tem_xhxuNosLALsizTNojBjNcL'
|
||||
change_made_notify_watcher: 'tem_7KVkfmv9SZETb25dtHbUtG'
|
||||
one_time_recruiting_email: 'tem_mdFMgtcczHKYu94Jmq68j8'
|
||||
greed_tournament_rank: 'tem_c4KYnk2TriEkkZx5NqqGLG'
|
||||
|
|
|
@ -29,6 +29,17 @@ UserSchema.methods.isAdmin = ->
|
|||
p = @get('permissions')
|
||||
return p and 'admin' in p
|
||||
|
||||
UserSchema.methods.trackActivity = (activityName, increment) ->
|
||||
now = new Date()
|
||||
increment ?= parseInt increment or 1
|
||||
increment = Math.max increment, 0
|
||||
activity = @get('activity') ? {}
|
||||
activity[activityName] ?= {first: now, count: 0}
|
||||
activity[activityName].count += increment
|
||||
activity[activityName].last = now
|
||||
@set 'activity', activity
|
||||
activity
|
||||
|
||||
emailNameMap =
|
||||
generalNews: 'announcement'
|
||||
adventurerNews: 'tester'
|
||||
|
|
|
@ -48,7 +48,7 @@ UserHandler = class UserHandler extends Handler
|
|||
delete obj[prop] for prop in serverProperties
|
||||
includePrivates = req.user and (req.user.isAdmin() or req.user._id.equals(document._id))
|
||||
delete obj[prop] for prop in privateProperties unless includePrivates
|
||||
includeCandidate = includePrivates or (obj.jobProfileApproved and req.user and ('employer' in (req.user.get('permissions') ? [])) and @employerCanViewCandidate req.user, obj)
|
||||
includeCandidate = includePrivates or (obj.jobProfile?.active and req.user and ('employer' in (req.user.get('permissions') ? [])) and @employerCanViewCandidate req.user, obj)
|
||||
delete obj[prop] for prop in candidateProperties unless includeCandidate
|
||||
return obj
|
||||
|
||||
|
@ -189,11 +189,14 @@ UserHandler = class UserHandler extends Handler
|
|||
return @avatar(req, res, args[0]) if args[1] is 'avatar'
|
||||
return @getNamesByIDs(req, res) if args[1] is 'names'
|
||||
return @nameToID(req, res, args[0]) if args[1] is 'nameToID'
|
||||
return @getLevelSessionsForEmployer(req, res, args[0]) if args[1] is 'level.sessions' and args[2] is 'employer'
|
||||
return @getLevelSessions(req, res, args[0]) if args[1] is 'level.sessions'
|
||||
return @getCandidates(req, res) if args[1] is 'candidates'
|
||||
return @getEmployers(req, res) if args[1] is 'employers'
|
||||
return @getSimulatorLeaderboard(req, res, args[0]) if args[1] is 'simulatorLeaderboard'
|
||||
return @getMySimulatorLeaderboardRank(req, res, args[0]) if args[1] is 'simulator_leaderboard_rank'
|
||||
return @getEarnedAchievements(req, res, args[0]) if args[1] is 'achievements'
|
||||
return @trackActivity(req, res, args[0], args[2], args[3]) if args[1] is 'track' and args[2]
|
||||
return @sendNotFoundError(res)
|
||||
super(arguments...)
|
||||
|
||||
|
@ -225,9 +228,18 @@ UserHandler = class UserHandler extends Handler
|
|||
res.redirect photoURL
|
||||
res.end()
|
||||
|
||||
getLevelSessionsForEmployer: (req, res, userID) ->
|
||||
return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
||||
query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']}
|
||||
projection = 'levelName levelID team playtime codeLanguage submitted' # code totalScore
|
||||
LevelSession.find(query).select(projection).exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
|
||||
getLevelSessions: (req, res, userID) ->
|
||||
return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin()
|
||||
query = {'creator': userID}
|
||||
query = creator: userID
|
||||
projection = null
|
||||
if req.query.project
|
||||
projection = {}
|
||||
|
@ -249,6 +261,25 @@ UserHandler = class UserHandler extends Handler
|
|||
doc.save()
|
||||
@sendSuccess(res, cleandocs)
|
||||
|
||||
trackActivity: (req, res, userID, activityName, increment=1) ->
|
||||
return @sendMethodNotAllowed res unless req.method is 'POST'
|
||||
isMe = userID is req.user._id + ''
|
||||
isAuthorized = isMe or req.user.isAdmin()
|
||||
isAuthorized ||= ('employer' in req.user.get('permissions')) and (activityName in ['viewed_by_employer', 'messaged_by_employer'])
|
||||
return @sendUnauthorizedError res unless isAuthorized
|
||||
updateUser = (user) =>
|
||||
activity = user.trackActivity activityName, increment
|
||||
user.update {activity: activity}, (err) =>
|
||||
return @sendDatabaseError res, err if err
|
||||
@sendSuccess res, result: 'success'
|
||||
if isMe
|
||||
updateUser(req.user)
|
||||
else
|
||||
@getDocumentForIdOrSlug userID, (err, user) =>
|
||||
return @sendDatabaseError res, err if err
|
||||
return @sendNotFoundError res unless user
|
||||
updateUser user
|
||||
|
||||
agreeToEmployerAgreement: (req, res) ->
|
||||
userIsAnonymous = req.user?.get('anonymous')
|
||||
if userIsAnonymous then return errors.unauthorized(res, "You need to be logged in to agree to the employer agreeement.")
|
||||
|
@ -278,13 +309,11 @@ UserHandler = class UserHandler extends Handler
|
|||
getCandidates: (req, res) ->
|
||||
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
||||
since = (new Date((new Date()) - 2 * 30.4 * 86400 * 1000)).toISOString()
|
||||
#query = {'jobProfile.active': true, 'jobProfile.updated': {$gt: since}}
|
||||
query = {'jobProfile.updated': {$gt: since}}
|
||||
query.jobProfileApproved = true unless req.user.isAdmin()
|
||||
#query.jobProfileApproved = true unless req.user.isAdmin() # We split into featured and other now.
|
||||
query['jobProfile.active'] = true unless req.user.isAdmin()
|
||||
selection = 'jobProfile'
|
||||
selection = 'jobProfile jobProfileApproved photoURL'
|
||||
selection += ' email' if authorized
|
||||
selection += ' jobProfileApproved' if req.user.isAdmin()
|
||||
User.find(query).select(selection).exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
candidates = (candidate for candidate in documents when @employerCanViewCandidate req.user, candidate.toObject())
|
||||
|
@ -292,7 +321,7 @@ UserHandler = class UserHandler extends Handler
|
|||
@sendSuccess(res, candidates)
|
||||
|
||||
formatCandidate: (authorized, document) ->
|
||||
fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile']
|
||||
fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile', 'jobProfileApproved']
|
||||
obj = _.pick document.toObject(), fields
|
||||
obj.photoURL ||= obj.jobProfile.photoURL if authorized
|
||||
subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated', 'active']
|
||||
|
@ -311,6 +340,14 @@ UserHandler = class UserHandler extends Handler
|
|||
return false if job.employer?.toLowerCase() is employer.get('employerAt')?.toLowerCase()
|
||||
true
|
||||
|
||||
getEmployers: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
||||
query = {employerAt: {$exists: true}}
|
||||
selection = 'name firstName lastName email activity signedEmployerAgreement photoURL employerAt'
|
||||
User.find(query).select(selection).lean().exec (err, documents) =>
|
||||
return @sendDatabaseError res, err if err
|
||||
@sendSuccess res, documents
|
||||
|
||||
buildGravatarURL: (user, size, fallback) ->
|
||||
emailHash = @buildEmailHash user
|
||||
fallback ?= "http://codecombat.com/file/db/thang.type/52a00d55cf1818f2be00000b/portrait.png"
|
||||
|
|
|
@ -93,7 +93,10 @@ sendMain = (req, res) ->
|
|||
log.error "Error modifying main.html: #{err}" if err
|
||||
# insert the user object directly into the html so the application can have it immediately. Sanitize </script>
|
||||
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)).replace(/\//g, '\\/'))
|
||||
res.send data
|
||||
res.header "Cache-Control", "no-cache, no-store, must-revalidate"
|
||||
res.header "Pragma", "no-cache"
|
||||
res.header "Expires", 0
|
||||
res.send 200, data
|
||||
|
||||
setupFacebookCrossDomainCommunicationRoute = (app) ->
|
||||
app.get '/channel.html', (req, res) ->
|
||||
|
|
80
test/app/lib/FacebookHandler.spec.coffee
Normal file
80
test/app/lib/FacebookHandler.spec.coffee
Normal file
|
@ -0,0 +1,80 @@
|
|||
FacebookHandler = require 'lib/FacebookHandler'
|
||||
|
||||
mockAuthEvent =
|
||||
response:
|
||||
authResponse:
|
||||
accessToken: "aksdhjflkqjrj245234b52k345q344le4j4k5l45j45s4dkljvdaskl"
|
||||
userID: "4301938"
|
||||
expiresIn: 5138
|
||||
signedRequest: "akjsdhfjkhea.3423nkfkdsejnfkd"
|
||||
status: "connected"
|
||||
|
||||
# Whatev, it's all public info anyway
|
||||
mockMe =
|
||||
id: "4301938"
|
||||
email: "scott@codecombat.com"
|
||||
first_name: "Scott"
|
||||
gender: "male"
|
||||
last_name: "Erickson"
|
||||
link: "https://www.facebook.com/scott.erickson.779"
|
||||
locale: "en_US"
|
||||
name: "Scott Erickson"
|
||||
timezone: -7
|
||||
updated_time: "2014-05-21T04:58:06+0000"
|
||||
username: "scott.erickson.779"
|
||||
verified: true
|
||||
work: [
|
||||
{
|
||||
employer:
|
||||
id: "167559910060759"
|
||||
name: "CodeCombat"
|
||||
|
||||
location:
|
||||
id: "114952118516947"
|
||||
name: "San Francisco, California"
|
||||
|
||||
start_date: "2013-02-28"
|
||||
}
|
||||
{
|
||||
end_date: "2013-01-31"
|
||||
employer:
|
||||
id: "39198748555"
|
||||
name: "Skritter"
|
||||
|
||||
location:
|
||||
id: "106109576086811"
|
||||
name: "Oberlin, Ohio"
|
||||
|
||||
start_date: "2008-06-01"
|
||||
}
|
||||
]
|
||||
|
||||
window.FB ?= {
|
||||
api: ->
|
||||
}
|
||||
|
||||
describe 'lib/FacebookHandler.coffee', ->
|
||||
it 'on facebook-logged-in, gets data from FB and sends a patch to the server', ->
|
||||
me.clear({silent:true})
|
||||
me.markToRevert()
|
||||
me.set({_id: '12345'})
|
||||
|
||||
spyOn FB, 'api'
|
||||
|
||||
new FacebookHandler()
|
||||
Backbone.Mediator.publish 'facebook-logged-in', mockAuthEvent
|
||||
|
||||
expect(FB.api).toHaveBeenCalled()
|
||||
apiArgs = FB.api.calls.argsFor(0)
|
||||
expect(apiArgs[0]).toBe('/me')
|
||||
apiArgs[1](mockMe) # sending the 'response'
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
expect(request).toBeDefined()
|
||||
params = JSON.parse request.params
|
||||
expect(params.firstName).toBe(mockMe.first_name)
|
||||
expect(params.lastName).toBe(mockMe.last_name)
|
||||
expect(params.gender).toBe(mockMe.gender)
|
||||
expect(params.email).toBe(mockMe.email)
|
||||
expect(params.facebookID).toBe(mockMe.id)
|
||||
expect(request.method).toBe('PATCH')
|
||||
expect(_.string.startsWith(request.url, '/db/user/12345')).toBeTruthy()
|
|
@ -2,7 +2,7 @@ describe 'Local Mongo queries', ->
|
|||
LocalMongo = require 'lib/LocalMongo'
|
||||
|
||||
beforeEach ->
|
||||
this.fixture1 =
|
||||
@fixture1 =
|
||||
'id': 'somestring'
|
||||
'value': 9000
|
||||
'levels': [3, 8, 21]
|
||||
|
@ -10,68 +10,72 @@ describe 'Local Mongo queries', ->
|
|||
'type': 'unicorn'
|
||||
'likes': ['poptarts', 'popsicles', 'popcorn']
|
||||
|
||||
this.fixture2 = this: is: so: 'deep'
|
||||
@fixture2 = this: is: so: 'deep'
|
||||
|
||||
it 'regular match of a property', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'gender': 'unicorn')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'unicorn')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'zebra')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'unicorn', 'id':'somestring')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'gender': 'unicorn')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'unicorn')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'zebra')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'unicorn', 'id':'somestring')).toBeTruthy()
|
||||
|
||||
it 'array match of a property', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'poptarts')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'walks on the beach')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes':'poptarts')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes':'walks on the beach')).toBeFalsy()
|
||||
|
||||
it 'nested match', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture2, 'this.is.so':'deep')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture2, 'this.is.so':'deep')).toBeTruthy()
|
||||
|
||||
it '$gt selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': 8000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': [8000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'levels': '$gt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$gt': 8000}, 'worth': {'$gt': 5})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': 8000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': [8000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$gt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$gt': 8000}, 'worth': {'$gt': 5})).toBeTruthy()
|
||||
|
||||
it '$gte selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': 9001)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': [9000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'levels': '$gte': [21, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': 9001)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': [9000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$gte': [21, 30])).toBeTruthy()
|
||||
|
||||
it '$lt selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lt': 9001)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lt': [9001, 9000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'levels': '$lt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$lt': 9001}, 'worth': {'$lt': 7})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': 9001)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': [9001, 9000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$lt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$lt': 9001}, 'worth': {'$lt': 7})).toBeTruthy()
|
||||
|
||||
it '$lte selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lte': 8000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$lte': 9000}, 'worth': {'$lte': [6, 5]})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lte': 8000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$lte': 9000}, 'worth': {'$lte': [6, 5]})).toBeTruthy()
|
||||
|
||||
it '$ne selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$ne': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'id': '$ne': 'otherstring')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'id': '$ne': ['otherstring', 'somestring'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$ne': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$ne': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'id': '$ne': 'otherstring')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'id': '$ne': ['otherstring', 'somestring'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$ne': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
|
||||
it '$in selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$in': ['unicorn', 'zebra'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$in': ['cats', 'dogs'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$in': ['popcorn', 'chicken'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$in': ['unicorn', 'zebra'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$in': ['cats', 'dogs'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$in': ['popcorn', 'chicken'])).toBeTruthy()
|
||||
|
||||
it '$nin selector', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$nin': ['unicorn', 'zebra'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$nin': ['cats', 'dogs'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$nin': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$nin': ['unicorn', 'zebra'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$nin': ['cats', 'dogs'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$nin': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
|
||||
it '$or operator', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $or: [{value:9000}, {type:'zebra'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $or: [{value:9001}, {worth:$lt:10}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $or: [{value:9000}, {type:'zebra'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $or: [{value:9001}, {worth:$lt:10}])).toBeTruthy()
|
||||
|
||||
it '$and operator', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:9000}, {type:'zebra'}])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:9000}, {type:'unicorn'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:$gte:9000}, {worth:$lt:10}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:9000}, {type:'zebra'}])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:9000}, {type:'unicorn'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:$gte:9000}, {worth:$lt:10}])).toBeTruthy()
|
||||
|
||||
it '$exists operator', ->
|
||||
expect(LocalMongo.matchesQuery(@fixture1, type: $exists: true)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, interesting: $exists: false)).toBeTruthy()
|
||||
|
||||
|
|
84
test/app/models/CocoModel.spec.coffee
Normal file
84
test/app/models/CocoModel.spec.coffee
Normal file
|
@ -0,0 +1,84 @@
|
|||
CocoModel = require 'models/CocoModel'
|
||||
|
||||
class BlandClass extends CocoModel
|
||||
@className: 'Bland'
|
||||
@schema: {
|
||||
type: 'object'
|
||||
additionalProperties: false
|
||||
properties:
|
||||
number: {type: 'number'}
|
||||
object: {type: 'object'}
|
||||
string: {type: 'string'}
|
||||
_id: {type: 'string'}
|
||||
}
|
||||
urlRoot: '/db/bland'
|
||||
|
||||
describe 'CocoModel', ->
|
||||
describe 'save', ->
|
||||
|
||||
it 'saves to db/<urlRoot>', ->
|
||||
b = new BlandClass({})
|
||||
res = b.save()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
expect(res).toBeDefined()
|
||||
expect(request.url).toBe(b.urlRoot)
|
||||
expect(request.method).toBe('POST')
|
||||
|
||||
it 'does not save if the data is invalid based on the schema', ->
|
||||
b = new BlandClass({number: 'NaN'})
|
||||
res = b.save()
|
||||
expect(res).toBe(false)
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
expect(request).toBeUndefined()
|
||||
|
||||
it 'uses PUT when _id is included', ->
|
||||
b = new BlandClass({_id: 'test'})
|
||||
b.save()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
expect(request.method).toBe('PUT')
|
||||
|
||||
describe 'patch', ->
|
||||
it 'PATCHes only properties that have changed', ->
|
||||
b = new BlandClass({_id: 'test', number:1})
|
||||
b.loaded = true
|
||||
b.set('string', 'string')
|
||||
b.patch()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
params = JSON.parse request.params
|
||||
expect(params.string).toBeDefined()
|
||||
expect(params.number).toBeUndefined()
|
||||
|
||||
it 'collates all changes made over several sets', ->
|
||||
b = new BlandClass({_id: 'test', number:1})
|
||||
b.loaded = true
|
||||
b.set('string', 'string')
|
||||
b.set('object', {4:5})
|
||||
b.patch()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
params = JSON.parse request.params
|
||||
expect(params.string).toBeDefined()
|
||||
expect(params.object).toBeDefined()
|
||||
expect(params.number).toBeUndefined()
|
||||
|
||||
it 'does not include data from previous patches', ->
|
||||
b = new BlandClass({_id: 'test', number:1})
|
||||
b.loaded = true
|
||||
b.set('object', {1:2})
|
||||
b.patch()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
attrs = JSON.stringify(b.attributes) # server responds with all
|
||||
request.response({status: 200, responseText: attrs})
|
||||
|
||||
b.set('number', 3)
|
||||
b.patch()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
params = JSON.parse request.params
|
||||
expect(params.object).toBeUndefined()
|
||||
|
||||
it 'does nothing when there\'s nothing to patch', ->
|
||||
b = new BlandClass({_id: 'test', number:1})
|
||||
b.loaded = true
|
||||
b.set('number', 1)
|
||||
b.patch()
|
||||
request = jasmine.Ajax.requests.mostRecent()
|
||||
expect(request).toBeUndefined()
|
|
@ -9,6 +9,10 @@ jasmine.getEnv().addReporter(new jasmine.SpecReporter({
|
|||
displaySuccessfulSpec: true,
|
||||
displayFailedSpec: true
|
||||
}))
|
||||
|
||||
rep = new jasmine.JsApiReporter()
|
||||
jasmine.getEnv().addReporter(rep)
|
||||
|
||||
GLOBAL._ = require('lodash')
|
||||
_.str = require('underscore.string')
|
||||
_.mixin(_.str.exports())
|
||||
|
@ -26,6 +30,8 @@ models_path = [
|
|||
'../../server/levels/thangs/LevelThangType'
|
||||
'../../server/users/User'
|
||||
'../../server/patches/Patch'
|
||||
'../../server/achievements/Achievement'
|
||||
'../../server/achievements/EarnedAchievement'
|
||||
]
|
||||
|
||||
for m in models_path
|
||||
|
@ -149,3 +155,13 @@ _drop = (done) ->
|
|||
chunks = mongoose.connection.db.collection('media.chunks')
|
||||
chunks.remove {}, ->
|
||||
done()
|
||||
|
||||
tickInterval = null
|
||||
tick = ->
|
||||
# When you want jasmine-node to exit after running the tests,
|
||||
# you have to close the connection first.
|
||||
if rep.finished
|
||||
mongoose.disconnect()
|
||||
clearTimeout tickInterval
|
||||
|
||||
tickInterval = setInterval tick, 1000
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue