diff --git a/app/core/utils.coffee b/app/core/utils.coffee index 18b20fa8b..572b3a3da 100644 --- a/app/core/utils.coffee +++ b/app/core/utils.coffee @@ -97,10 +97,15 @@ createQuadraticFunc = (params) -> 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 +# f(x) = ax^b + c +createPowFunc = (params) -> + (x) -> (params.a or 1) * Math.pow(x, params.b or 1) + (params.c or 0) + module.exports.functionCreators = linear: positify(createLinearFunc) quadratic: positify(createQuadraticFunc) logarithmic: positify(createLogFunc) + pow: positify(createPowFunc) # Call done with true to satisfy the 'until' goal and stop repeating func module.exports.keepDoingUntil = (func, wait=100, totalWait=5000) -> diff --git a/app/lib/world/names.coffee b/app/lib/world/names.coffee index b70fd2dac..8acef2f2a 100644 --- a/app/lib/world/names.coffee +++ b/app/lib/world/names.coffee @@ -649,9 +649,12 @@ module.exports.thangNames = thangNames = ] 'Ninja': [ 'Amara' + 'Itachi' 'Kosaraju' + 'Madara' 'Minato' 'Naruto' + 'Obito' 'Sakura' 'Sasuke' 'Shigeru' diff --git a/app/locale/he.coffee b/app/locale/he.coffee index b0c06deb9..4fbaa7eb3 100644 --- a/app/locale/he.coffee +++ b/app/locale/he.coffee @@ -19,8 +19,8 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", editor: "עורך" blog: "בלוג" forum: "פורום" -# account: "Account" -# profile: "Profile" + account: "חשבון" + profile: "פרופיל" # stats: "Stats" # code: "Code" admin: "אדמין" # Only shows up when you are an admin @@ -30,7 +30,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", about: "עלינו" contact: "צור קשר" twitter_follow: "עקוב אחרינו בטוויטר" -# teachers: "Teachers" + teachers: "מורים" modal: close: "סגור" @@ -50,27 +50,27 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", play: play_as: "שחק בתור " # Ladder page spectate: "צופה" # Ladder page -# players: "players" # Hover over a level on /play -# hours_played: "hours played" # Hover over a level on /play -# items: "Items" # Tooltip on item shop button from /play -# unlock: "Unlock" # For purchasing items and heroes -# confirm: "Confirm" -# owned: "Owned" # For items you own -# locked: "Locked" -# purchasable: "Purchasable" # For a hero you unlocked but haven't purchased -# available: "Available" + players: "שחקנים" # Hover over a level on /play + hours_played: "שעות משחק" # Hover over a level on /play + items: "כלים" # Tooltip on item shop button from /play + unlock: "קנה" # For purchasing items and heroes + confirm: "אשר" + owned: "נרכש" # For items you own + locked: "נעול" + purchasable: "ניתן לרכישה" # For a hero you unlocked but haven't purchased + available: "זמין" # skills_granted: "Skills Granted" # Property documentation details -# heroes: "Heroes" # Tooltip on hero shop button from /play -# achievements: "Achievements" # Tooltip on achievement list button from /play -# account: "Account" # Tooltip on account button from /play -# settings: "Settings" # Tooltip on settings button from /play -# next: "Next" # Go from choose hero to choose inventory before playing a level -# change_hero: "Change Hero" # Go back from choose inventory to choose hero + heroes: "דמויות" # Tooltip on hero shop button from /play + achievements: "הישגים" # Tooltip on achievement list button from /play + account: "חשבון" # Tooltip on account button from /play + settings: "הגדרות" # Tooltip on settings button from /play + next: "הבא" # Go from choose hero to choose inventory before playing a level + change_hero: "שנה דמות" # Go back from choose inventory to choose hero # choose_inventory: "Equip Items" -# buy_gems: "Buy Gems" + buy_gems: "רכש אבני חן" # subscription_required: "Subscription Required" # older_campaigns: "Older Campaigns" -# anonymous: "Anonymous Player" + anonymous: "משתמש אנונימי" level_difficulty: "רמת קושי: " campaign_beginner: "מסע המתחילים" # awaiting_levels_adventurer_prefix: "We release five levels per week." @@ -92,22 +92,22 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # campaign_classic_algorithms: "Classic Algorithms" # campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." -# share_progress_modal: -# blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat." -# email_invalid: "Email address invalid." + share_progress_modal: + blurb: ".אתה מתקדם מצויין! ספר למישהו כמה למדת" + email_invalid: ".כתובת המייל שהוזנה שגויה" # form_blurb: "Enter their email below and we’ll show them!" -# form_label: "Email Address" -# placeholder: "email address" + form_label: "כתובת מייל" + placeholder: "כתובת המייל" # title: "Excellent Work, Apprentice" -# tell_friend: "Tell your Friend" -# tell_parent: "Tell your Parent" + tell_friend: "ספר לחברים" + tell_parent: "ספר להורים" login: sign_up: "הירשם" - log_in: "היכנס" -# logging_in: "Logging In" + log_in: "תחברס" + logging_in: "מתחבר" log_out: "צא" -# forgot_password: "Forgot your password?" + forgot_password: "שכחתי סיסמא" # authenticate_gplus: "Authenticate G+" # load_profile: "Load G+ Profile" # load_email: "Load G+ Email" @@ -122,21 +122,21 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", sign_up: "הירשם" log_in: "כנס עם סיסמה" # social_signup: "Or, you can sign up through Facebook or G+:" -# required: "You need to log in before you can go that way." -# login_switch: "Already have an account?" + required: ".יש להתחבר על מנת לגשת לשלב זה" + login_switch: "? כבר יש לך משתמש" recover: recover_account_title: "שחזר סיסמה" send_password: "שלח סיסמה חדשה" -# recovery_sent: "Recovery email sent." + recovery_sent: "מייל לשחזור סיסמא נשלח" -# items: + items: # primary: "Primary" # secondary: "Secondary" -# armor: "Armor" + armor: "שריון" # accessories: "Accessories" # misc: "Misc" -# books: "Books" + books: "ספרי כישוף" common: # back: "Back" # When used as an action verb, like "Navigate backward" @@ -144,19 +144,19 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", loading: "...טוען" saving: "...שומר" sending: "...שולח" -# send: "Send" + send: "שלח" cancel: "ביטול" save: "שמור" -# publish: "Publish" -# create: "Create" + publish: "פרסם" + create: "צור" manual: "מדריך" fork: "קילשון" play: "שחק" # When used as an action verb, like "Play next level" -# retry: "Retry" -# actions: "Actions" -# info: "Info" -# help: "Help" -# watch: "Watch" + retry: "נסה שוב" + actions: "פעולות" + info: "מידע" + help: "עזרה" + watch: "צפה" # unwatch: "Unwatch" # submit_patch: "Submit Patch" # submit_changes: "Submit Changes" diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee index c5ddf5ab2..7f6048d6a 100644 --- a/app/locale/hi.coffee +++ b/app/locale/hi.coffee @@ -1,17 +1,17 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDescription: "Hindi", translation: -# home: -# slogan: "Learn to Code by Playing a Game" -# no_ie: "CodeCombat does not run in Internet Explorer 8 or older. Sorry!" # Warning that only shows up in IE8 and older -# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!" # Warning that shows up on mobile devices -# play: "Play" # The big play button that opens up the campaign view. + home: + slogan: "खेल खेल के द्वारा कोड करना सीखें" + no_ie: "CodeCombat Internet Explorer 8 या पुराने में नहीं चलता है| असुविधा के लिए खेद है!" # Warning that only shows up in IE8 and older + no_mobile: "CodeCombat मोबाइल उपकरणों के लिए तैयार नहीं है और काम नहीं कर सकता!" # Warning that shows up on mobile devices + play: "खेलें " # The big play button that opens up the campaign view. # old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" # Warning that shows up on really old Firefox/Chrome/Safari # old_browser_suffix: "You can try anyway, but it probably won't work." # ipad_browser: "Bad news: CodeCombat doesn't run on iPad in the browser. Good news: our native iPad app is awaiting Apple approval." -# campaign: "Campaign" -# for_beginners: "For Beginners" -# multiplayer: "Multiplayer" # Not currently shown on home page -# for_developers: "For Developers" # Not currently shown on home page. -# or_ipad: "Or download for iPad" + campaign: "अभियान" + for_beginners: "नौसिखिये के लिए" + multiplayer: "मल्टीप्लेयर" # Not currently shown on home page + for_developers: "डेवलपर्स के लिए" # Not currently shown on home page. + or_ipad: "या iPad के लिए डाउनलोड करें" # nav: # play: "Levels" # The top nav bar entry where players choose which levels to play diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee index d3256f31f..c412d94ba 100644 --- a/app/locale/ko.coffee +++ b/app/locale/ko.coffee @@ -52,7 +52,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t spectate: "관중모드" # Ladder page # players: "players" # Hover over a level on /play # hours_played: "hours played" # Hover over a level on /play -# items: "Items" # Tooltip on item shop button from /play + items: "아이템" # Tooltip on item shop button from /play # unlock: "Unlock" # For purchasing items and heroes # confirm: "Confirm" # owned: "Owned" # For items you own @@ -92,12 +92,12 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # campaign_classic_algorithms: "Classic Algorithms" # campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." -# share_progress_modal: + share_progress_modal: # blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat." # email_invalid: "Email address invalid." # form_blurb: "Enter their email below and we’ll show them!" -# form_label: "Email Address" -# placeholder: "email address" + form_label: "이메일" + placeholder: "이메일" # title: "Excellent Work, Apprentice" # tell_friend: "Tell your Friend" # tell_parent: "Tell your Parent" @@ -130,13 +130,13 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t send_password: "복구 비밀번호 전송" # recovery_sent: "Recovery email sent." -# items: + items: # primary: "Primary" # secondary: "Secondary" -# armor: "Armor" + armor: "갑옷" # accessories: "Accessories" # misc: "Misc" -# books: "Books" + books: "책" common: # back: "Back" # When used as an action verb, like "Navigate backward" @@ -164,7 +164,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t general: and: "그리고" name: "이름" -# date: "Date" + date: "날짜" body: "구성" version: "버전" # pending: "Pending" @@ -179,9 +179,9 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t version_history_for: "버전 히스토리 : " # select_changes: "Select two changes below to see the difference." # undo_prefix: "Undo" -# undo_shortcut: "(Ctrl+Z)" + undo_shortcut: "(Ctrl+Z)" # redo_prefix: "Redo" -# redo_shortcut: "(Ctrl+Shift+Z)" + redo_shortcut: "(Ctrl+Shift+Z)" # play_preview: "Play preview of current level" result: "결과" results: "결과들" @@ -205,25 +205,25 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t hard: "상급" player: "플레이어" # player_level: "Level" # Like player level 5, not like level: Dungeons of Kithgard -# warrior: "Warrior" -# ranger: "Ranger" -# wizard: "Wizard" + warrior: "전사" + ranger: "레인저" + wizard: "마법사" -# units: -# second: "second" -# seconds: "seconds" -# minute: "minute" -# minutes: "minutes" -# hour: "hour" -# hours: "hours" -# day: "day" -# days: "days" -# week: "week" -# weeks: "weeks" -# month: "month" -# months: "months" -# year: "year" -# years: "years" + units: + second: "초" + seconds: "초" + minute: "분" + minutes: "분" + hour: "시간" + hours: "시간" + day: "일" + days: "일" + week: "주" + weeks: "주" + month: "개월" + months: "개월" + year: "년" + years: "년" play_level: done: "완료" @@ -355,13 +355,13 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # multiplayer_caption: "Play with friends!" # auth_caption: "Save your progress." -# leaderboard: + leaderboard: # leaderboard: "Leaderboard" # view_other_solutions: "View Other Solutions" # scores: "Scores" # top_players: "Top Players by" -# day: "Today" -# week: "This Week" + day: "오늘" + week: "이번 주" # all: "All-Time" # time: "Time" # damage_taken: "Damage Taken" @@ -433,7 +433,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t choose_hero: # choose_hero: "Choose Your Hero" -# programming_language: "Programming Language" + programming_language: "프로그래밍 언어" # programming_language_description: "Which programming language do you want to use?" # default: "Default" # experimental: "Experimental" @@ -444,7 +444,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t lua_blurb: "게임 스크립팅 언어" io_blurb: "간단하지만 아직 잘 알려지지 않은 언어." # status: "Status" -# weapons: "Weapons" + weapons: "무기" # weapons_warrior: "Swords - Short Range, No Magic" # weapons_ranger: "Crossbows, Guns - Long Range, No Magic" # weapons_wizard: "Wands, Staffs - Long Range, Magic" @@ -485,7 +485,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t options: # general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level # volume_label: "Volume" -# music_label: "Music" + music_label: "음악" # music_description: "Turn background music on/off." # autorun_label: "Autorun" # autorun_description: "Control automatic code execution." @@ -520,17 +520,17 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # press_paragraph_1_prefix: "Want to write about us? Feel free to download and use all of the resources included in our" # press_paragraph_1_link: "press packet" # press_paragraph_1_suffix: ". All logos and images may be used without contacting us directly." -# team: "Team" -# george_title: "CEO" + team: "팀" + george_title: "최고경영자" # george_blurb: "Businesser" -# scott_title: "Programmer" + scott_title: "프로그래머" # scott_blurb: "Reasonable One" -# nick_title: "Programmer" + nick_title: "프로그래머" # nick_blurb: "Motivation Guru" -# michael_title: "Programmer" + michael_title: "프로그래머" # michael_blurb: "Sys Admin" -# matt_title: "Programmer" -# matt_blurb: "Bicyclist" + matt_title: "프로그래머" + matt_blurb: "자전거 타는 사람" # teachers: # title: "CodeCombat for Teachers" @@ -588,7 +588,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t forum_page: "포럼" forum_suffix: " 대신에." # faq_prefix: "There's also a" -# faq: "FAQ" + faq: "자주 묻는 질문" # subscribe_prefix: "If you need help figuring out a level, please" # subscribe: "buy a CodeCombat subscription" # subscribe_suffix: "and we'll be happy to help you with your code." @@ -706,9 +706,9 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t revert: "되돌리기" revert_models: "모델 되돌리기" pick_a_terrain: "지형을 선택하세요." -# dungeon: "Dungeon" + dungeon: "지하 감옥" # indoor: "Indoor" -# desert: "Desert" + desert: "사막" grassy: "풀로 덮인" small: "작게" # large: "Large" @@ -1007,10 +1007,10 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # user_remark: "User Remark" # user_remarks: "User Remarks" # versions: "Versions" -# items: "Items" + items: "아이템" # heroes: "Heroes" # achievement: "Achievement" -# clas: "CLAs" + clas: "CLAs" # play_counts: "Play Counts" # feedback: "Feedback" # payment_info: "Payment Info" diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index 9bcbbd46c..7e9eb9ef8 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -112,7 +112,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: load_profile: "Carregar Perfil do G+" load_email: "Carregar E-mail do G+" finishing: "A terminar" - sign_in_with_facebook: "Iniciar sessão com o Facebook" + sign_in_with_facebook: "Iniciar sessão com o F" sign_in_with_gplus: "Iniciar sessão com o G+" signup_switch: "Queres criar uma conta?" @@ -606,7 +606,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: me_tab: "Eu" picture_tab: "Fotografia" upload_picture: "Anexar uma fotografia" -# god_mode: "God Mode" + god_mode: "Modo Deus" password_tab: "Palavra-passe" emails_tab: "E-mails" admin: "Administrador" @@ -860,7 +860,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: ratio: "Rácio" leaderboard: "Tabela de Classificação" battle_as: "Lutar como " - summary_your: "As tuas " + summary_your: "As Tuas " summary_matches: "Partidas - " summary_wins: " Vitórias, " summary_losses: " Derrotas" diff --git a/app/schemas/models/achievement.coffee b/app/schemas/models/achievement.coffee index 98d4767ad..fdf783754 100644 --- a/app/schemas/models/achievement.coffee +++ b/app/schemas/models/achievement.coffee @@ -66,7 +66,7 @@ _.extend AchievementSchema.properties, type: 'object' description: 'Function that gives total experience for X amount achieved' properties: - kind: {enum: ['linear', 'logarithmic', 'quadratic'] } + kind: {enum: ['linear', 'logarithmic', 'quadratic', 'pow'] } parameters: type: 'object' default: { a: 1, b: 0, c: 0 } diff --git a/app/styles/play/campaign-view.sass b/app/styles/play/campaign-view.sass index 737ab74f1..9fbf37a2a 100644 --- a/app/styles/play/campaign-view.sass +++ b/app/styles/play/campaign-view.sass @@ -424,7 +424,7 @@ $gameControlMargin: 30px #volume-button position: absolute - left: 1% + right: 1% top: 1% padding: 3px 8px @include opacity(0.75) @@ -450,9 +450,9 @@ $gameControlMargin: 30px #back-button position: absolute - left: 70px - left: -webkit-calc(1% + 55px) - left: calc(1% + 55px) + right: 70px + right: -webkit-calc(1% + 55px) + right: calc(1% + 55px) top: 1% padding: 3px 8px @include opacity(0.75) @@ -565,7 +565,12 @@ $gameControlMargin: 30px margin-top: 30px min-width: 100px - + #small-nav-logo + position: absolute + top: 1% + left: 1% + height: 60px + z-index: 1 body.ipad #campaign-view // iPad only supports up to Kithgard Gates for now. diff --git a/app/templates/play/campaign-view.jade b/app/templates/play/campaign-view.jade index 2ed824e18..5245fe112 100644 --- a/app/templates/play/campaign-view.jade +++ b/app/templates/play/campaign-view.jade @@ -1,3 +1,6 @@ +a(href="/") + img#small-nav-logo(src="/images/pages/base/logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat") + if campaign .map .gradient.horizontal-gradient.top-gradient diff --git a/app/views/play/menu/InventoryModal.coffee b/app/views/play/menu/InventoryModal.coffee index 61ca63162..228158afe 100644 --- a/app/views/play/menu/InventoryModal.coffee +++ b/app/views/play/menu/InventoryModal.coffee @@ -250,6 +250,7 @@ module.exports = class InventoryModal extends ModalView onUnequippedItemClick: (e) -> return if @justDoubleClicked + return if @justClickedEquipItemButton itemEl = $(e.target).closest('.item') #@playSound 'menu-button-click' @selectUnequippedItem(itemEl) @@ -270,6 +271,8 @@ module.exports = class InventoryModal extends ModalView itemEl = $(e.target).closest('.item') @selectUnequippedItem(itemEl) @equipSelectedItem() + @justClickedEquipItemButton = true + _.defer => @justClickedEquipItemButton = false #- Select/equip higher-level, all encompassing methods the callbacks all use diff --git a/scripts/recalculateStatistics.coffee b/scripts/recalculateStatistics.coffee index 7c54478af..4892c4f58 100644 --- a/scripts/recalculateStatistics.coffee +++ b/scripts/recalculateStatistics.coffee @@ -27,19 +27,19 @@ whenAllFinished = -> async.parallel [ # Misc - (c) -> report UserHandler.recalculateStats, 'gamesCompleted', c - + #(c) -> report UserHandler.recalculateStats, 'gamesCompleted', c + # Edits (c) -> report UserHandler.recalculateStats, 'articleEdits', c (c) -> report UserHandler.recalculateStats, 'levelEdits', c (c) -> report UserHandler.recalculateStats, 'levelComponentEdits', c (c) -> report UserHandler.recalculateStats, 'levelSystemEdits', c (c) -> report UserHandler.recalculateStats, 'thangTypeEdits', c - + # Patches (c) -> report UserHandler.recalculateStats, 'patchesContributed', c (c) -> report UserHandler.recalculateStats, 'patchesSubmitted', c - + # Patches in memory (c) -> report UserHandler.recalculateStats, 'totalTranslationPatches', c (c) -> report UserHandler.recalculateStats, 'totalMiscPatches', c diff --git a/server/levels/sessions/LevelSession.coffee b/server/levels/sessions/LevelSession.coffee index 49153fde7..b330eeb51 100644 --- a/server/levels/sessions/LevelSession.coffee +++ b/server/levels/sessions/LevelSession.coffee @@ -30,31 +30,31 @@ LevelSessionSchema.plugin(AchievablePlugin) previous = {} LevelSessionSchema.post 'init', (doc) -> - previous[doc.get 'id'] = - 'state.complete': doc.get 'state.complete' - 'playtime': doc.get 'playtime' + unless doc.previousStateInfo + doc.previousStateInfo = + 'state.complete': doc.get 'state.complete' + playtime: doc.get 'playtime' LevelSessionSchema.pre 'save', (next) -> User = require '../../users/User' # Avoid mutual inclusion cycles @set('changed', new Date()) id = @get('id') - initd = id of previous + initd = @previousStateInfo? levelID = @get('levelID') userID = @get('creator') activeUserEvent = null # Newly completed level - if not (initd and previous[id]['state']?['complete']) and @get('state.complete') + if not (initd and @previousStateInfo['state.complete']) and @get('state.complete') User.update {_id: userID}, {$inc: 'stats.gamesCompleted': 1}, {}, (err, count) -> log.error err if err? activeUserEvent = "level-completed/#{levelID}" # Spent at least 30s playing this level - if not initd and @get('playtime') >= 30 or initd and (@get('playtime') - previous[id]['playtime'] >= 30) + if not initd and @get('playtime') >= 30 or initd and (@get('playtime') - @previousStateInfo['playtime'] >= 30) activeUserEvent = "level-playtime/#{levelID}" - delete previous[id] if initd if activeUserEvent? User.saveActiveUser userID, activeUserEvent, next else diff --git a/server/routes/db.coffee b/server/routes/db.coffee index 8b5a9747c..d34dc6869 100644 --- a/server/routes/db.coffee +++ b/server/routes/db.coffee @@ -43,7 +43,9 @@ module.exports.setup = (app) -> handler[req.route.method](req, res, parts[1..]...) catch error errorMessage = "Error trying db method #{req?.route?.method} route #{parts} from #{name}: #{error}" - # TODO: add user info to this log + if req.user? + userInfo = req.user.getUserInfo() + errorMessage += "\n-- User Info Id: #{userInfo.id} #{if req.user.isAnonymous() then '' else 'Email:'} #{userInfo.email}" log.error(errorMessage) log.error(error) log.error(error.stack) diff --git a/server/users/User.coffee b/server/users/User.coffee index 81c11a18b..c9d8ced80 100644 --- a/server/users/User.coffee +++ b/server/users/User.coffee @@ -45,6 +45,12 @@ UserSchema.methods.isAdmin = -> UserSchema.methods.isAnonymous = -> @get 'anonymous' +UserSchema.methods.getUserInfo = -> + info = + id : @get('_id') + email : if @get('anonymous') then 'Unregistered User' else @get('email') + return info + UserSchema.methods.trackActivity = (activityName, increment) -> now = new Date() increment ?= parseInt increment or 1 diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index f90e0d4d5..ecd228697 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -518,18 +518,23 @@ UserHandler = class UserHandler extends Handler countEdits = (model, done) -> statKey = User.statsMapping.edits[model.modelName] return done(new Error 'Could not resolve statKey for model') unless statKey? - userStream = User.find().stream() + userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false usersTotal = 0 usersFinished = 0 + numberRunning = 0 doneWithUser = (err) -> log.error err if err? ++usersFinished + --numberRunning + userStream.resume() done?() if streamFinished and usersFinished is usersTotal userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> - usersTotal += 1 + ++usersTotal + ++numberRunning + userStream.pause() if numberRunning > 20 userObjectID = user.get('_id') userStringID = userObjectID.toHexString() @@ -540,6 +545,7 @@ UserHandler = class UserHandler extends Handler else update = $unset: {} update.$unset[statKey] = '' + console.log "... updating #{userStringID} patches #{statKey} to #{count}, #{usersTotal} players found so far." if count User.findByIdAndUpdate user.get('_id'), update, (err) -> log.error err if err? doneWithUser() @@ -565,20 +571,26 @@ UserHandler = class UserHandler extends Handler update = {} update[method] = {} update[method][statName] = count or '' + console.log "... updating #{user.get('_id')} patches #{JSON.stringify(query)} #{statName} to #{count}, #{usersTotal} players found so far." if count User.findByIdAndUpdate user.get('_id'), update, doneUpdatingUser - userStream = User.find().stream() + userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false usersTotal = 0 usersFinished = 0 + numberRunning = 0 doneWithUser = (err) -> log.error err if err? ++usersFinished + --numberRunning + userStream.resume() done?() if streamFinished and usersFinished is usersTotal userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> - usersTotal += 1 + ++usersTotal + ++numberRunning + userStream.pause() if numberRunning > 20 userObjectID = user.get '_id' userStringID = userObjectID.toHexString() # Extend query with a patch ownership test @@ -596,18 +608,23 @@ UserHandler = class UserHandler extends Handler countPatchesByUsers = (query, statName, done) -> Patch = require '../patches/Patch' - userStream = User.find().stream() + userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false usersTotal = 0 usersFinished = 0 + numberRunning = 0 doneWithUser = (err) -> log.error err if err? ++usersFinished + --numberRunning + userStream.resume() done?() if streamFinished and usersFinished is usersTotal userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> - usersTotal += 1 + ++usersTotal + ++numberRunning + userStream.pause() if numberRunning > 20 userObjectID = user.get '_id' userStringID = userObjectID.toHexString() # Extend query with a patch ownership test @@ -618,28 +635,37 @@ UserHandler = class UserHandler extends Handler update = {} update[method] = {} update[method][statName] = count or '' + console.log "... updating #{userStringID} patches #{query} to #{count}, #{usersTotal} players found so far." if count User.findByIdAndUpdate user.get('_id'), update, doneWithUser statRecalculators: gamesCompleted: (done) -> LevelSession = require '../levels/sessions/LevelSession' - userStream = User.find().stream() + userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false usersTotal = 0 usersFinished = 0 + numberRunning = 0 doneWithUser = (err) -> log.error err if err? ++usersFinished - done?() if streamFinished and usersFinished is usersTotal + --numberRunning + userStream.resume() + if streamFinished and usersFinished is usersTotal + console.log "----------- Finished recalculating statistics for gamesCompleted for #{usersFinished} players. -----------" + done?() userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> - usersTotal += 1 + ++usersTotal + ++numberRunning + userStream.pause() if numberRunning > 20 userID = user.get('_id').toHexString() LevelSession.count {creator: userID, 'state.complete': true}, (err, count) -> update = if count then {$set: 'stats.gamesCompleted': count} else {$unset: 'stats.gamesCompleted': ''} + console.log "... updating #{userID} gamesCompleted to #{count}, #{usersTotal} players found so far." if Math.random() < 0.001 User.findByIdAndUpdate user.get('_id'), update, doneWithUser articleEdits: (done) ->