diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 2e33a5836..af98d1afa 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -1037,6 +1037,7 @@ ambassador_title: "Ambassador" ambassador_title_description: "(Support)" ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world." + teacher_title: "Teacher" editor: main_title: "CodeCombat Editors" @@ -1193,6 +1194,7 @@ ambassador_join_note_strong: "Note" ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." + teacher_subscribe_desc: "Get emails on updates and announcements for teachers." changes_auto_save: "Changes are saved automatically when you toggle checkboxes." diligent_scribes: "Our Diligent Scribes:" powerful_archmages: "Our Powerful Archmages:" diff --git a/app/schemas/models/user.coffee b/app/schemas/models/user.coffee index 80a822413..c1b1766d5 100644 --- a/app/schemas/models/user.coffee +++ b/app/schemas/models/user.coffee @@ -79,6 +79,7 @@ _.extend UserSchema.properties, archmageNews: {$ref: '#/definitions/emailSubscription'} artisanNews: {$ref: '#/definitions/emailSubscription'} diplomatNews: {$ref: '#/definitions/emailSubscription'} + teacherNews: {$ref: '#/definitions/emailSubscription'} scribeNews: {$ref: '#/definitions/emailSubscription'} # notifications diff --git a/app/styles/account/profile-view.sass b/app/styles/account/profile-view.sass deleted file mode 100644 index a122188f3..000000000 --- a/app/styles/account/profile-view.sass +++ /dev/null @@ -1,344 +0,0 @@ -@import "app/styles/bootstrap/variables" - -#profile-view - $sideBackground: rgb(220, 220, 220) - #login-message - h1, h2, h3, h4 - font-family: Arial, Helvetica, sans-serif - color: #333333 - width: 100% - text-align: center - margin-top: 200px - .profile-control-bar - background-color: $sideBackground - width: 100% - text-align: center - - .profile-completion-progress - width: 100% - height: 33px - margin-bottom: 0 - border-radius: 0 - background-color: darken($sideBackground, 15%) - - .progress-bar - line-height: 33px - font-size: 16px - - .progress-text - position: absolute - width: 100% - text-align: center - line-height: 33px - font-size: 16px - color: white - text-shadow: 0px 1px 0px black - - button, a.btn - margin: 10px 2px 10px 2px - - &:disabled - border-radius: 0 - opacity: 1 - - i - margin-right: 5px - - .sample-profile - position: absolute - right: 5px - - .main-content-area - padding: 0 - background-color: white - - .flat-button - width: 100% - margin-bottom: 10px - background: rgb(78, 78, 78) - border: 0 - border-radius: 0 - padding: 10px - - .public-profile-container - padding: 20px - - img.profile-photo - width: 256px - border-radius: 6px - - .job-profile-container - width: 100% - height: 100% - min-height: 600px - padding: 0 - display: table - - h1, h2, h3, h4, h5, h6 - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif - color: #555 - - ul.links, ul.projects, ul.sessions - margin: 0 - padding: 0 - - li - list-style: none - - .job-profile-row - height: 100% - display: table-row - $side-width: 250px - $side-padding: 5px - $middle-width: 524px - $middle-padding: 20px - - .full-height-column - height: 100% - padding: $side-padding - display: table-cell - vertical-align: top - - h3:first-child - margin: 5px 0 5px 0 - - .left-column - width: $side-width - 2 * $side-padding - padding: $side-padding - background-color: $sideBackground - - .sub-column - width: $side-width - 2 * $side-padding - overflow-wrap: break-word - - #profile-photo-container - position: relative - margin-bottom: 10px - - img.profile-photo - width: $side-width - 2 * $side-padding - border-radius: 6px - - .profile-caption - background-color: rgba(0, 0, 0, 0.5) - color: white - border-bottom-right-radius: 6px - border-bottom-left-radius: 6px - position: absolute - width: 100% - bottom: 0px - text-align: center - - ul.links - text-align: center - li.has-icon - display: inline-block - img - margin: 0 0 10px 0 - li.has-icon:not(:nth-child(5)) - img - margin: 0 5px 10px 5px - - #contact-candidate - margin-top: 20px - background-color: rgb(177, 55, 25) - padding: 15px - font-size: 20px - - .middle-column - width: $middle-width - 2 * $middle-padding - padding-left: $middle-padding - padding-right: $middle-padding - background-color: white - - .sub-column - width: $middle-width - 2 * $middle-padding - overflow-wrap: break-word - - &.double-column - width: $middle-width + $side-width + 2 * $side-padding - 2 * $middle-padding - $middle-padding-double: 30px - padding-left: $middle-padding-double - padding-right: $middle-padding-double - - .sub-column - width: $middle-width + $side-width + 2 * $side-padding - 2 * $middle-padding - 2 * $middle-padding-double - overflow-wrap: break-word - - code - background-color: $sideBackground - color: #555 - margin: 2px 0 - display: inline-block - text-transform: lowercase - - .long-description - margin-top: 10px - img - max-width: 524px - 60px - max-height: 200px - - .experience-header - margin-top: 25px - - .header-icon - margin-right: 10px - width: 32px - height: 32px - - .experience-entry - margin-bottom: 15px - - .duration - margin-left: 10px - margin-bottom: 10px - - #job-profile-notes - width: 100% - height: 100px - - #remark-treema - background-color: white - border: 0 - padding-top: 0 - - .right-column - width: $side-width - background-color: $sideBackground - - .sub-column - width: $side-width - 2 * $side-padding - overflow-wrap: break-word - - > h3:first-child - background-color: white - padding: 5px 5px - margin: 5px 2px 5px 2px - - ul.projects - li - margin-bottom: 10px - padding: 5px 3px - border: 2px solid $sideBackground - transition: .5s ease-in-out - position: relative - background-color: white - - &:hover - border-color: rgb(100, 130, 255) - - a - position: relative - z-index: 2 - - > a - position: absolute - width: 100% - height: 100% - top: 0 - left: 0 - z-index: 1 - - .project-image - width: 230px - height: 115px - background-size: cover - background-repeat: no-repeat - background-position: center - - -webkit-filter: grayscale(100%) - -webkit-transition: .5s ease-in-out - -moz-filter: grayscale(100%) - -moz-transition: .5s ease-in-out - -o-filter: grayscale(100%) - -o-transition: .5s ease-in-out - filter: grayscale(100%) - transition: .5s ease-in-out - - ul.projects li:hover .project-image, .project-image:hover - -webkit-filter: grayscale(0%) - -moz-filter: grayscale(0%) - -o-filter: grayscale(0%) - filter: grayscale(0%) - - .main-content-area - - .job-profile-container - .editable-section - position: relative - transition: box-shadow 0.5s easeInOutQuad - min-height: 30px - - &.just-saved - box-shadow: 0px 0px 20px 0px #080 - z-index: 1 - - .editable-form - display: none - background-color: white - padding: 5px 5px 5px 5px - - .skill-array-item - display: inline-block - - input - width: 120px - margin: 5px - - .project-image - width: 210px - height: 105px - cursor: pointer - - .editable-icon - display: none - - .job-profile-container.editable-profile - - .full-height-column.deemphasized - background-color: $sideBackground - - .saving - opacity: 0.75 - - .editable-thinner - padding-right: 30px - - .editable-icon - display: block - position: absolute - right: 5px - top: 5px - font-size: 20px - color: $blue - opacity: 0.5 - - .edit-label - color: $blue - font-weight: 300 - - .edit-example-button - background-color: transparentize($blue, 0.25) - - .edit-example-text - color: $blue - - code.edit-example-tag - color: $blue - - .emphasized - outline: 1px solid $green - - .editable-section.deemphasized:not(.just-saved), .our-notes-section.deemphasized - opacity: 0.5 - - .editable-section:hover - cursor: pointer - outline: 1px solid $blue - - .editable-icon - opacity: 1.0 - cursor: pointer - - .editable-form - cursor: default diff --git a/app/styles/admin/candidates.sass b/app/styles/admin/candidates.sass deleted file mode 100644 index 1a34e9f12..000000000 --- a/app/styles/admin/candidates.sass +++ /dev/null @@ -1,74 +0,0 @@ -#admin-candidates-view - - 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 - - .tablesorter-header - cursor: pointer - &:hover - color: black - - &:first-child - // Make sure that "Developer #56" doesn't wrap onto second row - min-width: 110px - - .tablesorter-headerAsc - background-color: #cfc - - .tablesorter-headerDesc - background-color: #ccf - - tr - cursor: pointer - - tr.expired - opacity: 0.5 - - code - background-color: rgb(220, 220, 220) - color: #555 - margin: 2px 0 - display: inline-block - text-transform: lowercase - - td:nth-child(3) select - min-width: 100px - td:nth-child(6) select - min-width: 50px - td:nth-child(7) select - min-width: 100px - -#employers-view, #profile-view.viewed-by-employer - #outer-content-wrapper, #intermediate-content-wrapper, #inner-content-wrapper - background: #949494 - - .main-content-area - background-color: #EAEAEA \ No newline at end of file diff --git a/app/styles/kinds/search.sass b/app/styles/kinds/search.sass index 7644e613a..622011580 100644 --- a/app/styles/kinds/search.sass +++ b/app/styles/kinds/search.sass @@ -18,9 +18,20 @@ .name-row @extend .body-row max-width: 300px + .description-row + @extend .body-row + max-width: 520px .small-name-row @extend .body-row max-width: 200px + .watch-row + @extend .body-row + max-width: 80px + text-align: center + &.watching + opacity: 1.0 + &.not-watching + opacity: 0.5 tr.mine background-color: #f8ecaa diff --git a/app/styles/play/ladder_home.sass b/app/styles/play/ladder_home.sass index 38eb07af8..451494ac5 100644 --- a/app/styles/play/ladder_home.sass +++ b/app/styles/play/ladder_home.sass @@ -1,7 +1,7 @@ @import "app/styles/mixins" @import "app/styles/bootstrap/variables" -#ladder-home-view +#main-ladder-view .level width: 100% position: relative diff --git a/app/styles/recruitment_base.sass b/app/styles/recruitment_base.sass deleted file mode 100644 index 6501c7303..000000000 --- a/app/styles/recruitment_base.sass +++ /dev/null @@ -1,52 +0,0 @@ -@import "app/styles/mixins" -@import "app/styles/bootstrap/variables" - -#employers-wrapper - background-color: #B4B4B4 - height: 100% - #outer-content-wrapper, #intermediate-content-wrapper, #inner-content-wrapper - background: #B4B4B4 - - .navbar, #top-nav, .content.clearfix - background-color: #B4B4B4 - - .footer - border-top: none - background-color: #B4B4B4 - padding-bottom: 50px - - -#employer-content-area - margin: auto - -.employer-modal-background-wrapper - background-color: white - border: 2px #333333 solid - border-radius: 4px - h1, h2, h3, h4, h5 - color: black - font-family: Arial, Helvetica, sans-serif - .input-large - font-size: 28px - height: 60px - border: 2px rgb(231,231,231) solid - box-shadow: none - width: 70% - margin-left: 15% - #create-account-button, #contract-agreement-button, #login-button - background: #fce232 /* Old browsers */ - background: -moz-linear-gradient(top, #fce232 0%, #ea8e2b 100%) - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fce232), color-stop(100%,#ea8e2b)) - background: -webkit-linear-gradient(top, #fce232 0%,#ea8e2b 100%) - background: -o-linear-gradient(top, #fce232 0%,#ea8e2b 100%) - background: -ms-linear-gradient(top, #fce232 0%,#ea8e2b 100%) - background: linear-gradient(to bottom, #fce232 0%,#ea8e2b 100%) - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fce232', endColorstr='#ea8e2b',GradientType=0 ) - height: 60px - font-size: 24px - color: black - .login-link - text-decoration: underline - #login-button - margin-left: 40% - width: 20% diff --git a/app/templates/account/account-settings-view.jade b/app/templates/account/account-settings-view.jade index cabc1d8c9..adb7f45bc 100644 --- a/app/templates/account/account-settings-view.jade +++ b/app/templates/account/account-settings-view.jade @@ -159,7 +159,7 @@ else | (Translator) input#email_diplomatNews(name="email_diplomatNews", type="checkbox", checked=subs.diplomatNews) span(data-i18n="contribute.diplomat_subscribe_desc").help-block Get emails about i18n developments and, eventually, levels to translate. - + .form-group.checkbox label.control-label(for="email_ambassadorNews") span(data-i18n="classes.ambassador_title") @@ -169,7 +169,13 @@ else | (Support) input#email_ambassadorNews(name="email_ambassadorNews", type="checkbox", checked=subs.ambassadorNews) span(data-i18n="contribute.ambassador_subscribe_desc").help-block Get emails on support updates and multiplayer developments. - + + .form-group.checkbox + label.control-label(for="email_teacherNews") + span(data-i18n="classes.teacher_title") + input#email_teacherNews(name="email_teacherNews", type="checkbox", checked=subs.teacherNews) + span(data-i18n="contribute.teacher_subscribe_desc").help-block + button#toggle-all-btn.btn.btn-primary.form-control(data-i18n="account_settings.email_toggle") Toggle All .panel.panel-default diff --git a/app/templates/editor/level/table.jade b/app/templates/editor/level/table.jade index b936393e4..a6093232f 100755 --- a/app/templates/editor/level/table.jade +++ b/app/templates/editor/level/table.jade @@ -1 +1,35 @@ extends /templates/common/table + +block tableResultsHeader + tr + th(colspan=4) + span(data-i18n="general.results") + | Results + span + |: #{documents.length} + +block tableHeader + tr + th(data-i18n="general.name") Name + th(data-i18n="general.description") Description + th(data-i18n="general.version") Version + th(data-i18n="common.watch") Watch + +block tableBody + for document in documents + - var data = document.attributes; + tr(class=document.get('creator') == me.id ? 'mine' : '') + td(title=data.name).name-row + a(href="/editor/#{page}/#{data.slug || data._id}") + | #{data.name} + td(title=data.description).description-row + | #{data.description} + td #{data.version.major}.#{data.version.minor} + if document.watching() + td.watch-row.watching + span(aria-hidden="true").glyphicon.glyphicon-eye-open + span(data-i18n="common.watch").sr-only Watch + else + td.watch-row.not-watching + span(aria-hidden="true").glyphicon.glyphicon-eye-close + span(data-i18n="common.unwatch").sr-only Unwatch \ No newline at end of file diff --git a/app/templates/recruitment_base.jade b/app/templates/recruitment_base.jade deleted file mode 100644 index b04d4848d..000000000 --- a/app/templates/recruitment_base.jade +++ /dev/null @@ -1,21 +0,0 @@ -body - #fb-root - #employers-wrapper - block header - .nav - .content.clearfix - .navbar-header - a.navbar-brand(href='/') - img(src="/images/pages/base/recruitment_logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat") - block outer_content - #outer-content-wrapper - - #intermediate-content-wrapper - - #inner-content-wrapper - .main-content-area#employer-content-area - block content - p If this is showing, you dun goofed - - block footer - .footer \ No newline at end of file diff --git a/app/views/admin/PendingPatchesView.coffee b/app/views/admin/PendingPatchesView.coffee index f6234db00..1f578f3cb 100644 --- a/app/views/admin/PendingPatchesView.coffee +++ b/app/views/admin/PendingPatchesView.coffee @@ -7,7 +7,7 @@ class PendingPatchesCollection extends CocoCollection url: '/db/patch?view=pending' model: Patch -module.exports = class PatchesView extends RootView +module.exports = class PendingPatchesView extends RootView id: 'pending-patches-view' template: template diff --git a/app/views/courses/ClassroomSettingsModal.coffee b/app/views/courses/ClassroomSettingsModal.coffee index dbad58b90..824973ff8 100644 --- a/app/views/courses/ClassroomSettingsModal.coffee +++ b/app/views/courses/ClassroomSettingsModal.coffee @@ -2,7 +2,7 @@ Classroom = require 'models/Classroom' ModalView = require 'views/core/ModalView' template = require 'templates/courses/classroom-settings-modal' -module.exports = class AddLevelSystemModal extends ModalView +module.exports = class ClassroomSettingsModal extends ModalView id: 'classroom-settings-modal' template: template diff --git a/app/views/courses/StudentLogInModal.coffee b/app/views/courses/StudentLogInModal.coffee index ffebbab8e..91c2d86fc 100644 --- a/app/views/courses/StudentLogInModal.coffee +++ b/app/views/courses/StudentLogInModal.coffee @@ -4,7 +4,7 @@ auth = require 'core/auth' forms = require 'core/forms' User = require 'models/User' -module.exports = class StudentSignInModal extends ModalView +module.exports = class StudentLogInModal extends ModalView id: 'student-log-in-modal' template: template diff --git a/app/views/editor/level/LevelSearchView.coffee b/app/views/editor/level/LevelSearchView.coffee index e7b2ecf87..c384a848c 100644 --- a/app/views/editor/level/LevelSearchView.coffee +++ b/app/views/editor/level/LevelSearchView.coffee @@ -6,6 +6,7 @@ module.exports = class LevelSearchView extends SearchView model: require 'models/Level' modelURL: '/db/level' tableTemplate: require 'templates/editor/level/table' + projection: ['slug', 'name', 'description', 'version', 'watchers', 'creator'] page: 'level' getRenderData: -> diff --git a/app/views/i18n/I18NEditThangTypeView.coffee b/app/views/i18n/I18NEditThangTypeView.coffee index 52c058e9b..00f67aeee 100644 --- a/app/views/i18n/I18NEditThangTypeView.coffee +++ b/app/views/i18n/I18NEditThangTypeView.coffee @@ -1,8 +1,8 @@ I18NEditModelView = require './I18NEditModelView' ThangType = require 'models/ThangType' -module.exports = class ThangTypeI18NView extends I18NEditModelView - id: 'thang-type-i18n-view' +module.exports = class I18NEditThangTypeView extends I18NEditModelView + id: 'i18n-thang-type-view' modelClass: ThangType buildTranslationList: -> diff --git a/app/views/ladder/MainLadderView.coffee b/app/views/ladder/MainLadderView.coffee index 66cc9c373..ebd2eca0c 100644 --- a/app/views/ladder/MainLadderView.coffee +++ b/app/views/ladder/MainLadderView.coffee @@ -11,8 +11,8 @@ class LevelSessionsCollection extends CocoCollection super() @url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID" -module.exports = class LadderHomeView extends RootView - id: 'ladder-home-view' +module.exports = class MainLadderView extends RootView + id: 'main-ladder-view' template: template constructor: (options) -> diff --git a/app/views/modal/SignupModal.coffee b/app/views/modal/SignupModal.coffee deleted file mode 100644 index d8311dce5..000000000 --- a/app/views/modal/SignupModal.coffee +++ /dev/null @@ -1,4 +0,0 @@ -AuthModal = require 'views/core/AuthModal' - -module.exports = class SignupModalView extends AuthModal - mode: 'signup' diff --git a/app/views/play/modal/ShareProgressModal.coffee b/app/views/play/modal/ShareProgressModal.coffee index 4b3c34943..4ea07b376 100644 --- a/app/views/play/modal/ShareProgressModal.coffee +++ b/app/views/play/modal/ShareProgressModal.coffee @@ -2,7 +2,7 @@ ModalView = require 'views/core/ModalView' template = require 'templates/play/modal/share-progress-modal' storage = require 'core/storage' -module.exports = class SubscribeModal extends ModalView +module.exports = class ShareProgressModal extends ModalView id: 'share-progress-modal' template: template plain: true diff --git a/server/classrooms/Classroom.coffee b/server/classrooms/Classroom.coffee index c33fceb41..daaad2741 100644 --- a/server/classrooms/Classroom.coffee +++ b/server/classrooms/Classroom.coffee @@ -4,6 +4,7 @@ config = require '../../server_config' plugins = require '../plugins/plugins' User = require '../users/User' jsonSchema = require '../../app/schemas/models/classroom.schema' +utils = require '../lib/utils' ClassroomSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} @@ -18,12 +19,10 @@ ClassroomSchema.statics.editableProperties = [ 'aceConfig' ] -# 250 words; will want to use 4 code words once we get past 10M classrooms. -words = 'angry apple arm army art baby back bad bag ball bath bean bear bed bell best big bird bite blue boat book box boy bread burn bus cake car cat chair city class clock cloud coat coin cold cook cool corn crash cup dark day deep desk dish dog door down draw dream drink drop dry duck dust east eat egg enemy eye face false farm fast fear fight find fire flag floor fly food foot fork fox free fruit full fun funny game gate gift glass goat gold good green hair half hand happy heart heavy help hide hill home horse house ice idea iron jelly job jump key king lamp large last late lazy leaf left leg life light lion lock long luck map mean milk mix moon more most mouth music name neck net new next nice night north nose old only open page paint pan paper park party path pig pin pink place plane plant plate play point pool power pull push queen rain ready red rest rice ride right ring road rock room run sad safe salt same sand sell shake shape share sharp sheep shelf ship shirt shoe shop short show sick side silly sing sink sit size sky sleep slow small snow sock soft soup south space speed spell spoon star start step stone stop sweet swim sword table team thick thin thing think today tooth top town tree true turn type under want warm watch water west wide win word yes zoo'.split(' ') - ClassroomSchema.statics.generateNewCode = (done) -> tryCode = -> - codeCamel = _.map(_.sample(words, 3), (s) -> s[0].toUpperCase() + s.slice(1)).join('') + # Use 4 code words once we get past 10M classrooms + codeCamel = utils.getCodeCamel(3) code = codeCamel.toLowerCase() Classroom.findOne code: code, (err, classroom) -> return done() if err @@ -31,8 +30,6 @@ ClassroomSchema.statics.generateNewCode = (done) -> tryCode() tryCode() -#ClassroomSchema.plugin plugins.NamedPlugin - ClassroomSchema.pre('save', (next) -> return next() if @get('code') Classroom.generateNewCode (code, codeCamel) => diff --git a/server/commons/mail.coffee b/server/commons/mail.coffee index 432441060..02642e44d 100644 --- a/server/commons/mail.coffee +++ b/server/commons/mail.coffee @@ -3,6 +3,6 @@ config = require '../../server_config' module.exports.MAILCHIMP_LIST_ID = 'e9851239eb' module.exports.MAILCHIMP_GROUP_ID = '4529' -# these two need to be parallel -module.exports.MAILCHIMP_GROUPS = ['Announcements', 'Adventurers', 'Artisans', 'Archmages', 'Scribes', 'Diplomats', 'Ambassadors'] -module.exports.NEWS_GROUPS = ['generalNews', 'adventurerNews', 'artisanNews', 'archmageNews', 'scribeNews', 'diplomatNews', 'ambassadorNews'] +# These two need to be parallel +module.exports.MAILCHIMP_GROUPS = ['Announcements', 'Adventurers', 'Artisans', 'Archmages', 'Scribes', 'Diplomats', 'Ambassadors', 'Teachers'] +module.exports.NEWS_GROUPS = ['generalNews', 'adventurerNews', 'artisanNews', 'archmageNews', 'scribeNews', 'diplomatNews', 'ambassadorNews', 'teacherNews'] diff --git a/server/lib/utils.coffee b/server/lib/utils.coffee index 2bae86c09..b0b20c1e7 100644 --- a/server/lib/utils.coffee +++ b/server/lib/utils.coffee @@ -6,6 +6,11 @@ config = require '../../server_config' module.exports = isID: (id) -> _.isString(id) and id.length is 24 and id.match(/[a-f0-9]/gi)?.length is 24 + getCodeCamel: (numWords=3) -> + # 250 words + words = 'angry apple arm army art baby back bad bag ball bath bean bear bed bell best big bird bite blue boat book box boy bread burn bus cake car cat chair city class clock cloud coat coin cold cook cool corn crash cup dark day deep desk dish dog door down draw dream drink drop dry duck dust east eat egg enemy eye face false farm fast fear fight find fire flag floor fly food foot fork fox free fruit full fun funny game gate gift glass goat gold good green hair half hand happy heart heavy help hide hill home horse house ice idea iron jelly job jump key king lamp large last late lazy leaf left leg life light lion lock long luck map mean milk mix moon more most mouth music name neck net new next nice night north nose old only open page paint pan paper park party path pig pin pink place plane plant plate play point pool power pull push queen rain ready red rest rice ride right ring road rock room run sad safe salt same sand sell shake shape share sharp sheep shelf ship shirt shoe shop short show sick side silly sing sink sit size sky sleep slow small snow sock soft soup south space speed spell spoon star start step stone stop sweet swim sword table team thick thin thing think today tooth top town tree true turn type under want warm watch water west wide win word yes zoo'.split(' ') + _.map(_.sample(words, numWords), (s) -> s[0].toUpperCase() + s.slice(1)).join('') + objectIdFromTimestamp: (timestamp) -> # mongoDB ObjectId contains creation date in first 4 bytes # So, it can be used instead of a redundant created field diff --git a/server/queues/scoring/scoringUtils.coffee b/server/queues/scoring/scoringUtils.coffee index f6c655c7e..5695e60a7 100644 --- a/server/queues/scoring/scoringUtils.coffee +++ b/server/queues/scoring/scoringUtils.coffee @@ -41,7 +41,7 @@ module.exports.formatSessionInformation = (session) -> shouldUpdateLastOpponentSubmitDateForLeague: session.shouldUpdateLastOpponentSubmitDateForLeague module.exports.calculateSessionScores = (callback) -> - sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID' + sessionIDs = _.map @clientResponseObject.sessions, 'sessionID' async.map sessionIDs, retrieveOldSessionData.bind(@), (err, oldScores) => if err? then return callback err, {error: 'There was an error retrieving the old scores'} try @@ -151,7 +151,7 @@ module.exports.addMatchToSessionsAndUpdate = (newScoreObject, callback) -> #log.info "Match object computed, result: #{JSON.stringify(matchObject, null, 2)}" #log.info 'Writing match object to database...' #use bind with async to do the writes - sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID' + sessionIDs = _.map @clientResponseObject.sessions, 'sessionID' async.each sessionIDs, updateMatchesInSession.bind(@, matchObject), (err) -> callback err diff --git a/server/routes/auth.coffee b/server/routes/auth.coffee index e425418de..a8ad2ba12 100644 --- a/server/routes/auth.coffee +++ b/server/routes/auth.coffee @@ -8,6 +8,7 @@ errors = require '../commons/errors' languages = require '../routes/languages' sendwithus = require '../sendwithus' log = require 'winston' +utils = require '../lib/utils' module.exports.setup = (app) -> authentication.serializeUser((user, done) -> done(null, user._id)) @@ -101,7 +102,10 @@ module.exports.setup = (app) -> if not user return errors.notFound(res, [{message: 'not found', property: 'email'}]) - user.set('passwordReset', Math.random().toString(36).slice(2, 7).toUpperCase()) + user.set('passwordReset', utils.getCodeCamel()) + emailContent = "
Reset your password at http://codecombat.com/account/settings
" + emailContent += "Your old password cannot be retrieved.
" user.save (err) => return errors.serverError(res) if err unless config.unittest @@ -111,8 +115,8 @@ module.exports.setup = (app) -> address: req.body.email email_data: subject: 'CodeCombat Recovery Password' - title: 'Recovery Password' - content: "Your CodeCombat recovery password for email #{req.body.email} is: #{user.get('passwordReset')}
Log in at http://codecombat.com/account/settings and change it.
Hope this helps!
" + title: '' + content: emailContent sendwithus.api.send context, (err, result) -> if err console.error "Error sending password reset email: #{err.message or err}" diff --git a/server/trial_requests/TrialRequest.coffee b/server/trial_requests/TrialRequest.coffee index a5de8f871..1dc0ecf9d 100644 --- a/server/trial_requests/TrialRequest.coffee +++ b/server/trial_requests/TrialRequest.coffee @@ -5,6 +5,7 @@ hipchat = require '../hipchat' sendwithus = require '../sendwithus' Prepaid = require '../prepaids/Prepaid' jsonSchema = require '../../app/schemas/models/trial_request.schema' +User = require '../users/User' TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} @@ -32,6 +33,19 @@ TrialRequestSchema.post 'save', (doc) -> sendwithus.api.send emailParams, (err, result) => log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err + # Subscribe to teacher news group + User.findById doc.get('applicant'), (err, user) => + if err + log.error "Trial request user find error: #{err}" + return + emails = _.cloneDeep(user.get('emails') ? {}) + emails.teacherNews ?= {} + emails.teacherNews.enabled = true + user.update {$set: {emails: emails}}, {}, (err) => + if err + log.error "Trial request user update error: #{err}" + return + TrialRequestSchema.statics.privateProperties = [] TrialRequestSchema.statics.editableProperties = [ 'created' diff --git a/server/users/User.coffee b/server/users/User.coffee index fb3bd4f62..62953b0cd 100644 --- a/server/users/User.coffee +++ b/server/users/User.coffee @@ -76,6 +76,7 @@ emailNameMap = diplomatNews: 'translator' ambassadorNews: 'support' anyNotes: 'notification' + teacherNews: 'teacher' UserSchema.methods.setEmailSubscription = (newName, enabled) -> oldSubs = _.clone @get('emailSubscriptions') diff --git a/spec/server/functional/trial_request.spec.coffee b/spec/server/functional/trial_request.spec.coffee index cbcae5c89..c34b7ec3e 100644 --- a/spec/server/functional/trial_request.spec.coffee +++ b/spec/server/functional/trial_request.spec.coffee @@ -134,7 +134,11 @@ describe 'Trial Requests', -> expect(prepaid.get('type')).toEqual('course') expect(prepaid.get('creator')).toEqual(user.get('_id')) expect(prepaid.get('maxRedeemers')).toEqual(2) - done() + User.findById user._id, (err, user) => + expect(err).toBeNull() + return done(err) if err + expect(user.get('emails')?.teacherNews?.enabled).toEqual(true) + done() it 'Deny trial request', (done) -> loginNewUser (user) ->