diff --git a/scripts/batchAddAchievements.js b/scripts/batchAddAchievements.js index 6aafec085..4ba503007 100644 --- a/scripts/batchAddAchievements.js +++ b/scripts/batchAddAchievements.js @@ -12,7 +12,7 @@ var mongoose = require('mongoose'); database.connect(); -var Achievement = require('../server/achievements/Achievement'); +var Achievement = require('../server/models/Achievement'); var tierNames = { "Wood": 1, diff --git a/scripts/buildSchoolGraph.coffee b/scripts/buildSchoolGraph.coffee index a14ca7636..ea039d2c7 100644 --- a/scripts/buildSchoolGraph.coffee +++ b/scripts/buildSchoolGraph.coffee @@ -18,7 +18,7 @@ do (setupLodash = this) -> database.connect() UserHandler = require '../server/users/user_handler' -User = require '../server/users/User' +User = require '../server/models/User' startDate = new Date 2015, 11, 1 diff --git a/scripts/mail.coffee b/scripts/mail.coffee index dbc81a790..952d4b2a1 100644 --- a/scripts/mail.coffee +++ b/scripts/mail.coffee @@ -7,9 +7,9 @@ async = require 'async' serverSetup = require '../server_setup' sendwithus = require '../server/sendwithus' -User = require '../server/users/User' -Level = require '../server/levels/Level' -LevelSession = require '../server/levels/sessions/LevelSession' +User = require '../server/models/User' +Level = require '../server/models/Level' +LevelSession = require '../server/models/LevelSession' tournamentResults = require '../app/views/play/ladder/tournament_results' alreadyEmailed = [] diff --git a/scripts/recalculatePayments.coffee b/scripts/recalculatePayments.coffee index 5bc28e2de..becf3e74e 100644 --- a/scripts/recalculatePayments.coffee +++ b/scripts/recalculatePayments.coffee @@ -12,8 +12,8 @@ do (setupLodash = this) -> database.connect() -User = require '../server/users/User' -Payment = require '../server/payments/Payment' +User = require '../server/models/User' +Payment = require '../server/models/Payment' PaymentHandler = require '../server/payments/payment_handler' t0 = new Date().getTime() diff --git a/scripts/recreateEarnedAchievements.coffee b/scripts/recreateEarnedAchievements.coffee index fba5d1eaf..97b415950 100644 --- a/scripts/recreateEarnedAchievements.coffee +++ b/scripts/recreateEarnedAchievements.coffee @@ -13,9 +13,9 @@ do (setupLodash = this) -> database.connect() LocalMongo = require '../app/lib/LocalMongo' -User = require '../server/users/User' -EarnedAchievement = require '../server/achievements/EarnedAchievement' -Achievement = require '../server/achievements/Achievement' +User = require '../server/models/User' +EarnedAchievement = require '../server/models/EarnedAchievement' +Achievement = require '../server/models/Achievement' Achievement.loadAchievements (achievementCategories) -> # Really, it's just the 'users' category, since we don't keep all the LevelSession achievements in memory, rather letting the clients make those. userAchievements = achievementCategories.users diff --git a/scripts/resetUsersProgress.coffee b/scripts/resetUsersProgress.coffee index 6e88dcdb5..7c6e07ea9 100644 --- a/scripts/resetUsersProgress.coffee +++ b/scripts/resetUsersProgress.coffee @@ -15,7 +15,7 @@ do (setupLodash = this) -> database.connect() UserHandler = require '../server/users/user_handler' -User = require '../server/users/User' +User = require '../server/models/User' userIDs = [ # Fill in userID strings here diff --git a/scripts/setupAchievements.coffee b/scripts/setupAchievements.coffee index 54e7a6f5f..02e9b4fda 100644 --- a/scripts/setupAchievements.coffee +++ b/scripts/setupAchievements.coffee @@ -199,8 +199,8 @@ repeatableAchievements = b: 1 c: 0 -Achievement = require '../server/achievements/Achievement' -EarnedAchievement = require '../server/achievements/EarnedAchievement' +Achievement = require '../server/models/Achievement' +EarnedAchievement = require '../server/models/EarnedAchievement' Achievement.find {}, (err, achievements) -> achievementIDs = (achievement.get('_id') + '' for achievement in achievements) diff --git a/scripts/transpile.coffee b/scripts/transpile.coffee index 1d17fcba2..02ce7f39b 100644 --- a/scripts/transpile.coffee +++ b/scripts/transpile.coffee @@ -6,8 +6,8 @@ GLOBAL.Aether = Aether = require 'aether' async = require 'async' serverSetup = require '../server_setup' -Level = require '../server/levels/Level' -LevelSession = require '../server/levels/sessions/LevelSession' +Level = require '../server/models/Level' +LevelSession = require '../server/models/LevelSession' {createAetherOptions} = require '../app/lib/aether_utils' i = 0 diff --git a/server/achievements/achievement_handler.coffee b/server/achievements/achievement_handler.coffee index 6377f73dc..f12539d9a 100644 --- a/server/achievements/achievement_handler.coffee +++ b/server/achievements/achievement_handler.coffee @@ -1,4 +1,4 @@ -Achievement = require './Achievement' +Achievement = require './../models/Achievement' Handler = require '../commons/Handler' class AchievementHandler extends Handler diff --git a/server/achievements/earned_achievement_handler.coffee b/server/achievements/earned_achievement_handler.coffee index f00e4ba78..53c3d8979 100644 --- a/server/achievements/earned_achievement_handler.coffee +++ b/server/achievements/earned_achievement_handler.coffee @@ -1,14 +1,14 @@ log = require 'winston' mongoose = require 'mongoose' async = require 'async' -Achievement = require './Achievement' -EarnedAchievement = require './EarnedAchievement' -User = require '../users/User' +Achievement = require './../models/Achievement' +EarnedAchievement = require './../models/EarnedAchievement' +User = require '../models/User' Handler = require '../commons/Handler' LocalMongo = require '../../app/lib/LocalMongo' util = require '../../app/core/utils' -LevelSession = require '../levels/sessions/LevelSession' -UserPollsRecord = require '../polls/UserPollsRecord' +LevelSession = require '../models/LevelSession' +UserPollsRecord = require '../models/UserPollsRecord' class EarnedAchievementHandler extends Handler modelClass: EarnedAchievement diff --git a/server/analytics/analytics_log_event_handler.coffee b/server/analytics/analytics_log_event_handler.coffee index f31a17234..b2bac8b64 100644 --- a/server/analytics/analytics_log_event_handler.coffee +++ b/server/analytics/analytics_log_event_handler.coffee @@ -1,9 +1,9 @@ log = require 'winston' mongoose = require 'mongoose' utils = require '../lib/utils' -AnalyticsLogEvent = require './AnalyticsLogEvent' -Campaign = require '../campaigns/Campaign' -Level = require '../levels/Level' +AnalyticsLogEvent = require './../models/AnalyticsLogEvent' +Campaign = require '../models/Campaign' +Level = require '../models/Level' Handler = require '../commons/Handler' class AnalyticsLogEventHandler extends Handler diff --git a/server/analytics/analytics_perday_handler.coffee b/server/analytics/analytics_perday_handler.coffee index 4c6d6a3d4..00075ed0b 100644 --- a/server/analytics/analytics_perday_handler.coffee +++ b/server/analytics/analytics_perday_handler.coffee @@ -1,7 +1,7 @@ -AnalyticsPerDay = require './AnalyticsPerDay' -AnalyticsString = require './AnalyticsString' -Campaign = require '../campaigns/Campaign' -Level = require '../levels/Level' +AnalyticsPerDay = require './../models/AnalyticsPerDay' +AnalyticsString = require './../models/AnalyticsString' +Campaign = require '../models/Campaign' +Level = require '../models/Level' Handler = require '../commons/Handler' log = require 'winston' diff --git a/server/analytics/analytics_string_handler.coffee b/server/analytics/analytics_string_handler.coffee index cfd81a7bf..e6049b537 100644 --- a/server/analytics/analytics_string_handler.coffee +++ b/server/analytics/analytics_string_handler.coffee @@ -1,4 +1,4 @@ -AnalyticsString = require './AnalyticsString' +AnalyticsString = require './../models/AnalyticsString' Handler = require '../commons/Handler' class AnalyticsStringHandler extends Handler diff --git a/server/analytics/analytics_stripe_invoice_handler.coffee b/server/analytics/analytics_stripe_invoice_handler.coffee index fcf3a3c20..be381421e 100644 --- a/server/analytics/analytics_stripe_invoice_handler.coffee +++ b/server/analytics/analytics_stripe_invoice_handler.coffee @@ -1,5 +1,5 @@ Handler = require '../commons/Handler' -AnalyticsStripeInvoice = require './AnalyticsStripeInvoice' +AnalyticsStripeInvoice = require './../models/AnalyticsStripeInvoice' class AnalyticsStripeInvoiceHandler extends Handler modelClass: AnalyticsStripeInvoice diff --git a/server/analytics/analytics_users_active_handler.coffee b/server/analytics/analytics_users_active_handler.coffee index c223a62c7..53f123239 100644 --- a/server/analytics/analytics_users_active_handler.coffee +++ b/server/analytics/analytics_users_active_handler.coffee @@ -1,4 +1,4 @@ -AnalyticsUsersActive = require './AnalyticsUsersActive' +AnalyticsUsersActive = require './../models/AnalyticsUsersActive' Handler = require '../commons/Handler' class AnalyticsUsersActiveHandler extends Handler diff --git a/server/articles/Article.coffee b/server/articles/Article.coffee deleted file mode 100644 index 3bb6db297..000000000 --- a/server/articles/Article.coffee +++ /dev/null @@ -1,43 +0,0 @@ -mongoose = require 'mongoose' -plugins = require '../plugins/plugins' -config = require '../../server_config' - -ArticleSchema = new mongoose.Schema(body: String, {strict: false,read:config.mongo.readpref}) - -ArticleSchema.index( - { - index: 1 - _fts: 'text' - _ftsx: 1 - }, - { - name: 'search index' - sparse: true - weights: {body: 1, name: 1} - default_language: 'english' - 'language_override': 'searchLanguage' - 'textIndexVersion': 2 - }) -ArticleSchema.index( - { - original: 1 - 'version.major': -1 - 'version.minor': -1 - }, - { - name: 'version index' - unique: true - }) -ArticleSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true}) - -ArticleSchema.plugin(plugins.NamedPlugin) -ArticleSchema.plugin(plugins.VersionedPlugin) -ArticleSchema.plugin(plugins.SearchablePlugin, {searchable: ['body', 'name']}) -ArticleSchema.plugin(plugins.TranslationCoveragePlugin) -ArticleSchema.plugin(plugins.PatchablePlugin) - -ArticleSchema.statics.postEditableProperties = [] -ArticleSchema.statics.editableProperties = ['body', 'name', 'i18n', 'i18nCoverage'] -ArticleSchema.statics.jsonSchema = require '../../app/schemas/models/article' - -module.exports = mongoose.model('article', ArticleSchema) diff --git a/server/articles/article_handler.coffee b/server/articles/article_handler.coffee index 14c40cc4b..3f4eb5518 100644 --- a/server/articles/article_handler.coffee +++ b/server/articles/article_handler.coffee @@ -1,6 +1,6 @@ # TODO: Remove once mapping.coffee is refactored out -Article = require './Article' +Article = require './../models/Article' Handler = require '../commons/Handler' ArticleHandler = class ArticleHandler extends Handler diff --git a/server/campaigns/Campaign.coffee b/server/campaigns/Campaign.coffee deleted file mode 100644 index ea96d206f..000000000 --- a/server/campaigns/Campaign.coffee +++ /dev/null @@ -1,41 +0,0 @@ -mongoose = require 'mongoose' -plugins = require '../plugins/plugins' -log = require 'winston' -config = require '../../server_config' -jsonSchema = require '../../app/schemas/models/campaign.schema' - -CampaignSchema = new mongoose.Schema(body: String, {strict: false,read:config.mongo.readpref}) - -CampaignSchema.index({i18nCoverage: 1}, {name: 'translation coverage index', sparse: true}) -CampaignSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true}) -CampaignSchema.index({type: 1}, {name: 'type index', sparse: true}) - -CampaignSchema.plugin(plugins.NamedPlugin) -CampaignSchema.plugin(plugins.TranslationCoveragePlugin) -CampaignSchema.plugin plugins.PatchablePlugin - -CampaignSchema.statics.updateAdjacentCampaigns = (savedCampaign) -> - Campaign = require '../campaigns/Campaign' - query = {} - query["adjacentCampaigns.#{savedCampaign.get '_id'}"] = {$exists: true} - Campaign.find(query).exec (err, campaigns) -> - return log.error "Couldn't search for adjacent campaigns to update because of #{err}" if err - for campaign in campaigns - acs = campaign.get 'adjacentCampaigns' - ac = acs[savedCampaign.get '_id'] - # Let's make sure that we're adding translations, otherwise let's not update yet. - # We could possibly remove this; not sure it's worth having. - [oldI18NCount, newI18NCount] = [0, 0] - oldI18NCount += _.size(translations) for lang, translations of ac.i18n ? {} - newI18NCount += _.size(translations) for lang, translations of savedCampaign.get('i18n') ? {} - continue unless newI18NCount > oldI18NCount - ac.i18n = savedCampaign.get('i18n') - # Save without using middleware so that we don't get into a post-save loop. - Campaign.findByIdAndUpdate campaign._id, {$set: {adjacentCampaigns: acs}}, (err, doc) -> - return log.error "Couldn't save updated adjacent campaign because of #{err}" if err - -CampaignSchema.post 'save', -> @constructor.updateAdjacentCampaigns @ - -CampaignSchema.statics.jsonSchema = jsonSchema - -module.exports = mongoose.model('campaign', CampaignSchema) diff --git a/server/campaigns/campaign_handler.coffee b/server/campaigns/campaign_handler.coffee index b5a330556..e3cb82a44 100644 --- a/server/campaigns/campaign_handler.coffee +++ b/server/campaigns/campaign_handler.coffee @@ -1,6 +1,6 @@ -Campaign = require './Campaign' -Level = require '../levels/Level' -Achievement = require '../achievements/Achievement' +Campaign = require './../models/Campaign' +Level = require '../models/Level' +Achievement = require '../models/Achievement' Handler = require '../commons/Handler' async = require 'async' mongoose = require 'mongoose' diff --git a/server/clans/clan_handler.coffee b/server/clans/clan_handler.coffee index 7dbc6060c..84cbf4a69 100644 --- a/server/clans/clan_handler.coffee +++ b/server/clans/clan_handler.coffee @@ -1,13 +1,13 @@ async = require 'async' mongoose = require 'mongoose' Handler = require '../commons/Handler' -AnalyticsLogEvent = require '../analytics/AnalyticsLogEvent' -Clan = require './Clan' -EarnedAchievement = require '../achievements/EarnedAchievement' +AnalyticsLogEvent = require '../models/AnalyticsLogEvent' +Clan = require './../models/Clan' +EarnedAchievement = require '../models/EarnedAchievement' EarnedAchievementHandler = require '../achievements/earned_achievement_handler' -LevelSession = require '../levels/sessions/LevelSession' +LevelSession = require '../models/LevelSession' LevelSessionHandler = require '../levels/sessions/level_session_handler' -User = require '../users/User' +User = require '../models/User' UserHandler = require '../users/user_handler' memberLimit = 200 diff --git a/server/classrooms/Classroom.coffee b/server/classrooms/Classroom.coffee deleted file mode 100644 index d6646686a..000000000 --- a/server/classrooms/Classroom.coffee +++ /dev/null @@ -1,63 +0,0 @@ -mongoose = require 'mongoose' -log = require 'winston' -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} - -ClassroomSchema.index({ownerID: 1}, {name: 'ownerID index'}) -ClassroomSchema.index({members: 1}, {name: 'members index'}) -ClassroomSchema.index({code: 1}, {name: 'code index', unique: true}) - -ClassroomSchema.statics.privateProperties = [] -ClassroomSchema.statics.editableProperties = [ - 'description' - 'name' - 'aceConfig' - 'averageStudentExp' - 'ageRangeMin' - 'ageRangeMax' - 'archived' -] - -ClassroomSchema.statics.generateNewCode = (done) -> - tryCode = -> - # 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 - return done(code, codeCamel) unless classroom - tryCode() - tryCode() - -ClassroomSchema.pre('save', (next) -> - return next() if @get('code') - Classroom.generateNewCode (code, codeCamel) => - @set 'code', code - @set 'codeCamel', codeCamel - next() -) - -ClassroomSchema.methods.isOwner = (userID) -> - return userID.equals(@get('ownerID')) - -ClassroomSchema.methods.isMember = (userID) -> - return _.any @get('members') or [], (memberID) -> userID.equals(memberID) - -ClassroomSchema.statics.jsonSchema = jsonSchema - -ClassroomSchema.set('toObject', { - transform: (doc, ret, options) -> - return ret unless options.req - user = options.req.user - unless user?.isAdmin() or user?.get('_id').equals(doc.get('ownerID')) - delete ret.code - delete ret.codeCamel - return ret -}) - -module.exports = Classroom = mongoose.model 'classroom', ClassroomSchema, 'classrooms' diff --git a/server/classrooms/classroom_handler.coffee b/server/classrooms/classroom_handler.coffee index bc727724a..149fe3c9b 100644 --- a/server/classrooms/classroom_handler.coffee +++ b/server/classrooms/classroom_handler.coffee @@ -1,8 +1,8 @@ async = require 'async' mongoose = require 'mongoose' Handler = require '../commons/Handler' -Classroom = require './Classroom' -User = require '../users/User' +Classroom = require './../models/Classroom' +User = require '../models/User' sendwithus = require '../sendwithus' utils = require '../lib/utils' UserHandler = require '../users/user_handler' diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index 7a7384e76..aceff9437 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -3,8 +3,8 @@ mongoose = require 'mongoose' Grid = require 'gridfs-stream' errors = require './errors' log = require 'winston' -Patch = require '../patches/Patch' -User = require '../users/User' +Patch = require '../models/Patch' +User = require '../models/User' sendwithus = require '../sendwithus' slack = require '../slack' deltasLib = require '../../app/core/deltas' diff --git a/server/commons/database.coffee b/server/commons/database.coffee index b17ab239f..e1dd132d1 100644 --- a/server/commons/database.coffee +++ b/server/commons/database.coffee @@ -19,7 +19,7 @@ module.exports = # Hack around Mongoose not exporting Aggregate so that we can patch its exec, too # https://github.com/LearnBoost/mongoose/issues/1910 - Level = require '../levels/Level' + Level = require '../models/Level' Aggregate = Level.aggregate().constructor maxAge = (Math.random() * 10 + 10) * 60 * 1000 # Randomize so that each server doesn't refresh cache from db at same times mongooseCache.install(mongoose, {max: 1000, maxAge: maxAge, debug: false}, Aggregate) diff --git a/server/courses/CourseInstance.coffee b/server/courses/CourseInstance.coffee deleted file mode 100644 index e51ec4b0e..000000000 --- a/server/courses/CourseInstance.coffee +++ /dev/null @@ -1,32 +0,0 @@ -mongoose = require 'mongoose' -config = require '../../server_config' -plugins = require '../plugins/plugins' -jsonSchema = require '../../app/schemas/models/course_instance.schema' - -CourseInstanceSchema = new mongoose.Schema { - ownerID: mongoose.Schema.Types.ObjectId - courseID: mongoose.Schema.Types.ObjectId - classroomID: mongoose.Schema.Types.ObjectId - prepaidID: mongoose.Schema.Types.ObjectId - members: [mongoose.Schema.Types.ObjectId] -}, {strict: false, minimize: false, read:config.mongo.readpref} - -CourseInstanceSchema.index({ownerID: 1}, {name: 'ownerID index'}) -CourseInstanceSchema.index({members: 1}, {name: 'members index'}) -CourseInstanceSchema.index({classroomID: 1}, {name: 'classroomID index', sparse: true}) -CourseInstanceSchema.index({prepaidID: 1}, {name: 'prepaidID index', sparse: true}) # Deprecated? Can we get rid of this? - -CourseInstanceSchema.statics.privateProperties = [] -CourseInstanceSchema.statics.editableProperties = [ - 'description' - 'name' - 'aceConfig' -] -CourseInstanceSchema.statics.postEditableProperties = [ - 'courseID' - 'classroomID' -] - -CourseInstanceSchema.statics.jsonSchema = jsonSchema - -module.exports = CourseInstance = mongoose.model 'course.instance', CourseInstanceSchema, 'course.instances' diff --git a/server/courses/course_instance_handler.coffee b/server/courses/course_instance_handler.coffee index 5543fcf8e..6c7a425cc 100644 --- a/server/courses/course_instance_handler.coffee +++ b/server/courses/course_instance_handler.coffee @@ -1,14 +1,14 @@ async = require 'async' Handler = require '../commons/Handler' -Campaign = require '../campaigns/Campaign' -Classroom = require '../classrooms/Classroom' +Campaign = require '../models/Campaign' +Classroom = require '../models/Classroom' Course = require '../models/Course' -CourseInstance = require './CourseInstance' -LevelSession = require '../levels/sessions/LevelSession' +CourseInstance = require './../models/CourseInstance' +LevelSession = require '../models/LevelSession' LevelSessionHandler = require '../levels/sessions/level_session_handler' -Prepaid = require '../prepaids/Prepaid' +Prepaid = require '../models/Prepaid' PrepaidHandler = require '../prepaids/prepaid_handler' -User = require '../users/User' +User = require '../models/User' UserHandler = require '../users/user_handler' utils = require '../../app/core/utils' {objectIdFromTimestamp} = require '../lib/utils' diff --git a/server/levels/components/level_component_handler.coffee b/server/levels/components/level_component_handler.coffee index 67997abe2..e68b5ab24 100644 --- a/server/levels/components/level_component_handler.coffee +++ b/server/levels/components/level_component_handler.coffee @@ -1,4 +1,4 @@ -LevelComponent = require './LevelComponent' +LevelComponent = require './../../models/LevelComponent' Handler = require '../../commons/Handler' mongoose = require 'mongoose' diff --git a/server/levels/feedbacks/level_feedback_handler.coffee b/server/levels/feedbacks/level_feedback_handler.coffee index 4226b1d07..279e3e4ac 100644 --- a/server/levels/feedbacks/level_feedback_handler.coffee +++ b/server/levels/feedbacks/level_feedback_handler.coffee @@ -1,4 +1,4 @@ -LevelFeedback = require './LevelFeedback' +LevelFeedback = require './../../models/LevelFeedback' Handler = require '../../commons/Handler' class LevelFeedbackHandler extends Handler diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 05fc579af..c84413ebd 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -1,17 +1,17 @@ -Level = require './Level' -Session = require './sessions/LevelSession' -User = require '../users/User' +Level = require './../models/Level' +Session = require './../models/LevelSession' +User = require '../models/User' SessionHandler = require './sessions/level_session_handler' -Feedback = require './feedbacks/LevelFeedback' +Feedback = require './../models/LevelFeedback' Handler = require '../commons/Handler' mongoose = require 'mongoose' async = require 'async' utils = require '../lib/utils' log = require 'winston' -Campaign = require '../campaigns/Campaign' +Campaign = require '../models/Campaign' Course = require '../models/Course' -CourseInstance = require '../courses/CourseInstance' -Classroom = require '../classrooms/Classroom' +CourseInstance = require '../models/CourseInstance' +Classroom = require '../models/Classroom' LevelHandler = class LevelHandler extends Handler modelClass: Level diff --git a/server/levels/sessions/level_session_handler.coffee b/server/levels/sessions/level_session_handler.coffee index 5ce45af02..2a48d2da8 100644 --- a/server/levels/sessions/level_session_handler.coffee +++ b/server/levels/sessions/level_session_handler.coffee @@ -1,4 +1,4 @@ -LevelSession = require './LevelSession' +LevelSession = require './../../models/LevelSession' Handler = require '../../commons/Handler' log = require 'winston' diff --git a/server/levels/systems/level_system_handler.coffee b/server/levels/systems/level_system_handler.coffee index 4c356f1d7..ec825d7d8 100644 --- a/server/levels/systems/level_system_handler.coffee +++ b/server/levels/systems/level_system_handler.coffee @@ -1,4 +1,4 @@ -LevelSystem = require './LevelSystem' +LevelSystem = require './../../models/LevelSystem' Handler = require '../../commons/Handler' LevelSystemHandler = class LevelSystemHandler extends Handler diff --git a/server/levels/thangs/thang_type_handler.coffee b/server/levels/thangs/thang_type_handler.coffee index 246c6b4bd..84d42bbe3 100644 --- a/server/levels/thangs/thang_type_handler.coffee +++ b/server/levels/thangs/thang_type_handler.coffee @@ -1,4 +1,4 @@ -ThangType = require './ThangType' +ThangType = require './../../models/ThangType' Handler = require '../../commons/Handler' ThangTypeHandler = class ThangTypeHandler extends Handler diff --git a/server/lib/picoctf.coffee b/server/lib/picoctf.coffee index 811aab213..2837b76e4 100644 --- a/server/lib/picoctf.coffee +++ b/server/lib/picoctf.coffee @@ -1,6 +1,6 @@ config = require '../../server_config' request = require 'request' -User = require '../users/User' +User = require '../models/User' http = require 'http' authstr = new Buffer("#{config.picoCTF_auth.username}:#{config.picoCTF_auth.password}").toString 'base64' diff --git a/server/lib/stripe_utils.coffee b/server/lib/stripe_utils.coffee index 3b7fa9727..03a00026f 100644 --- a/server/lib/stripe_utils.coffee +++ b/server/lib/stripe_utils.coffee @@ -1,5 +1,5 @@ log = require 'winston' -Payment = require '../payments/Payment' +Payment = require '../models/Payment' PaymentHandler = require '../payments/payment_handler' module.exports = diff --git a/server/lib/utils.coffee b/server/lib/utils.coffee index ce45f422b..37afc050f 100644 --- a/server/lib/utils.coffee +++ b/server/lib/utils.coffee @@ -1,4 +1,4 @@ -AnalyticsString = require '../analytics/AnalyticsString' +AnalyticsString = require '../models/AnalyticsString' log = require 'winston' mongoose = require 'mongoose' config = require '../../server_config' diff --git a/server/mail/sent/mail_sent_handler.coffee b/server/mail/sent/mail_sent_handler.coffee index 35e920c2b..63d6369ff 100644 --- a/server/mail/sent/mail_sent_handler.coffee +++ b/server/mail/sent/mail_sent_handler.coffee @@ -1,4 +1,4 @@ -MailSent = require './MailSent' +MailSent = require './../../models/MailSent' Handler = require '../../commons/Handler' class MailSentHandler extends Handler diff --git a/server/middleware/auth.coffee b/server/middleware/auth.coffee index 66a308f23..a8d087780 100644 --- a/server/middleware/auth.coffee +++ b/server/middleware/auth.coffee @@ -5,7 +5,7 @@ wrap = require 'co-express' Promise = require 'bluebird' parse = require '../commons/parse' request = require 'request' -User = require '../users/User' +User = require '../models/User' utils = require '../lib/utils' mongoose = require 'mongoose' diff --git a/server/middleware/campaigns.coffee b/server/middleware/campaigns.coffee index 5c4bb4aaf..c5d003ca5 100644 --- a/server/middleware/campaigns.coffee +++ b/server/middleware/campaigns.coffee @@ -4,9 +4,9 @@ wrap = require 'co-express' Promise = require 'bluebird' database = require '../commons/database' mongoose = require 'mongoose' -Campaign = require '../campaigns/Campaign' +Campaign = require '../models/Campaign' parse = require '../commons/parse' -LevelSession = require '../levels/sessions/LevelSession' +LevelSession = require '../models/LevelSession' module.exports = fetchByType: wrap (req, res, next) -> diff --git a/server/middleware/classrooms.coffee b/server/middleware/classrooms.coffee index 708a22f2b..1464eed6a 100644 --- a/server/middleware/classrooms.coffee +++ b/server/middleware/classrooms.coffee @@ -5,10 +5,10 @@ wrap = require 'co-express' Promise = require 'bluebird' database = require '../commons/database' mongoose = require 'mongoose' -Classroom = require '../classrooms/Classroom' +Classroom = require '../models/Classroom' parse = require '../commons/parse' -LevelSession = require '../levels/sessions/LevelSession' -User = require '../users/User' +LevelSession = require '../models/LevelSession' +User = require '../models/User' module.exports = getByOwner: wrap (req, res, next) -> diff --git a/server/middleware/users.coffee b/server/middleware/users.coffee index eac3837e8..5b4f30d50 100644 --- a/server/middleware/users.coffee +++ b/server/middleware/users.coffee @@ -3,7 +3,7 @@ wrap = require 'co-express' Promise = require 'bluebird' parse = require '../commons/parse' request = require 'request' -User = require '../users/User' +User = require '../models/User' module.exports = diff --git a/server/middleware/versions.coffee b/server/middleware/versions.coffee index 0e464a49c..b87e56a8d 100644 --- a/server/middleware/versions.coffee +++ b/server/middleware/versions.coffee @@ -1,6 +1,6 @@ utils = require '../lib/utils' errors = require '../commons/errors' -User = require '../users/User' +User = require '../models/User' sendwithus = require '../sendwithus' slack = require '../slack' _ = require 'lodash' diff --git a/server/achievements/Achievement.coffee b/server/models/Achievement.coffee similarity index 98% rename from server/achievements/Achievement.coffee rename to server/models/Achievement.coffee index 4ca286e71..30277712d 100644 --- a/server/achievements/Achievement.coffee +++ b/server/models/Achievement.coffee @@ -55,7 +55,7 @@ AchievementSchema.statics.achievementCollections = {} # TODO might want to tweak this to only load new achievements AchievementSchema.statics.loadAchievements = (done) -> AchievementSchema.statics.resetAchievements() - Achievement = require('../achievements/Achievement') + Achievement = require('./Achievement') query = Achievement.find({collection: {$ne: 'level.sessions'}}) query.exec (err, docs) -> _.each docs, (achievement) -> diff --git a/server/analytics/AnalyticsLogEvent.coffee b/server/models/AnalyticsLogEvent.coffee similarity index 100% rename from server/analytics/AnalyticsLogEvent.coffee rename to server/models/AnalyticsLogEvent.coffee diff --git a/server/analytics/AnalyticsPerDay.coffee b/server/models/AnalyticsPerDay.coffee similarity index 100% rename from server/analytics/AnalyticsPerDay.coffee rename to server/models/AnalyticsPerDay.coffee diff --git a/server/analytics/AnalyticsString.coffee b/server/models/AnalyticsString.coffee similarity index 100% rename from server/analytics/AnalyticsString.coffee rename to server/models/AnalyticsString.coffee diff --git a/server/analytics/AnalyticsStripeInvoice.coffee b/server/models/AnalyticsStripeInvoice.coffee similarity index 100% rename from server/analytics/AnalyticsStripeInvoice.coffee rename to server/models/AnalyticsStripeInvoice.coffee diff --git a/server/analytics/AnalyticsUsersActive.coffee b/server/models/AnalyticsUsersActive.coffee similarity index 100% rename from server/analytics/AnalyticsUsersActive.coffee rename to server/models/AnalyticsUsersActive.coffee diff --git a/server/models/Article.coffee b/server/models/Article.coffee index 485f8dc13..3bb6db297 100644 --- a/server/models/Article.coffee +++ b/server/models/Article.coffee @@ -1,3 +1,43 @@ -# TODO: Migrate Article to here +mongoose = require 'mongoose' +plugins = require '../plugins/plugins' +config = require '../../server_config' -module.exports = require '../articles/Article' \ No newline at end of file +ArticleSchema = new mongoose.Schema(body: String, {strict: false,read:config.mongo.readpref}) + +ArticleSchema.index( + { + index: 1 + _fts: 'text' + _ftsx: 1 + }, + { + name: 'search index' + sparse: true + weights: {body: 1, name: 1} + default_language: 'english' + 'language_override': 'searchLanguage' + 'textIndexVersion': 2 + }) +ArticleSchema.index( + { + original: 1 + 'version.major': -1 + 'version.minor': -1 + }, + { + name: 'version index' + unique: true + }) +ArticleSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true}) + +ArticleSchema.plugin(plugins.NamedPlugin) +ArticleSchema.plugin(plugins.VersionedPlugin) +ArticleSchema.plugin(plugins.SearchablePlugin, {searchable: ['body', 'name']}) +ArticleSchema.plugin(plugins.TranslationCoveragePlugin) +ArticleSchema.plugin(plugins.PatchablePlugin) + +ArticleSchema.statics.postEditableProperties = [] +ArticleSchema.statics.editableProperties = ['body', 'name', 'i18n', 'i18nCoverage'] +ArticleSchema.statics.jsonSchema = require '../../app/schemas/models/article' + +module.exports = mongoose.model('article', ArticleSchema) diff --git a/server/models/Campaign.coffee b/server/models/Campaign.coffee index 7f9be2b0d..28c0d87b3 100644 --- a/server/models/Campaign.coffee +++ b/server/models/Campaign.coffee @@ -1,3 +1,41 @@ -# TODO: Migrate Campaign to here +mongoose = require 'mongoose' +plugins = require '../plugins/plugins' +log = require 'winston' +config = require '../../server_config' +jsonSchema = require '../../app/schemas/models/campaign.schema.coffee' -module.exports = require '../campaigns/Campaign' +CampaignSchema = new mongoose.Schema(body: String, {strict: false,read:config.mongo.readpref}) + +CampaignSchema.index({i18nCoverage: 1}, {name: 'translation coverage index', sparse: true}) +CampaignSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true}) +CampaignSchema.index({type: 1}, {name: 'type index', sparse: true}) + +CampaignSchema.plugin(plugins.NamedPlugin) +CampaignSchema.plugin(plugins.TranslationCoveragePlugin) +CampaignSchema.plugin plugins.PatchablePlugin + +CampaignSchema.statics.updateAdjacentCampaigns = (savedCampaign) -> + Campaign = require './Campaign' + query = {} + query["adjacentCampaigns.#{savedCampaign.get '_id'}"] = {$exists: true} + Campaign.find(query).exec (err, campaigns) -> + return log.error "Couldn't search for adjacent campaigns to update because of #{err}" if err + for campaign in campaigns + acs = campaign.get 'adjacentCampaigns' + ac = acs[savedCampaign.get '_id'] + # Let's make sure that we're adding translations, otherwise let's not update yet. + # We could possibly remove this; not sure it's worth having. + [oldI18NCount, newI18NCount] = [0, 0] + oldI18NCount += _.size(translations) for lang, translations of ac.i18n ? {} + newI18NCount += _.size(translations) for lang, translations of savedCampaign.get('i18n') ? {} + continue unless newI18NCount > oldI18NCount + ac.i18n = savedCampaign.get('i18n') + # Save without using middleware so that we don't get into a post-save loop. + Campaign.findByIdAndUpdate campaign._id, {$set: {adjacentCampaigns: acs}}, (err, doc) -> + return log.error "Couldn't save updated adjacent campaign because of #{err}" if err + +CampaignSchema.post 'save', -> @constructor.updateAdjacentCampaigns @ + +CampaignSchema.statics.jsonSchema = jsonSchema + +module.exports = mongoose.model('campaign', CampaignSchema) diff --git a/server/clans/Clan.coffee b/server/models/Clan.coffee similarity index 89% rename from server/clans/Clan.coffee rename to server/models/Clan.coffee index 8749055d9..98087d81c 100644 --- a/server/clans/Clan.coffee +++ b/server/models/Clan.coffee @@ -2,8 +2,8 @@ mongoose = require 'mongoose' log = require 'winston' config = require '../../server_config' plugins = require '../plugins/plugins' -User = require '../users/User' -jsonSchema = require '../../app/schemas/models/clan.schema' +User = require './User' +jsonSchema = require '../../app/schemas/models/clan.schema.coffee' ClanSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} diff --git a/server/models/Classroom.coffee b/server/models/Classroom.coffee index 609a1e47b..05e835d8f 100644 --- a/server/models/Classroom.coffee +++ b/server/models/Classroom.coffee @@ -1,3 +1,63 @@ -# TODO: Migrate Classroom to here +mongoose = require 'mongoose' +log = require 'winston' +config = require '../../server_config' +plugins = require '../plugins/plugins' +User = require './User' +jsonSchema = require '../../app/schemas/models/classroom.schema.coffee' +utils = require '../lib/utils' -module.exports = require '../classrooms/Classroom' +ClassroomSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} + +ClassroomSchema.index({ownerID: 1}, {name: 'ownerID index'}) +ClassroomSchema.index({members: 1}, {name: 'members index'}) +ClassroomSchema.index({code: 1}, {name: 'code index', unique: true}) + +ClassroomSchema.statics.privateProperties = [] +ClassroomSchema.statics.editableProperties = [ + 'description' + 'name' + 'aceConfig' + 'averageStudentExp' + 'ageRangeMin' + 'ageRangeMax' + 'archived' +] + +ClassroomSchema.statics.generateNewCode = (done) -> + tryCode = -> + # 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 + return done(code, codeCamel) unless classroom + tryCode() + tryCode() + +ClassroomSchema.pre('save', (next) -> + return next() if @get('code') + Classroom.generateNewCode (code, codeCamel) => + @set 'code', code + @set 'codeCamel', codeCamel + next() +) + +ClassroomSchema.methods.isOwner = (userID) -> + return userID.equals(@get('ownerID')) + +ClassroomSchema.methods.isMember = (userID) -> + return _.any @get('members') or [], (memberID) -> userID.equals(memberID) + +ClassroomSchema.statics.jsonSchema = jsonSchema + +ClassroomSchema.set('toObject', { + transform: (doc, ret, options) -> + return ret unless options.req + user = options.req.user + unless user?.isAdmin() or user?.get('_id').equals(doc.get('ownerID')) + delete ret.code + delete ret.codeCamel + return ret +}) + +module.exports = Classroom = mongoose.model 'classroom', ClassroomSchema, 'classrooms' diff --git a/server/models/CourseInstance.coffee b/server/models/CourseInstance.coffee index adc60090e..b249e5619 100644 --- a/server/models/CourseInstance.coffee +++ b/server/models/CourseInstance.coffee @@ -1,3 +1,32 @@ -# TODO: Migrate CourseInstance to here +mongoose = require 'mongoose' +config = require '../../server_config' +plugins = require '../plugins/plugins' +jsonSchema = require '../../app/schemas/models/course_instance.schema.coffee' -module.exports = require '../courses/CourseInstance' +CourseInstanceSchema = new mongoose.Schema { + ownerID: mongoose.Schema.Types.ObjectId + courseID: mongoose.Schema.Types.ObjectId + classroomID: mongoose.Schema.Types.ObjectId + prepaidID: mongoose.Schema.Types.ObjectId + members: [mongoose.Schema.Types.ObjectId] +}, {strict: false, minimize: false, read:config.mongo.readpref} + +CourseInstanceSchema.index({ownerID: 1}, {name: 'ownerID index'}) +CourseInstanceSchema.index({members: 1}, {name: 'members index'}) +CourseInstanceSchema.index({classroomID: 1}, {name: 'classroomID index', sparse: true}) +CourseInstanceSchema.index({prepaidID: 1}, {name: 'prepaidID index', sparse: true}) # Deprecated? Can we get rid of this? + +CourseInstanceSchema.statics.privateProperties = [] +CourseInstanceSchema.statics.editableProperties = [ + 'description' + 'name' + 'aceConfig' +] +CourseInstanceSchema.statics.postEditableProperties = [ + 'courseID' + 'classroomID' +] + +CourseInstanceSchema.statics.jsonSchema = jsonSchema + +module.exports = CourseInstance = mongoose.model 'course.instance', CourseInstanceSchema, 'course.instances' diff --git a/server/achievements/EarnedAchievement.coffee b/server/models/EarnedAchievement.coffee similarity index 99% rename from server/achievements/EarnedAchievement.coffee rename to server/models/EarnedAchievement.coffee index a963c0bed..9c7cf7d46 100644 --- a/server/achievements/EarnedAchievement.coffee +++ b/server/models/EarnedAchievement.coffee @@ -17,7 +17,7 @@ EarnedAchievementSchema.index({user: 1, achievement: 1}, {unique: true, name: 'e EarnedAchievementSchema.index({user: 1, changed: -1}, {name: 'latest '}) EarnedAchievementSchema.statics.createForAchievement = (achievement, doc, originalDocObj=null, previouslyEarnedAchievement=null, done) -> - User = require '../users/User' + User = require './User' userObjectID = doc.get(achievement.get('userField')) userID = if _.isObject userObjectID then userObjectID.toHexString() else userObjectID # Standardize! Use strings, not ObjectId's diff --git a/server/levels/Level.coffee b/server/models/Level.coffee similarity index 100% rename from server/levels/Level.coffee rename to server/models/Level.coffee diff --git a/server/levels/components/LevelComponent.coffee b/server/models/LevelComponent.coffee similarity index 90% rename from server/levels/components/LevelComponent.coffee rename to server/models/LevelComponent.coffee index 68280f661..673bb2c31 100644 --- a/server/levels/components/LevelComponent.coffee +++ b/server/models/LevelComponent.coffee @@ -1,7 +1,7 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -jsonschema = require '../../../app/schemas/models/level_component' -config = require '../../../server_config' +plugins = require '../plugins/plugins' +jsonschema = require '../../app/schemas/models/level_component' +config = require '../../server_config' LevelComponentSchema = new mongoose.Schema { description: String diff --git a/server/levels/feedbacks/LevelFeedback.coffee b/server/models/LevelFeedback.coffee similarity index 75% rename from server/levels/feedbacks/LevelFeedback.coffee rename to server/models/LevelFeedback.coffee index 1e3a47950..5a2f866c1 100644 --- a/server/levels/feedbacks/LevelFeedback.coffee +++ b/server/models/LevelFeedback.coffee @@ -1,9 +1,9 @@ # TODO: not updated since rename from level_instance, or since we redid how all models are done; probably busted mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -jsonschema = require '../../../app/schemas/models/level_feedback' -config = require '../../../server_config' +plugins = require '../plugins/plugins' +jsonschema = require '../../app/schemas/models/level_feedback' +config = require '../../server_config' LevelFeedbackSchema = new mongoose.Schema({ created: diff --git a/server/levels/sessions/LevelSession.coffee b/server/models/LevelSession.coffee similarity index 94% rename from server/levels/sessions/LevelSession.coffee rename to server/models/LevelSession.coffee index 86f94f134..06846e3cc 100644 --- a/server/levels/sessions/LevelSession.coffee +++ b/server/models/LevelSession.coffee @@ -1,9 +1,9 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -AchievablePlugin = require '../../plugins/achievements' -jsonschema = require '../../../app/schemas/models/level_session' +plugins = require '../plugins/plugins' +AchievablePlugin = require '../plugins/achievements' +jsonschema = require '../../app/schemas/models/level_session' log = require 'winston' -config = require '../../../server_config' +config = require '../../server_config' LevelSessionSchema = new mongoose.Schema({ created: @@ -43,8 +43,8 @@ LevelSessionSchema.post 'init', (doc) -> playtime: doc.get 'playtime' LevelSessionSchema.pre 'save', (next) -> - User = require '../../users/User' # Avoid mutual inclusion cycles - Level = require '../Level' + User = require './User' # Avoid mutual inclusion cycles + Level = require './Level' @set('changed', new Date()) id = @get('id') diff --git a/server/levels/systems/LevelSystem.coffee b/server/models/LevelSystem.coffee similarity index 87% rename from server/levels/systems/LevelSystem.coffee rename to server/models/LevelSystem.coffee index 1d3cb53af..b85731434 100644 --- a/server/levels/systems/LevelSystem.coffee +++ b/server/models/LevelSystem.coffee @@ -1,7 +1,7 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -jsonschema = require '../../../app/schemas/models/level_system' -config = require '../../../server_config' +plugins = require '../plugins/plugins' +jsonschema = require '../../app/schemas/models/level_system' +config = require '../../server_config' LevelSystemSchema = new mongoose.Schema { description: String diff --git a/server/levels/thangs/LevelThangType.coffee b/server/models/LevelThangType.coffee similarity index 97% rename from server/levels/thangs/LevelThangType.coffee rename to server/models/LevelThangType.coffee index 264ef5348..b7c34745a 100644 --- a/server/levels/thangs/LevelThangType.coffee +++ b/server/models/LevelThangType.coffee @@ -1,5 +1,5 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' +plugins = require '../plugins/plugins' LevelComponentSchema = new mongoose.Schema( original: {type: mongoose.Schema.ObjectId, ref: 'level.session'} diff --git a/server/mail/sent/MailSent.coffee b/server/models/MailSent.coffee similarity index 70% rename from server/mail/sent/MailSent.coffee rename to server/models/MailSent.coffee index f87bc6743..71c51a04e 100644 --- a/server/mail/sent/MailSent.coffee +++ b/server/models/MailSent.coffee @@ -1,6 +1,6 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -jsonschema = require '../../../app/schemas/models/mail_sent' +plugins = require '../plugins/plugins' +jsonschema = require '../../app/schemas/models/mail_sent' MailSent = new mongoose.Schema({ sent: diff --git a/server/models/Patch.coffee b/server/models/Patch.coffee index 3246062d8..9aaabd981 100644 --- a/server/models/Patch.coffee +++ b/server/models/Patch.coffee @@ -1,3 +1,79 @@ -# TODO: Migrate Patch to here +mongoose = require('mongoose') +deltas = require '../../app/core/deltas' +log = require 'winston' +{handlers} = require '../commons/mapping' +config = require '../../server_config' -module.exports = require '../patches/Patch' \ No newline at end of file +PatchSchema = new mongoose.Schema({status: String}, {strict: false,read:config.mongo.readpref}) + +PatchSchema.pre 'save', (next) -> + return next() unless @isNew # patch can't be altered after creation, so only need to check data once + target = @get('target') + targetID = target.id + Handler = require '../commons/Handler' + if not Handler.isID(targetID) + err = new Error('Invalid input.') + err.response = {message: 'isn\'t a MongoDB id.', property: 'target.id'} + err.code = 422 + return next(err) + + collection = target.collection + handler = require('../' + handlers[collection]) + handler.getDocumentForIdOrSlug targetID, (err, document) => + if err + err = new Error('Server error.') + err.response = {message: '', property: 'target.id'} + err.code = 500 + return next(err) + + if not document + err = new Error('Target of patch not found.') + err.response = {message: 'was not found.', property: 'target.id'} + err.code = 404 + return next(err) + + target.id = document.get('_id') + if handler.modelClass.schema.uses_coco_versions + target.original = document.get('original') + version = document.get('version') + target.version = _.pick document.get('version'), 'major', 'minor' + @set('target', target) + else + target.original = targetID + + patches = document.get('patches') or [] + patches = _.clone patches + patches.push @_id + document.set 'patches', patches, {strict: false} + @targetLoaded = document + document.save (err) -> next(err) + +PatchSchema.methods.isTranslationPatch = -> # Don't ever fat arrow bind this one + expanded = deltas.flattenDelta @get('delta') + _.some expanded, (delta) -> 'i18n' in delta.dataPath + +PatchSchema.methods.isMiscPatch = -> + expanded = deltas.flattenDelta @get('delta') + _.some expanded, (delta) -> 'i18n' not in delta.dataPath + +# Keep track of when a patch is pending and newly approved. +PatchSchema.path('status').set (newVal) -> + @set 'wasPending', @status is 'pending' and newVal isnt 'pending' + @set 'newlyAccepted', newVal is 'accepted' and not @get('newlyAccepted') # Only true on the first accept + newVal + +PatchSchema.methods.isNewlyAccepted = -> @get('newlyAccepted') +PatchSchema.methods.wasPending = -> @get 'wasPending' + +PatchSchema.pre 'save', (next) -> + User = require './User' + userID = @get('creator').toHexString() + + if @get('status') is 'accepted' + User.incrementStat userID, 'stats.patchesContributed' # accepted patches + else if @get('status') is 'pending' + User.incrementStat userID, 'stats.patchesSubmitted' # submitted patches + + next() + +module.exports = mongoose.model('patch', PatchSchema) diff --git a/server/payments/Payment.coffee b/server/models/Payment.coffee similarity index 100% rename from server/payments/Payment.coffee rename to server/models/Payment.coffee diff --git a/server/polls/Poll.coffee b/server/models/Poll.coffee similarity index 94% rename from server/polls/Poll.coffee rename to server/models/Poll.coffee index e6ad7a609..807accb14 100644 --- a/server/polls/Poll.coffee +++ b/server/models/Poll.coffee @@ -1,6 +1,6 @@ mongoose = require 'mongoose' plugins = require '../plugins/plugins' -jsonSchema = require '../../app/schemas/models/poll.schema' +jsonSchema = require '../../app/schemas/models/poll.schema.coffee' log = require 'winston' config = require '../../server_config' PollSchema = new mongoose.Schema { diff --git a/server/prepaids/Prepaid.coffee b/server/models/Prepaid.coffee similarity index 100% rename from server/prepaids/Prepaid.coffee rename to server/models/Prepaid.coffee diff --git a/server/purchases/Purchase.coffee b/server/models/Purchase.coffee similarity index 100% rename from server/purchases/Purchase.coffee rename to server/models/Purchase.coffee diff --git a/server/queues/scoring/ScoringTask.coffee b/server/models/ScoringTask.coffee similarity index 100% rename from server/queues/scoring/ScoringTask.coffee rename to server/models/ScoringTask.coffee diff --git a/server/levels/thangs/ThangType.coffee b/server/models/ThangType.coffee similarity index 91% rename from server/levels/thangs/ThangType.coffee rename to server/models/ThangType.coffee index 732dc5f09..54920b120 100644 --- a/server/levels/thangs/ThangType.coffee +++ b/server/models/ThangType.coffee @@ -1,6 +1,6 @@ mongoose = require 'mongoose' -plugins = require '../../plugins/plugins' -config = require '../../../server_config' +plugins = require '../plugins/plugins' +config = require '../../server_config' ThangTypeSchema = new mongoose.Schema({ body: String, diff --git a/server/models/TrialRequest.coffee b/server/models/TrialRequest.coffee index c1e3e5012..536fa0984 100644 --- a/server/models/TrialRequest.coffee +++ b/server/models/TrialRequest.coffee @@ -3,10 +3,10 @@ log = require 'winston' mongoose = require 'mongoose' config = require '../../server_config' sendwithus = require '../sendwithus' -Prepaid = require '../prepaids/Prepaid' +Prepaid = require './Prepaid' jsonSchema = require '../../app/schemas/models/trial_request.schema' -Classroom = require '../classrooms/Classroom' -User = require '../users/User' +Classroom = require './Classroom' +User = require './User' TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, read:config.mongo.readpref} diff --git a/server/models/User.coffee b/server/models/User.coffee index 06ea46b31..bdb734152 100644 --- a/server/models/User.coffee +++ b/server/models/User.coffee @@ -1,3 +1,382 @@ -# TODO: Migrate User to here +mongoose = require 'mongoose' +jsonschema = require '../../app/schemas/models/user' +crypto = require 'crypto' +{salt, isProduction} = require '../../server_config' +mail = require '../commons/mail' +log = require 'winston' +plugins = require '../plugins/plugins' +AnalyticsUsersActive = require './AnalyticsUsersActive' -module.exports = require '../users/User' \ No newline at end of file +config = require '../../server_config' +stripe = require('stripe')(config.stripe.secretKey) + +sendwithus = require '../sendwithus' +delighted = require '../delighted' + +UserSchema = new mongoose.Schema({ + dateCreated: + type: Date + 'default': Date.now +}, {strict: false}) + +UserSchema.index({'dateCreated': 1}) +UserSchema.index({'emailLower': 1}, {unique: true, sparse: true, name: 'emailLower_1'}) +UserSchema.index({'facebookID': 1}, {sparse: true}) +UserSchema.index({'gplusID': 1}, {sparse: true}) +UserSchema.index({'iosIdentifierForVendor': 1}, {name: 'iOS identifier for vendor', sparse: true, unique: true}) +UserSchema.index({'mailChimp.leid': 1}, {sparse: true}) +UserSchema.index({'nameLower': 1}, {sparse: true, name: 'nameLower_1'}) +UserSchema.index({'simulatedBy': 1}) +UserSchema.index({'slug': 1}, {name: 'slug index', sparse: true, unique: true}) +UserSchema.index({'stripe.subscriptionID': 1}, {unique: true, sparse: true}) +UserSchema.index({'siteref': 1}, {name: 'siteref index', sparse: true}) +UserSchema.index({'schoolName': 1}, {name: 'schoolName index', sparse: true}) +UserSchema.index({'country': 1}, {name: 'country index', sparse: true}) +UserSchema.index({'role': 1}, {name: 'role index', sparse: true}) + +UserSchema.post('init', -> + @set('anonymous', false) if @get('email') +) + +UserSchema.methods.isInGodMode = -> + p = @get('permissions') + return p and 'godmode' in p + +UserSchema.methods.isAdmin = -> + p = @get('permissions') + return p and 'admin' in p + +UserSchema.methods.hasPermission = (neededPermissions) -> + permissions = @get('permissions') or [] + if _.contains(permissions, 'admin') + return true + if _.isString(neededPermissions) + neededPermissions = [neededPermissions] + return _.size(_.intersection(permissions, neededPermissions)) + +UserSchema.methods.isArtisan = -> + p = @get('permissions') + return p and 'artisan' in p + +UserSchema.methods.isAnonymous = -> + @get 'anonymous' + +UserSchema.statics.teacherRoles = ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent', 'parent'] + +UserSchema.methods.isTeacher = -> + return @get('role') in User.teacherRoles + +UserSchema.methods.getUserInfo = -> + id: @get('_id') + email: if @get('anonymous') then 'Unregistered User' else @get('email') + +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' + artisanNews: 'level_creator' + archmageNews: 'developer' + scribeNews: 'article_editor' + diplomatNews: 'translator' + ambassadorNews: 'support' + anyNotes: 'notification' + teacherNews: 'teacher' + +UserSchema.methods.setEmailSubscription = (newName, enabled) -> + oldSubs = _.clone @get('emailSubscriptions') + if oldSubs and oldName = emailNameMap[newName] + oldSubs = (s for s in oldSubs when s isnt oldName) + oldSubs.push(oldName) if enabled + @set('emailSubscriptions', oldSubs) + + newSubs = _.clone(@get('emails') or _.cloneDeep(jsonschema.properties.emails.default)) + newSubs[newName] ?= {} + newSubs[newName].enabled = enabled + @set('emails', newSubs) + @newsSubsChanged = true if newName in mail.NEWS_GROUPS + +UserSchema.methods.gems = -> + gemsEarned = @get('earned')?.gems ? 0 + gemsEarned = gemsEarned + 100000 if @isInGodMode() + gemsPurchased = @get('purchased')?.gems ? 0 + gemsSpent = @get('spent') ? 0 + gemsEarned + gemsPurchased - gemsSpent + +UserSchema.methods.isEmailSubscriptionEnabled = (newName) -> + emails = @get 'emails' + if not emails + oldSubs = @get('emailSubscriptions') + oldName = emailNameMap[newName] + return oldName and oldName in oldSubs if oldSubs + emails ?= {} + _.defaults emails, _.cloneDeep(jsonschema.properties.emails.default) + return emails[newName]?.enabled + +UserSchema.statics.updateServiceSettings = (doc, callback) -> + return callback?() unless isProduction or GLOBAL.testing + return callback?() if doc.updatedMailChimp + return callback?() unless doc.get('email') + existingProps = doc.get('mailChimp') + emailChanged = (not existingProps) or existingProps?.email isnt doc.get('email') + + if emailChanged and customerID = doc.get('stripe')?.customerID + unless stripe?.customers + console.error('Oh my god, Stripe is not imported correctly-how could we have done this (again)?') + stripe?.customers?.update customerID, {email:doc.get('email')}, (err, customer) -> + console.error('Error updating stripe customer...', err) if err + + return callback?() unless emailChanged or doc.newsSubsChanged + + newGroups = [] + for [mailchimpEmailGroup, emailGroup] in _.zip(mail.MAILCHIMP_GROUPS, mail.NEWS_GROUPS) + newGroups.push(mailchimpEmailGroup) if doc.isEmailSubscriptionEnabled(emailGroup) + + if (not existingProps) and newGroups.length is 0 + return callback?() # don't add totally unsubscribed people to the list + + params = {} + params.id = mail.MAILCHIMP_LIST_ID + params.email = if existingProps then {leid: existingProps.leid} else {email: doc.get('email')} + params.merge_vars = { + groupings: [{id: mail.MAILCHIMP_GROUP_ID, groups: newGroups}] + 'new-email': doc.get('email') + } + params.update_existing = true + + onSuccess = (data) -> + data.email = doc.get('email') # Make sure that we don't spam opt-in emails even if MailChimp doesn't update the email it gets in this object until they have confirmed. + doc.set('mailChimp', data) + doc.updatedMailChimp = true + doc.save() + callback?() + + onFailure = (error) -> + log.error 'failed to subscribe', error, callback? + doc.updatedMailChimp = true + callback?() + + mc?.lists.subscribe params, onSuccess, onFailure + +UserSchema.statics.statsMapping = + edits: + article: 'stats.articleEdits' + level: 'stats.levelEdits' + 'level.component': 'stats.levelComponentEdits' + 'level.system': 'stats.levelSystemEdits' + 'thang.type': 'stats.thangTypeEdits' + 'Achievement': 'stats.achievementEdits' + 'campaign': 'stats.campaignEdits' + 'poll': 'stats.pollEdits' + translations: + article: 'stats.articleTranslationPatches' + level: 'stats.levelTranslationPatches' + 'level.component': 'stats.levelComponentTranslationPatches' + 'level.system': 'stats.levelSystemTranslationPatches' + 'thang.type': 'stats.thangTypeTranslationPatches' + 'Achievement': 'stats.achievementTranslationPatches' + 'campaign': 'stats.campaignTranslationPatches' + 'poll': 'stats.pollTranslationPatches' + misc: + article: 'stats.articleMiscPatches' + level: 'stats.levelMiscPatches' + 'level.component': 'stats.levelComponentMiscPatches' + 'level.system': 'stats.levelSystemMiscPatches' + 'thang.type': 'stats.thangTypeMiscPatches' + 'Achievement': 'stats.achievementMiscPatches' + 'campaign': 'stats.campaignMiscPatches' + 'poll': 'stats.pollMiscPatches' + +UserSchema.statics.incrementStat = (id, statName, done, inc=1) -> + id = mongoose.Types.ObjectId id if _.isString id + @findById id, (err, user) -> + log.error err if err? + err = new Error "Could't find user with id '#{id}'" unless user or err + return done() if err? + user.incrementStat statName, done, inc + +UserSchema.methods.incrementStat = (statName, done, inc=1) -> + if /^concepts\./.test statName + # Concept stats are nested a level deeper. + concepts = @get('concepts') or {} + concept = statName.split('.')[1] + concepts[concept] = (concepts[concept] or 0) + inc + @set 'concepts', concepts + else + @set statName, (@get(statName) or 0) + inc + @save (err) -> done?(err) + +UserSchema.statics.unconflictName = unconflictName = (name, done) -> + User.findOne {slug: _.str.slugify(name)}, (err, otherUser) -> + return done err if err? + return done null, name unless otherUser + suffix = _.random(0, 9) + '' + unconflictName name + suffix, done + +UserSchema.methods.register = (done) -> + @set('anonymous', false) + if (name = @get 'name')? and name isnt '' + unconflictName name, (err, uniqueName) => + return done err if err + @set 'name', uniqueName + done() + else done() + if @isEmailSubscriptionEnabled 'generalNews' + data = + email_id: sendwithus.templates.welcome_email + recipient: + address: @get 'email' + sendwithus.api.send data, (err, result) -> + log.error "sendwithus post-save error: #{err}, result: #{result}" if err + delighted.addDelightedUser @ + @saveActiveUser 'register' + +UserSchema.methods.hasSubscription = -> + return false unless stripeObject = @get('stripe') + return true if stripeObject.sponsorID + return true if stripeObject.subscriptionID + return true if stripeObject.free is true + return true if _.isString(stripeObject.free) and new Date() < new Date(stripeObject.free) + +UserSchema.methods.isPremium = -> + return true if @isInGodMode() + return true if @isAdmin() + return true if @hasSubscription() + return false + +UserSchema.methods.formatEntity = (req, publicOnly=false) -> + obj = @toObject() + serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset', 'lastIP'] + delete obj[prop] for prop in serverProperties + candidateProperties = ['jobProfile', 'jobProfileApproved', 'jobProfileNotes'] + delete obj[prop] for prop in candidateProperties + includePrivates = not publicOnly and (req.user and (req.user.isAdmin() or req.user._id.equals(@_id))) + delete obj[prop] for prop in User.privateProperties unless includePrivates + return obj + +UserSchema.methods.isOnPremiumServer = -> + @get('country') in ['china', 'brazil'] + +UserSchema.methods.level = -> + xp = @get('points') or 0 + a = 5 + b = c = 100 + if xp > 0 then Math.floor(a * Math.log((1 / b) * (xp + c))) + 1 else 1 + +UserSchema.statics.saveActiveUser = (id, event, done=null) -> + # TODO: Disabling this until we know why our app servers CPU grows out of control. + return done?() + id = mongoose.Types.ObjectId id if _.isString id + @findById id, (err, user) -> + if err? + log.error err + else + user?.saveActiveUser event + done?() + +UserSchema.methods.saveActiveUser = (event, done=null) -> + # TODO: Disabling this until we know why our app servers CPU grows out of control. + return done?() + try + return done?() if @isAdmin() + userID = @get('_id') + + # Create if no active user entry for today + today = new Date() + minDate = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate())) + AnalyticsUsersActive.findOne({created: {$gte: minDate}, creator: mongoose.Types.ObjectId(userID)}).exec (err, activeUser) -> + if err? + log.error "saveActiveUser error retrieving active users: #{err}" + else if not activeUser + newActiveUser = new AnalyticsUsersActive() + newActiveUser.set 'creator', userID + newActiveUser.set 'event', event + newActiveUser.save (err) -> + log.error "Level session saveActiveUser error saving active user: #{err}" if err? + done?() + catch err + log.error err + done?() + +UserSchema.pre('save', (next) -> + Classroom = require './Classroom' + if @isTeacher() and not @wasTeacher + Classroom.update({members: @_id}, {$pull: {members: @_id}}, {multi: true}).exec (err, res) -> + console.log 'removed self from all classrooms as a member', err, res + if email = @get('email') + @set('emailLower', email.toLowerCase()) + if name = @get('name') + @set('nameLower', name.toLowerCase()) + pwd = @get('password') + if @get('password') + @set('passwordHash', User.hashPassword(pwd)) + @set('password', undefined) + if @get('email') and @get('anonymous') # a user registers + @register next + else + next() +) + +UserSchema.post 'save', (doc) -> + doc.newsSubsChanged = not _.isEqual(_.pick(doc.get('emails'), mail.NEWS_GROUPS), _.pick(doc.startingEmails, mail.NEWS_GROUPS)) + UserSchema.statics.updateServiceSettings(doc) + +UserSchema.post 'init', (doc) -> + doc.wasTeacher = doc.isTeacher() + doc.startingEmails = _.cloneDeep(doc.get('emails')) + +UserSchema.statics.hashPassword = (password) -> + password = password.toLowerCase() + shasum = crypto.createHash('sha512') + shasum.update(salt + password) + shasum.digest('hex') + +UserSchema.statics.privateProperties = [ + 'permissions', 'email', 'mailChimp', 'firstName', 'lastName', 'gender', 'facebookID', + 'gplusID', 'music', 'volume', 'aceConfig', 'employerAt', 'signedEmployerAgreement', + 'emailSubscriptions', 'emails', 'activity', 'stripe', 'stripeCustomerID', 'chinaVersion', 'country', + 'schoolName', 'ageRange', 'role' +] +UserSchema.statics.jsonSchema = jsonschema +UserSchema.statics.editableProperties = [ + 'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume', + 'firstName', 'lastName', 'gender', 'ageRange', 'facebookID', 'gplusID', 'emails', + 'testGroupNumber', 'music', 'hourOfCode', 'hourOfCodeComplete', 'preferredLanguage', + 'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile', 'savedEmployerFilterAlerts', + 'heroConfig', 'iosIdentifierForVendor', 'siteref', 'referrer', 'schoolName', 'role' +] + +UserSchema.statics.serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset', 'lastIP'] +UserSchema.statics.candidateProperties = [ 'jobProfile', 'jobProfileApproved', 'jobProfileNotes'] + +UserSchema.set('toObject', { + transform: (doc, ret, options) -> + req = options.req + return ret unless req # TODO: Make deleting properties the default, but the consequences are far reaching + publicOnly = options.publicOnly + delete ret[prop] for prop in User.serverProperties + includePrivates = not publicOnly and (req.user and (req.user.isAdmin() or req.user._id.equals(doc._id) or req.session.amActually is doc.id)) + if options.includedPrivates + excludedPrivates = _.reject User.privateProperties, (prop) -> + prop in options.includedPrivates + else + excludedPrivates = User.privateProperties + delete ret[prop] for prop in excludedPrivates unless includePrivates + delete ret[prop] for prop in User.candidateProperties + return ret +}) +UserSchema.plugin plugins.NamedPlugin + +module.exports = User = mongoose.model('User', UserSchema) + +AchievablePlugin = require '../plugins/achievements' +UserSchema.plugin(AchievablePlugin) diff --git a/server/user_code_problems/UserCodeProblem.coffee b/server/models/UserCodeProblem.coffee similarity index 100% rename from server/user_code_problems/UserCodeProblem.coffee rename to server/models/UserCodeProblem.coffee diff --git a/server/polls/UserPollsRecord.coffee b/server/models/UserPollsRecord.coffee similarity index 98% rename from server/polls/UserPollsRecord.coffee rename to server/models/UserPollsRecord.coffee index 0ca505aa0..d7716ee0e 100644 --- a/server/polls/UserPollsRecord.coffee +++ b/server/models/UserPollsRecord.coffee @@ -1,9 +1,9 @@ mongoose = require 'mongoose' plugins = require '../plugins/plugins' -jsonSchema = require '../../app/schemas/models/user-polls-record.schema' +jsonSchema = require '../../app/schemas/models/user-polls-record.schema.coffee' log = require 'winston' Poll = require './Poll' -User = require '../users/User' +User = require './User' UserPollsRecordSchema = new mongoose.Schema {}, {strict: false, minimize: false} diff --git a/server/patches/Patch.coffee b/server/patches/Patch.coffee deleted file mode 100644 index 712d7cdb3..000000000 --- a/server/patches/Patch.coffee +++ /dev/null @@ -1,79 +0,0 @@ -mongoose = require('mongoose') -deltas = require '../../app/core/deltas' -log = require 'winston' -{handlers} = require '../commons/mapping' -config = require '../../server_config' - -PatchSchema = new mongoose.Schema({status: String}, {strict: false,read:config.mongo.readpref}) - -PatchSchema.pre 'save', (next) -> - return next() unless @isNew # patch can't be altered after creation, so only need to check data once - target = @get('target') - targetID = target.id - Handler = require '../commons/Handler' - if not Handler.isID(targetID) - err = new Error('Invalid input.') - err.response = {message: 'isn\'t a MongoDB id.', property: 'target.id'} - err.code = 422 - return next(err) - - collection = target.collection - handler = require('../' + handlers[collection]) - handler.getDocumentForIdOrSlug targetID, (err, document) => - if err - err = new Error('Server error.') - err.response = {message: '', property: 'target.id'} - err.code = 500 - return next(err) - - if not document - err = new Error('Target of patch not found.') - err.response = {message: 'was not found.', property: 'target.id'} - err.code = 404 - return next(err) - - target.id = document.get('_id') - if handler.modelClass.schema.uses_coco_versions - target.original = document.get('original') - version = document.get('version') - target.version = _.pick document.get('version'), 'major', 'minor' - @set('target', target) - else - target.original = targetID - - patches = document.get('patches') or [] - patches = _.clone patches - patches.push @_id - document.set 'patches', patches, {strict: false} - @targetLoaded = document - document.save (err) -> next(err) - -PatchSchema.methods.isTranslationPatch = -> # Don't ever fat arrow bind this one - expanded = deltas.flattenDelta @get('delta') - _.some expanded, (delta) -> 'i18n' in delta.dataPath - -PatchSchema.methods.isMiscPatch = -> - expanded = deltas.flattenDelta @get('delta') - _.some expanded, (delta) -> 'i18n' not in delta.dataPath - -# Keep track of when a patch is pending and newly approved. -PatchSchema.path('status').set (newVal) -> - @set 'wasPending', @status is 'pending' and newVal isnt 'pending' - @set 'newlyAccepted', newVal is 'accepted' and not @get('newlyAccepted') # Only true on the first accept - newVal - -PatchSchema.methods.isNewlyAccepted = -> @get('newlyAccepted') -PatchSchema.methods.wasPending = -> @get 'wasPending' - -PatchSchema.pre 'save', (next) -> - User = require '../users/User' - userID = @get('creator').toHexString() - - if @get('status') is 'accepted' - User.incrementStat userID, 'stats.patchesContributed' # accepted patches - else if @get('status') is 'pending' - User.incrementStat userID, 'stats.patchesSubmitted' # submitted patches - - next() - -module.exports = mongoose.model('patch', PatchSchema) diff --git a/server/patches/patch_handler.coffee b/server/patches/patch_handler.coffee index 53bc3017c..b88f63a86 100644 --- a/server/patches/patch_handler.coffee +++ b/server/patches/patch_handler.coffee @@ -1,5 +1,5 @@ -Patch = require './Patch' -User = require '../users/User' +Patch = require './../models/Patch' +User = require '../models/User' Handler = require '../commons/Handler' schema = require '../../app/schemas/models/patch' {handlers} = require '../commons/mapping' diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee index b5e5837fe..6b9d52ed1 100644 --- a/server/payments/payment_handler.coffee +++ b/server/payments/payment_handler.coffee @@ -1,7 +1,7 @@ -Payment = require './Payment' -Prepaid = require '../prepaids/Prepaid' +Payment = require './../models/Payment' +Prepaid = require '../models/Prepaid' Product = require '../models/Product' -User = require '../users/User' +User = require '../models/User' Handler = require '../commons/Handler' {handlers} = require '../commons/mapping' mongoose = require 'mongoose' diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee index 4643d8a14..dacaa569e 100644 --- a/server/payments/subscription_handler.coffee +++ b/server/payments/subscription_handler.coffee @@ -9,8 +9,8 @@ config = require '../../server_config' Handler = require '../commons/Handler' slack = require '../slack' discountHandler = require './discount_handler' -Prepaid = require '../prepaids/Prepaid' -User = require '../users/User' +Prepaid = require '../models/Prepaid' +User = require '../models/User' {findStripeSubscription} = require '../lib/utils' {getSponsoredSubsAmount} = require '../../app/core/utils' StripeUtils = require '../lib/stripe_utils' diff --git a/server/plugins/achievements.coffee b/server/plugins/achievements.coffee index d9772a344..16ad24f77 100644 --- a/server/plugins/achievements.coffee +++ b/server/plugins/achievements.coffee @@ -1,5 +1,5 @@ mongoose = require 'mongoose' -EarnedAchievement = require '../achievements/EarnedAchievement' +EarnedAchievement = require '../models/EarnedAchievement' LocalMongo = require '../../app/lib/LocalMongo' util = require '../../app/core/utils' log = require 'winston' @@ -9,8 +9,8 @@ log = require 'winston' # TODO if this is still a common scenario I could implement a database hit after all, but only # on the condition that it's necessary and still not too frequent in occurrence AchievablePlugin = (schema, options) -> - User = require '../users/User' # Avoid mutual inclusion cycles - Achievement = require '../achievements/Achievement' + User = require '../models/User' # Avoid mutual inclusion cycles + Achievement = require '../models/Achievement' # Keep track the document before it's saved schema.post 'init', (doc) -> diff --git a/server/plugins/plugins.coffee b/server/plugins/plugins.coffee index db687f0e8..e9022af23 100644 --- a/server/plugins/plugins.coffee +++ b/server/plugins/plugins.coffee @@ -267,7 +267,7 @@ module.exports.VersionedPlugin = (schema) -> # Assume every save is a new version, hence an edit schema.pre 'save', (next) -> - User = require '../users/User' # Avoid mutual inclusion cycles + User = require '../models/User' # Avoid mutual inclusion cycles userID = @get('creator')?.toHexString() return next() unless userID? diff --git a/server/polls/poll_handler.coffee b/server/polls/poll_handler.coffee index 0245e2e92..adbc2f0df 100644 --- a/server/polls/poll_handler.coffee +++ b/server/polls/poll_handler.coffee @@ -1,5 +1,5 @@ -Poll = require './Poll' -UserPollsRecord = require './UserPollsRecord' +Poll = require './../models/Poll' +UserPollsRecord = require './../models/UserPollsRecord' Handler = require '../commons/Handler' async = require 'async' mongoose = require 'mongoose' diff --git a/server/polls/user_polls_record_handler.coffee b/server/polls/user_polls_record_handler.coffee index 36b81298a..2a9ba3744 100644 --- a/server/polls/user_polls_record_handler.coffee +++ b/server/polls/user_polls_record_handler.coffee @@ -1,4 +1,4 @@ -UserPollsRecord = require './UserPollsRecord' +UserPollsRecord = require './../models/UserPollsRecord' Handler = require '../commons/Handler' async = require 'async' mongoose = require 'mongoose' diff --git a/server/prepaids/prepaid_handler.coffee b/server/prepaids/prepaid_handler.coffee index 147777af4..77cab72a6 100644 --- a/server/prepaids/prepaid_handler.coffee +++ b/server/prepaids/prepaid_handler.coffee @@ -1,8 +1,8 @@ Course = require '../models/Course' Handler = require '../commons/Handler' slack = require '../slack' -Prepaid = require './Prepaid' -User = require '../users/User' +Prepaid = require './../models/Prepaid' +User = require '../models/User' StripeUtils = require '../lib/stripe_utils' utils = require '../../app/core/utils' mongoose = require 'mongoose' diff --git a/server/purchases/purchase_handler.coffee b/server/purchases/purchase_handler.coffee index 220252f05..3b9238f42 100644 --- a/server/purchases/purchase_handler.coffee +++ b/server/purchases/purchase_handler.coffee @@ -1,5 +1,5 @@ -Purchase = require './Purchase' -User = require '../users/User' +Purchase = require './../models/Purchase' +User = require '../models/User' Handler = require '../commons/Handler' {handlers} = require '../commons/mapping' mongoose = require 'mongoose' diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index c36bf747b..d2cde90b5 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -6,10 +6,10 @@ errors = require '../commons/errors' aws = require 'aws-sdk' db = require './../routes/db' queues = require '../commons/queue' -LevelSession = require '../levels/sessions/LevelSession' -Level = require '../levels/Level' -User = require '../users/User' -TaskLog = require './scoring/ScoringTask' +LevelSession = require '../models/LevelSession' +Level = require '../models/Level' +User = require '../models/User' +TaskLog = require './../models/ScoringTask' scoringUtils = require './scoring/scoringUtils' getTwoGames = require './scoring/getTwoGames' recordTwoGames = require './scoring/recordTwoGames' diff --git a/server/queues/scoring/createNewTask.coffee b/server/queues/scoring/createNewTask.coffee index 0318e45a3..d2a6e90bc 100644 --- a/server/queues/scoring/createNewTask.coffee +++ b/server/queues/scoring/createNewTask.coffee @@ -2,8 +2,8 @@ log = require 'winston' async = require 'async' errors = require '../../commons/errors' scoringUtils = require './scoringUtils' -LevelSession = require '../../levels/sessions/LevelSession' -Level = require '../../levels/Level' +LevelSession = require '../../models/LevelSession' +Level = require '../../models/Level' module.exports = createNewTask = (req, res) -> requestSessionID = req.body.session diff --git a/server/queues/scoring/dispatchTaskToConsumer.coffee b/server/queues/scoring/dispatchTaskToConsumer.coffee index 53af54c05..7785172f4 100644 --- a/server/queues/scoring/dispatchTaskToConsumer.coffee +++ b/server/queues/scoring/dispatchTaskToConsumer.coffee @@ -2,8 +2,8 @@ log = require 'winston' async = require 'async' errors = require '../../commons/errors' scoringUtils = require './scoringUtils' -LevelSession = require '../../levels/sessions/LevelSession' -TaskLog = require './ScoringTask' +LevelSession = require '../../models/LevelSession' +TaskLog = require './../../models/ScoringTask' module.exports = dispatchTaskToConsumer = (req, res) -> yetiGuru = {} diff --git a/server/queues/scoring/getTwoGames.coffee b/server/queues/scoring/getTwoGames.coffee index 35cce9486..73e655356 100644 --- a/server/queues/scoring/getTwoGames.coffee +++ b/server/queues/scoring/getTwoGames.coffee @@ -2,7 +2,7 @@ log = require 'winston' async = require 'async' errors = require '../../commons/errors' scoringUtils = require './scoringUtils' -LevelSession = require '../../levels/sessions/LevelSession' +LevelSession = require '../../models/LevelSession' Mandate = require '../../models/Mandate' module.exports = getTwoGames = (req, res) -> diff --git a/server/queues/scoring/processTaskResult.coffee b/server/queues/scoring/processTaskResult.coffee index 9d9b232f7..2ee8dfe5f 100644 --- a/server/queues/scoring/processTaskResult.coffee +++ b/server/queues/scoring/processTaskResult.coffee @@ -2,8 +2,8 @@ log = require 'winston' async = require 'async' errors = require '../../commons/errors' scoringUtils = require './scoringUtils' -LevelSession = require '../../levels/sessions/LevelSession' -TaskLog = require './ScoringTask' +LevelSession = require '../../models/LevelSession' +TaskLog = require './../../models/ScoringTask' module.exports = processTaskResult = (req, res) -> return if scoringUtils.simulatorIsTooOld req, res diff --git a/server/queues/scoring/recordTwoGames.coffee b/server/queues/scoring/recordTwoGames.coffee index fe9702dca..780af63d1 100644 --- a/server/queues/scoring/recordTwoGames.coffee +++ b/server/queues/scoring/recordTwoGames.coffee @@ -2,7 +2,7 @@ log = require 'winston' async = require 'async' errors = require '../../commons/errors' scoringUtils = require './scoringUtils' -LevelSession = require '../../levels/sessions/LevelSession' +LevelSession = require '../../models/LevelSession' module.exports = recordTwoGames = (req, res) -> sessions = req.body.sessions diff --git a/server/queues/scoring/scoringUtils.coffee b/server/queues/scoring/scoringUtils.coffee index 1324feafd..049ea37f8 100644 --- a/server/queues/scoring/scoringUtils.coffee +++ b/server/queues/scoring/scoringUtils.coffee @@ -1,8 +1,8 @@ log = require 'winston' async = require 'async' bayes = new (require 'bayesian-battle')() -LevelSession = require '../../levels/sessions/LevelSession' -User = require '../../users/User' +LevelSession = require '../../models/LevelSession' +User = require '../../models/User' perfmon = require '../../commons/perfmon' SIMULATOR_VERSION = 3 diff --git a/server/routes/auth.coffee b/server/routes/auth.coffee index ca3eb3d36..53d052928 100644 --- a/server/routes/auth.coffee +++ b/server/routes/auth.coffee @@ -1,8 +1,8 @@ authentication = require 'passport' LocalStrategy = require('passport-local').Strategy -User = require '../users/User' +User = require '../models/User' UserHandler = require '../users/user_handler' -LevelSession = require '../levels/sessions/LevelSession' +LevelSession = require '../models/LevelSession' config = require '../../server_config' errors = require '../commons/errors' languages = require '../routes/languages' diff --git a/server/routes/contact.coffee b/server/routes/contact.coffee index 2056af9ef..189f0774a 100644 --- a/server/routes/contact.coffee +++ b/server/routes/contact.coffee @@ -1,9 +1,9 @@ config = require '../../server_config' log = require 'winston' -User = require '../users/User' +User = require '../models/User' sendwithus = require '../sendwithus' async = require 'async' -LevelSession = require '../levels/sessions/LevelSession' +LevelSession = require '../models/LevelSession' moment = require 'moment' module.exports.setup = (app) -> diff --git a/server/routes/github.coffee b/server/routes/github.coffee index cff00ba0d..ec6a4b71e 100644 --- a/server/routes/github.coffee +++ b/server/routes/github.coffee @@ -3,7 +3,7 @@ errors = require '../commons/errors' mongoose = require 'mongoose' config = require('../../server_config') request = require 'request' -User = require '../users/User' +User = require '../models/User' module.exports.setup = (app) -> app.get '/github/auth_callback', (req, res) -> diff --git a/server/routes/index.coffee b/server/routes/index.coffee index f228c3bd4..f7bb1d68e 100644 --- a/server/routes/index.coffee +++ b/server/routes/index.coffee @@ -49,7 +49,7 @@ module.exports.setup = (app) -> app.get '/healthcheck', (req, res) -> try async = require 'async' - User = require '../users/User' + User = require '../models/User' async.waterfall [ (callback) -> User.find({}).limit(1).exec(callback) diff --git a/server/routes/mail.coffee b/server/routes/mail.coffee index d222843e0..fe2edbdbc 100644 --- a/server/routes/mail.coffee +++ b/server/routes/mail.coffee @@ -1,12 +1,12 @@ mail = require '../commons/mail' -MailSent = require '../mail/sent/MailSent' +MailSent = require '../models/MailSent' UserRemark = require '../users/remarks/UserRemark' -User = require '../users/User' +User = require '../models/User' async = require 'async' errors = require '../commons/errors' config = require '../../server_config' -LevelSession = require '../levels/sessions/LevelSession' -Level = require '../levels/Level' +LevelSession = require '../models/LevelSession' +Level = require '../models/Level' log = require 'winston' sendwithus = require '../sendwithus' if config.isProduction and config.redis.host isnt 'localhost' diff --git a/server/routes/stripe.coffee b/server/routes/stripe.coffee index 1541ca672..7b15882df 100644 --- a/server/routes/stripe.coffee +++ b/server/routes/stripe.coffee @@ -1,8 +1,8 @@ async = require 'async' config = require '../../server_config' stripe = require('stripe')(config.stripe.secretKey) -User = require '../users/User' -Payment = require '../payments/Payment' +User = require '../models/User' +Payment = require '../models/Payment' errors = require '../commons/errors' mongoose = require 'mongoose' utils = require '../../app/core/utils' diff --git a/server/user_code_problems/user_code_problem_handler.coffee b/server/user_code_problems/user_code_problem_handler.coffee index 38d7a5e71..e60adf0ee 100644 --- a/server/user_code_problems/user_code_problem_handler.coffee +++ b/server/user_code_problems/user_code_problem_handler.coffee @@ -1,4 +1,4 @@ -UserCodeProblem = require './UserCodeProblem' +UserCodeProblem = require './../models/UserCodeProblem' Handler = require '../commons/Handler' utils = require '../lib/utils' diff --git a/server/users/User.coffee b/server/users/User.coffee deleted file mode 100644 index a5f0cdb76..000000000 --- a/server/users/User.coffee +++ /dev/null @@ -1,382 +0,0 @@ -mongoose = require 'mongoose' -jsonschema = require '../../app/schemas/models/user' -crypto = require 'crypto' -{salt, isProduction} = require '../../server_config' -mail = require '../commons/mail' -log = require 'winston' -plugins = require '../plugins/plugins' -AnalyticsUsersActive = require '../analytics/AnalyticsUsersActive' - -config = require '../../server_config' -stripe = require('stripe')(config.stripe.secretKey) - -sendwithus = require '../sendwithus' -delighted = require '../delighted' - -UserSchema = new mongoose.Schema({ - dateCreated: - type: Date - 'default': Date.now -}, {strict: false}) - -UserSchema.index({'dateCreated': 1}) -UserSchema.index({'emailLower': 1}, {unique: true, sparse: true, name: 'emailLower_1'}) -UserSchema.index({'facebookID': 1}, {sparse: true}) -UserSchema.index({'gplusID': 1}, {sparse: true}) -UserSchema.index({'iosIdentifierForVendor': 1}, {name: 'iOS identifier for vendor', sparse: true, unique: true}) -UserSchema.index({'mailChimp.leid': 1}, {sparse: true}) -UserSchema.index({'nameLower': 1}, {sparse: true, name: 'nameLower_1'}) -UserSchema.index({'simulatedBy': 1}) -UserSchema.index({'slug': 1}, {name: 'slug index', sparse: true, unique: true}) -UserSchema.index({'stripe.subscriptionID': 1}, {unique: true, sparse: true}) -UserSchema.index({'siteref': 1}, {name: 'siteref index', sparse: true}) -UserSchema.index({'schoolName': 1}, {name: 'schoolName index', sparse: true}) -UserSchema.index({'country': 1}, {name: 'country index', sparse: true}) -UserSchema.index({'role': 1}, {name: 'role index', sparse: true}) - -UserSchema.post('init', -> - @set('anonymous', false) if @get('email') -) - -UserSchema.methods.isInGodMode = -> - p = @get('permissions') - return p and 'godmode' in p - -UserSchema.methods.isAdmin = -> - p = @get('permissions') - return p and 'admin' in p - -UserSchema.methods.hasPermission = (neededPermissions) -> - permissions = @get('permissions') or [] - if _.contains(permissions, 'admin') - return true - if _.isString(neededPermissions) - neededPermissions = [neededPermissions] - return _.size(_.intersection(permissions, neededPermissions)) - -UserSchema.methods.isArtisan = -> - p = @get('permissions') - return p and 'artisan' in p - -UserSchema.methods.isAnonymous = -> - @get 'anonymous' - -UserSchema.statics.teacherRoles = ['teacher', 'technology coordinator', 'advisor', 'principal', 'superintendent', 'parent'] - -UserSchema.methods.isTeacher = -> - return @get('role') in User.teacherRoles - -UserSchema.methods.getUserInfo = -> - id: @get('_id') - email: if @get('anonymous') then 'Unregistered User' else @get('email') - -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' - artisanNews: 'level_creator' - archmageNews: 'developer' - scribeNews: 'article_editor' - diplomatNews: 'translator' - ambassadorNews: 'support' - anyNotes: 'notification' - teacherNews: 'teacher' - -UserSchema.methods.setEmailSubscription = (newName, enabled) -> - oldSubs = _.clone @get('emailSubscriptions') - if oldSubs and oldName = emailNameMap[newName] - oldSubs = (s for s in oldSubs when s isnt oldName) - oldSubs.push(oldName) if enabled - @set('emailSubscriptions', oldSubs) - - newSubs = _.clone(@get('emails') or _.cloneDeep(jsonschema.properties.emails.default)) - newSubs[newName] ?= {} - newSubs[newName].enabled = enabled - @set('emails', newSubs) - @newsSubsChanged = true if newName in mail.NEWS_GROUPS - -UserSchema.methods.gems = -> - gemsEarned = @get('earned')?.gems ? 0 - gemsEarned = gemsEarned + 100000 if @isInGodMode() - gemsPurchased = @get('purchased')?.gems ? 0 - gemsSpent = @get('spent') ? 0 - gemsEarned + gemsPurchased - gemsSpent - -UserSchema.methods.isEmailSubscriptionEnabled = (newName) -> - emails = @get 'emails' - if not emails - oldSubs = @get('emailSubscriptions') - oldName = emailNameMap[newName] - return oldName and oldName in oldSubs if oldSubs - emails ?= {} - _.defaults emails, _.cloneDeep(jsonschema.properties.emails.default) - return emails[newName]?.enabled - -UserSchema.statics.updateServiceSettings = (doc, callback) -> - return callback?() unless isProduction or GLOBAL.testing - return callback?() if doc.updatedMailChimp - return callback?() unless doc.get('email') - existingProps = doc.get('mailChimp') - emailChanged = (not existingProps) or existingProps?.email isnt doc.get('email') - - if emailChanged and customerID = doc.get('stripe')?.customerID - unless stripe?.customers - console.error('Oh my god, Stripe is not imported correctly-how could we have done this (again)?') - stripe?.customers?.update customerID, {email:doc.get('email')}, (err, customer) -> - console.error('Error updating stripe customer...', err) if err - - return callback?() unless emailChanged or doc.newsSubsChanged - - newGroups = [] - for [mailchimpEmailGroup, emailGroup] in _.zip(mail.MAILCHIMP_GROUPS, mail.NEWS_GROUPS) - newGroups.push(mailchimpEmailGroup) if doc.isEmailSubscriptionEnabled(emailGroup) - - if (not existingProps) and newGroups.length is 0 - return callback?() # don't add totally unsubscribed people to the list - - params = {} - params.id = mail.MAILCHIMP_LIST_ID - params.email = if existingProps then {leid: existingProps.leid} else {email: doc.get('email')} - params.merge_vars = { - groupings: [{id: mail.MAILCHIMP_GROUP_ID, groups: newGroups}] - 'new-email': doc.get('email') - } - params.update_existing = true - - onSuccess = (data) -> - data.email = doc.get('email') # Make sure that we don't spam opt-in emails even if MailChimp doesn't update the email it gets in this object until they have confirmed. - doc.set('mailChimp', data) - doc.updatedMailChimp = true - doc.save() - callback?() - - onFailure = (error) -> - log.error 'failed to subscribe', error, callback? - doc.updatedMailChimp = true - callback?() - - mc?.lists.subscribe params, onSuccess, onFailure - -UserSchema.statics.statsMapping = - edits: - article: 'stats.articleEdits' - level: 'stats.levelEdits' - 'level.component': 'stats.levelComponentEdits' - 'level.system': 'stats.levelSystemEdits' - 'thang.type': 'stats.thangTypeEdits' - 'Achievement': 'stats.achievementEdits' - 'campaign': 'stats.campaignEdits' - 'poll': 'stats.pollEdits' - translations: - article: 'stats.articleTranslationPatches' - level: 'stats.levelTranslationPatches' - 'level.component': 'stats.levelComponentTranslationPatches' - 'level.system': 'stats.levelSystemTranslationPatches' - 'thang.type': 'stats.thangTypeTranslationPatches' - 'Achievement': 'stats.achievementTranslationPatches' - 'campaign': 'stats.campaignTranslationPatches' - 'poll': 'stats.pollTranslationPatches' - misc: - article: 'stats.articleMiscPatches' - level: 'stats.levelMiscPatches' - 'level.component': 'stats.levelComponentMiscPatches' - 'level.system': 'stats.levelSystemMiscPatches' - 'thang.type': 'stats.thangTypeMiscPatches' - 'Achievement': 'stats.achievementMiscPatches' - 'campaign': 'stats.campaignMiscPatches' - 'poll': 'stats.pollMiscPatches' - -UserSchema.statics.incrementStat = (id, statName, done, inc=1) -> - id = mongoose.Types.ObjectId id if _.isString id - @findById id, (err, user) -> - log.error err if err? - err = new Error "Could't find user with id '#{id}'" unless user or err - return done() if err? - user.incrementStat statName, done, inc - -UserSchema.methods.incrementStat = (statName, done, inc=1) -> - if /^concepts\./.test statName - # Concept stats are nested a level deeper. - concepts = @get('concepts') or {} - concept = statName.split('.')[1] - concepts[concept] = (concepts[concept] or 0) + inc - @set 'concepts', concepts - else - @set statName, (@get(statName) or 0) + inc - @save (err) -> done?(err) - -UserSchema.statics.unconflictName = unconflictName = (name, done) -> - User.findOne {slug: _.str.slugify(name)}, (err, otherUser) -> - return done err if err? - return done null, name unless otherUser - suffix = _.random(0, 9) + '' - unconflictName name + suffix, done - -UserSchema.methods.register = (done) -> - @set('anonymous', false) - if (name = @get 'name')? and name isnt '' - unconflictName name, (err, uniqueName) => - return done err if err - @set 'name', uniqueName - done() - else done() - if @isEmailSubscriptionEnabled 'generalNews' - data = - email_id: sendwithus.templates.welcome_email - recipient: - address: @get 'email' - sendwithus.api.send data, (err, result) -> - log.error "sendwithus post-save error: #{err}, result: #{result}" if err - delighted.addDelightedUser @ - @saveActiveUser 'register' - -UserSchema.methods.hasSubscription = -> - return false unless stripeObject = @get('stripe') - return true if stripeObject.sponsorID - return true if stripeObject.subscriptionID - return true if stripeObject.free is true - return true if _.isString(stripeObject.free) and new Date() < new Date(stripeObject.free) - -UserSchema.methods.isPremium = -> - return true if @isInGodMode() - return true if @isAdmin() - return true if @hasSubscription() - return false - -UserSchema.methods.formatEntity = (req, publicOnly=false) -> - obj = @toObject() - serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset', 'lastIP'] - delete obj[prop] for prop in serverProperties - candidateProperties = ['jobProfile', 'jobProfileApproved', 'jobProfileNotes'] - delete obj[prop] for prop in candidateProperties - includePrivates = not publicOnly and (req.user and (req.user.isAdmin() or req.user._id.equals(@_id))) - delete obj[prop] for prop in User.privateProperties unless includePrivates - return obj - -UserSchema.methods.isOnPremiumServer = -> - @get('country') in ['china', 'brazil'] - -UserSchema.methods.level = -> - xp = @get('points') or 0 - a = 5 - b = c = 100 - if xp > 0 then Math.floor(a * Math.log((1 / b) * (xp + c))) + 1 else 1 - -UserSchema.statics.saveActiveUser = (id, event, done=null) -> - # TODO: Disabling this until we know why our app servers CPU grows out of control. - return done?() - id = mongoose.Types.ObjectId id if _.isString id - @findById id, (err, user) -> - if err? - log.error err - else - user?.saveActiveUser event - done?() - -UserSchema.methods.saveActiveUser = (event, done=null) -> - # TODO: Disabling this until we know why our app servers CPU grows out of control. - return done?() - try - return done?() if @isAdmin() - userID = @get('_id') - - # Create if no active user entry for today - today = new Date() - minDate = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate())) - AnalyticsUsersActive.findOne({created: {$gte: minDate}, creator: mongoose.Types.ObjectId(userID)}).exec (err, activeUser) -> - if err? - log.error "saveActiveUser error retrieving active users: #{err}" - else if not activeUser - newActiveUser = new AnalyticsUsersActive() - newActiveUser.set 'creator', userID - newActiveUser.set 'event', event - newActiveUser.save (err) -> - log.error "Level session saveActiveUser error saving active user: #{err}" if err? - done?() - catch err - log.error err - done?() - -UserSchema.pre('save', (next) -> - Classroom = require '../classrooms/Classroom' - if @isTeacher() and not @wasTeacher - Classroom.update({members: @_id}, {$pull: {members: @_id}}, {multi: true}).exec (err, res) -> - console.log 'removed self from all classrooms as a member', err, res - if email = @get('email') - @set('emailLower', email.toLowerCase()) - if name = @get('name') - @set('nameLower', name.toLowerCase()) - pwd = @get('password') - if @get('password') - @set('passwordHash', User.hashPassword(pwd)) - @set('password', undefined) - if @get('email') and @get('anonymous') # a user registers - @register next - else - next() -) - -UserSchema.post 'save', (doc) -> - doc.newsSubsChanged = not _.isEqual(_.pick(doc.get('emails'), mail.NEWS_GROUPS), _.pick(doc.startingEmails, mail.NEWS_GROUPS)) - UserSchema.statics.updateServiceSettings(doc) - -UserSchema.post 'init', (doc) -> - doc.wasTeacher = doc.isTeacher() - doc.startingEmails = _.cloneDeep(doc.get('emails')) - -UserSchema.statics.hashPassword = (password) -> - password = password.toLowerCase() - shasum = crypto.createHash('sha512') - shasum.update(salt + password) - shasum.digest('hex') - -UserSchema.statics.privateProperties = [ - 'permissions', 'email', 'mailChimp', 'firstName', 'lastName', 'gender', 'facebookID', - 'gplusID', 'music', 'volume', 'aceConfig', 'employerAt', 'signedEmployerAgreement', - 'emailSubscriptions', 'emails', 'activity', 'stripe', 'stripeCustomerID', 'chinaVersion', 'country', - 'schoolName', 'ageRange', 'role' -] -UserSchema.statics.jsonSchema = jsonschema -UserSchema.statics.editableProperties = [ - 'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume', - 'firstName', 'lastName', 'gender', 'ageRange', 'facebookID', 'gplusID', 'emails', - 'testGroupNumber', 'music', 'hourOfCode', 'hourOfCodeComplete', 'preferredLanguage', - 'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile', 'savedEmployerFilterAlerts', - 'heroConfig', 'iosIdentifierForVendor', 'siteref', 'referrer', 'schoolName', 'role' -] - -UserSchema.statics.serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset', 'lastIP'] -UserSchema.statics.candidateProperties = [ 'jobProfile', 'jobProfileApproved', 'jobProfileNotes'] - -UserSchema.set('toObject', { - transform: (doc, ret, options) -> - req = options.req - return ret unless req # TODO: Make deleting properties the default, but the consequences are far reaching - publicOnly = options.publicOnly - delete ret[prop] for prop in User.serverProperties - includePrivates = not publicOnly and (req.user and (req.user.isAdmin() or req.user._id.equals(doc._id) or req.session.amActually is doc.id)) - if options.includedPrivates - excludedPrivates = _.reject User.privateProperties, (prop) -> - prop in options.includedPrivates - else - excludedPrivates = User.privateProperties - delete ret[prop] for prop in excludedPrivates unless includePrivates - delete ret[prop] for prop in User.candidateProperties - return ret -}) -UserSchema.plugin plugins.NamedPlugin - -module.exports = User = mongoose.model('User', UserSchema) - -AchievablePlugin = require '../plugins/achievements' -UserSchema.plugin(AchievablePlugin) diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index e07e663a0..220df41ea 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -1,7 +1,7 @@ schema = require '../../app/schemas/models/user' crypto = require 'crypto' request = require 'request' -User = require './User' +User = require './../models/User' Handler = require '../commons/Handler' mongoose = require 'mongoose' config = require '../../server_config' @@ -9,23 +9,23 @@ errors = require '../commons/errors' async = require 'async' log = require 'winston' moment = require 'moment' -AnalyticsLogEvent = require '../analytics/AnalyticsLogEvent' -Clan = require '../clans/Clan' -CourseInstance = require '../courses/CourseInstance' -LevelSession = require '../levels/sessions/LevelSession' +AnalyticsLogEvent = require '../models/AnalyticsLogEvent' +Clan = require '../models/Clan' +CourseInstance = require '../models/CourseInstance' +LevelSession = require '../models/LevelSession' LevelSessionHandler = require '../levels/sessions/level_session_handler' -Payment = require '../payments/Payment' +Payment = require '../models/Payment' SubscriptionHandler = require '../payments/subscription_handler' DiscountHandler = require '../payments/discount_handler' -EarnedAchievement = require '../achievements/EarnedAchievement' +EarnedAchievement = require '../models/EarnedAchievement' UserRemark = require './remarks/UserRemark' {findStripeSubscription} = require '../lib/utils' {isID} = require '../lib/utils' slack = require '../slack' sendwithus = require '../sendwithus' -Prepaid = require '../prepaids/Prepaid' -UserPollsRecord = require '../polls/UserPollsRecord' -EarnedAchievement = require '../achievements/EarnedAchievement' +Prepaid = require '../models/Prepaid' +UserPollsRecord = require '../models/UserPollsRecord' +EarnedAchievement = require '../models/EarnedAchievement' serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset', 'lastIP'] candidateProperties = [ @@ -792,7 +792,7 @@ UserHandler = class UserHandler extends Handler expanded = deltas.flattenDelta obj.get 'delta' _.some expanded, (delta) -> 'i18n' in delta.dataPath - Patch = require '../patches/Patch' + Patch = require '../models/Patch' # filter is passed a mongoose document and should return a boolean, # determining whether the patch should be counted countPatchesByUsersInMemory = (query, filter, statName, done) -> @@ -836,7 +836,7 @@ UserHandler = class UserHandler extends Handler updateUser user, count, doneWithUser countPatchesByUsers = (query, statName, done) -> - Patch = require '../patches/Patch' + Patch = require '../models/Patch' userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false @@ -870,7 +870,7 @@ UserHandler = class UserHandler extends Handler statRecalculators: gamesCompleted: (done) -> - LevelSession = require '../levels/sessions/LevelSession' + LevelSession = require '../models/LevelSession' userStream = User.find({anonymous: false}).sort('_id').stream() streamFinished = false @@ -899,23 +899,23 @@ UserHandler = class UserHandler extends Handler User.findByIdAndUpdate user.get('_id'), update, doneWithUser articleEdits: (done) -> - Article = require '../articles/Article' + Article = require '../models/Article' countEdits Article, done levelEdits: (done) -> - Level = require '../levels/Level' + Level = require '../models/Level' countEdits Level, done levelComponentEdits: (done) -> - LevelComponent = require '../levels/components/LevelComponent' + LevelComponent = require '../models/LevelComponent' countEdits LevelComponent, done levelSystemEdits: (done) -> - LevelSystem = require '../levels/systems/LevelSystem' + LevelSystem = require '../models/LevelSystem' countEdits LevelSystem, done thangTypeEdits: (done) -> - ThangType = require '../levels/thangs/ThangType' + ThangType = require '../models/ThangType' countEdits ThangType, done patchesContributed: (done) -> diff --git a/spec/helpers/helper.js b/spec/helpers/helper.js index 9303e3bef..0f8a56f49 100644 --- a/spec/helpers/helper.js +++ b/spec/helpers/helper.js @@ -37,6 +37,7 @@ if (database.generateMongoConnectionString() !== dbString) { } jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 120; // for long Stripe tests +require('../server/common'); // Make sure global testing functions are set up var initialized = false; beforeEach(function(done) { @@ -53,7 +54,7 @@ beforeEach(function(done) { }, function(cb) { // 5. Check actual database - var User = require('../../server/users/User'); + var User = require('../../server/models/User'); User.find({}).count(function(err, count) { // For this to serve as a line of defense against testing with the // production DB, tests must be run with @@ -77,6 +78,7 @@ beforeEach(function(done) { }, function(cb) { // Initialize products + request = require('../server/request'); request.get(getURL('/db/products'), function(err, res, body) { expect(err).toBe(null); expect(res.statusCode).toBe(200); diff --git a/spec/server/common.coffee b/spec/server/common.coffee index e71f818be..3ef743b0b 100644 --- a/spec/server/common.coffee +++ b/spec/server/common.coffee @@ -5,40 +5,13 @@ console.log 'IT BEGINS' if process.env.COCO_MONGO_HOST throw Error('Tests may not run with production environment') -GLOBAL._ = require 'lodash' -_.str = require 'underscore.string' -_.mixin(_.str.exports()) -GLOBAL.mongoose = require 'mongoose' # TODO: Remove, otherwise it hides when the server is missing a mongoose require +require '../../server' # make lodash globally available +mongoose = require 'mongoose' path = require 'path' GLOBAL.testing = true GLOBAL.tv4 = require 'tv4' # required for TreemaUtils to work -models_path = [ - '../../server/analytics/AnalyticsUsersActive' - '../../server/articles/Article' - '../../server/campaigns/Campaign' - '../../server/clans/Clan' - '../../server/classrooms/Classroom' - '../../server/models/Course' - '../../server/courses/CourseInstance' - '../../server/levels/Level' - '../../server/levels/components/LevelComponent' - '../../server/levels/systems/LevelSystem' - '../../server/levels/sessions/LevelSession' - '../../server/levels/thangs/LevelThangType' - '../../server/users/User' - '../../server/patches/Patch' - '../../server/achievements/Achievement' - '../../server/achievements/EarnedAchievement' - '../../server/payments/Payment' - '../../server/prepaids/Prepaid' - '../../server/models/TrialRequest' -] - -for m in models_path - model = path.basename(m) - #console.log('model=' + model) - GLOBAL[model] = require m +User = require '../../server/models/User' async = require 'async' @@ -70,9 +43,6 @@ GLOBAL.saveModels = (models, done) -> GLOBAL.simplePermissions = [target: 'public', access: 'owner'] GLOBAL.ObjectId = mongoose.Types.ObjectId -GLOBAL.request = require('request').defaults({jar: true}) -Promise = require 'bluebird' -Promise.promisifyAll(request, {multiArgs: true}) GLOBAL.unittest = {} unittest.users = unittest.users or {} diff --git a/spec/server/functional/achievement.spec.coffee b/spec/server/functional/achievement.spec.coffee index 9318678b2..31523ed78 100644 --- a/spec/server/functional/achievement.spec.coffee +++ b/spec/server/functional/achievement.spec.coffee @@ -38,6 +38,12 @@ diminishing = url = getURL('/db/achievement') +Achievement = require '../../../server/models/Achievement' +EarnedAchievement = require '../../../server/models/EarnedAchievement' +LevelSession = require '../../../server/models/LevelSession' +User = require '../../../server/models/User' +request = require '../request' + describe 'Achievement', -> allowHeader = 'GET, POST, PUT, PATCH, DELETE' diff --git a/spec/server/functional/admin.spec.coffee b/spec/server/functional/admin.spec.coffee index 96be3ef77..f52ba10ce 100644 --- a/spec/server/functional/admin.spec.coffee +++ b/spec/server/functional/admin.spec.coffee @@ -1,4 +1,5 @@ common = require '../common' +request = require '../request' describe 'recalculate statistics', -> url = getURL '/admin/user/recalculate/' diff --git a/spec/server/functional/article.spec.coffee b/spec/server/functional/article.spec.coffee index fed443726..3d634dedc 100644 --- a/spec/server/functional/article.spec.coffee +++ b/spec/server/functional/article.spec.coffee @@ -2,7 +2,10 @@ require '../common' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' +request = require '../request' requestAsync = Promise.promisify(request, {multiArgs: true}) +Article = require '../../../server/models/Article' +User = require '../../../server/models/User' describe 'GET /db/article', -> articleData1 = { name: 'Article 1', body: 'Article 1 body cow', i18nCoverage: [] } diff --git a/spec/server/functional/auth.spec.coffee b/spec/server/functional/auth.spec.coffee index bf59aa0c5..82e8ab1e5 100644 --- a/spec/server/functional/auth.spec.coffee +++ b/spec/server/functional/auth.spec.coffee @@ -1,9 +1,10 @@ require '../common' -User = require '../../../server/users/User' +User = require '../../../server/models/User' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' nock = require 'nock' +request = require '../request' urlLogin = getURL('/auth/login') urlReset = getURL('/auth/reset') diff --git a/spec/server/functional/campaign_handler.spec.coffee b/spec/server/functional/campaign_handler.spec.coffee index 35a341e86..8949eec07 100644 --- a/spec/server/functional/campaign_handler.spec.coffee +++ b/spec/server/functional/campaign_handler.spec.coffee @@ -29,6 +29,11 @@ achievementURL = getURL('/db/achievement') campaignURL = getURL('/db/campaign') campaignSchema = require '../../../app/schemas/models/campaign.schema' campaignLevelProperties = _.keys(campaignSchema.properties.levels.additionalProperties.properties) +Achievement = require '../../../server/models/Achievement' +Campaign = require '../../../server/models/Campaign' +Level = require '../../../server/models/Level' +User = require '../../../server/models/User' +request = require '../request' describe '/db/campaign', -> it 'prepares the db first', (done) -> diff --git a/spec/server/functional/campaigns.spec.coffee b/spec/server/functional/campaigns.spec.coffee index b27c1ea7e..3255d9bfc 100644 --- a/spec/server/functional/campaigns.spec.coffee +++ b/spec/server/functional/campaigns.spec.coffee @@ -1,14 +1,16 @@ config = require '../../../server_config' require '../common' clientUtils = require '../../../app/core/utils' # Must come after require /common -mongoose = require 'mongoose' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' +request = require '../request' requestAsync = Promise.promisify(request, {multiArgs: true}) campaignURL = getURL('/db/campaign') +Campaign = require '../../../server/models/Campaign' + describe '/db/campaign', -> beforeEach utils.wrap (done) -> diff --git a/spec/server/functional/clan.spec.coffee b/spec/server/functional/clan.spec.coffee index b608da92a..d4c4149b2 100644 --- a/spec/server/functional/clan.spec.coffee +++ b/spec/server/functional/clan.spec.coffee @@ -1,7 +1,9 @@ config = require '../../../server_config' require '../common' utils = require '../../../app/core/utils' # Must come after require /common -mongoose = require 'mongoose' +Clan = require '../../../server/models/Clan' +User = require '../../../server/models/User' +request = require '../request' describe 'Clans', -> clanURL = getURL('/db/clan') diff --git a/spec/server/functional/classrooms.spec.coffee b/spec/server/functional/classrooms.spec.coffee index 32a9a3aa3..117b83c78 100644 --- a/spec/server/functional/classrooms.spec.coffee +++ b/spec/server/functional/classrooms.spec.coffee @@ -1,11 +1,15 @@ config = require '../../../server_config' require '../common' clientUtils = require '../../../app/core/utils' # Must come after require /common -mongoose = require 'mongoose' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' +request = require '../request' requestAsync = Promise.promisify(request, {multiArgs: true}) +User = require '../../../server/models/User' +Classroom = require '../../../server/models/Classroom' +LevelSession = require '../../../server/models/LevelSession' +Level = require '../../../server/models/Level' classroomsURL = getURL('/db/classroom') diff --git a/spec/server/functional/course_instance.spec.coffee b/spec/server/functional/course_instance.spec.coffee index 370f7b7d6..891813ba1 100644 --- a/spec/server/functional/course_instance.spec.coffee +++ b/spec/server/functional/course_instance.spec.coffee @@ -4,6 +4,12 @@ require '../common' stripe = require('stripe')(config.stripe.secretKey) init = require '../init' utils = require '../utils' +CourseInstance = require '../../../server/models/CourseInstance' +Course = require '../../../server/models/Course' +User = require '../../../server/models/User' +Classroom = require '../../../server/models/Classroom' +Prepaid = require '../../../server/models/Prepaid' +request = require '../request' describe 'POST /db/course_instance', -> diff --git a/spec/server/functional/courses.spec.coffee b/spec/server/functional/courses.spec.coffee index d7ec03a46..b22a9f16e 100644 --- a/spec/server/functional/courses.spec.coffee +++ b/spec/server/functional/courses.spec.coffee @@ -2,7 +2,10 @@ require '../common' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' +request = require '../request' requestAsync = Promise.promisify(request, {multiArgs: true}) +Course = require '../../../server/models/Course' +User = require '../../../server/models/User' describe 'GET /db/course', -> beforeEach utils.wrap (done) -> diff --git a/spec/server/functional/db-id-version.spec.coffee b/spec/server/functional/db-id-version.spec.coffee index 746b5b2eb..f512b88dc 100644 --- a/spec/server/functional/db-id-version.spec.coffee +++ b/spec/server/functional/db-id-version.spec.coffee @@ -1,4 +1,7 @@ require '../common' +User = require '../../../server/models/User' +Article = require '../../../server/models/Article' +request = require '../request' describe '/db//version', -> it 'clears the db first', (done) -> diff --git a/spec/server/functional/discount_handler.spec.coffee b/spec/server/functional/discount_handler.spec.coffee index 4dc7ac07a..4e5e2da7f 100644 --- a/spec/server/functional/discount_handler.spec.coffee +++ b/spec/server/functional/discount_handler.spec.coffee @@ -1,5 +1,8 @@ config = require '../../../server_config' require '../common' +User = require '../../../server/models/User' +Payment = require '../../../server/models/Payment' +request = require '../request' # sample data that comes in through the webhook when you subscribe diff --git a/spec/server/functional/file.spec.coffee b/spec/server/functional/file.spec.coffee index e7ad50702..26699bd0c 100644 --- a/spec/server/functional/file.spec.coffee +++ b/spec/server/functional/file.spec.coffee @@ -2,6 +2,8 @@ require '../common' # Doesn't work on Travis. Need to figure out why, probably by having the # url not depend on some external resource. +mongoose = require 'mongoose' +request = require '../request' xdescribe '/file', -> url = getURL('/file') diff --git a/spec/server/functional/folder.spec.coffee b/spec/server/functional/folder.spec.coffee index e8ee823b2..6dc341618 100644 --- a/spec/server/functional/folder.spec.coffee +++ b/spec/server/functional/folder.spec.coffee @@ -1,4 +1,5 @@ require '../common' +request = require '../request' describe 'folder', -> url = getURL('/folder') diff --git a/spec/server/functional/languages.spec.coffee b/spec/server/functional/languages.spec.coffee index a42f71722..847083226 100644 --- a/spec/server/functional/languages.spec.coffee +++ b/spec/server/functional/languages.spec.coffee @@ -1,3 +1,4 @@ +request = require '../request' require '../common' describe 'languages', -> diff --git a/spec/server/functional/level.spec.coffee b/spec/server/functional/level.spec.coffee index acb8f000e..7cbf347e9 100644 --- a/spec/server/functional/level.spec.coffee +++ b/spec/server/functional/level.spec.coffee @@ -1,4 +1,11 @@ require '../common' +Campaign = require '../../../server/models/Campaign' +Classroom = require '../../../server/models/Classroom' +Course = require '../../../server/models/Course' +CourseInstance = require '../../../server/models/CourseInstance' +Level = require '../../../server/models/Level' +User = require '../../../server/models/User' +request = require '../request' describe 'Level', -> diff --git a/spec/server/functional/level_component.spec.coffee b/spec/server/functional/level_component.spec.coffee index 2748d2e51..d837516b2 100644 --- a/spec/server/functional/level_component.spec.coffee +++ b/spec/server/functional/level_component.spec.coffee @@ -1,4 +1,7 @@ require '../common' +Level = require '../../../server/models/Level' +LevelComponent = require '../../../server/models/LevelComponent' +request = require '../request' describe 'LevelComponent', -> diff --git a/spec/server/functional/level_feedback.spec.coffee b/spec/server/functional/level_feedback.spec.coffee index 4cd0da0de..5ab90c6eb 100644 --- a/spec/server/functional/level_feedback.spec.coffee +++ b/spec/server/functional/level_feedback.spec.coffee @@ -1,4 +1,5 @@ require '../common' +request = require '../request' describe 'LevelFeedback', -> diff --git a/spec/server/functional/level_session.spec.coffee b/spec/server/functional/level_session.spec.coffee index eddb3407c..02b48b220 100644 --- a/spec/server/functional/level_session.spec.coffee +++ b/spec/server/functional/level_session.spec.coffee @@ -1,4 +1,7 @@ require '../common' +LevelSession = require '../../../server/models/LevelSession' +mongoose = require 'mongoose' +request = require '../request' describe '/db/level.session', -> @@ -22,7 +25,6 @@ describe '/db/level.session', -> # Right now it's even possible to create ownerless sessions through POST xit 'allows users to create level sessions through PATCH', (done) -> loginJoe (joe) -> - console.log url + mongoose.Types.ObjectId() request {method: 'patch', uri: url + mongoose.Types.ObjectId(), json: session}, (err, res, body) -> expect(err).toBeNull() expect(res.statusCode).toBe 200 diff --git a/spec/server/functional/level_system.spec.coffee b/spec/server/functional/level_system.spec.coffee index 669fe5c4c..cf53c59e4 100644 --- a/spec/server/functional/level_system.spec.coffee +++ b/spec/server/functional/level_system.spec.coffee @@ -1,4 +1,7 @@ require '../common' +Level = require '../../../server/models/Level' +LevelSystem = require '../../../server/models/LevelSystem' +request = require '../request' describe 'LevelSystem', -> diff --git a/spec/server/functional/level_thang_component.spec.coffee b/spec/server/functional/level_thang_component.spec.coffee index d3d7e46b4..0e3aa9f04 100644 --- a/spec/server/functional/level_thang_component.spec.coffee +++ b/spec/server/functional/level_thang_component.spec.coffee @@ -1,4 +1,5 @@ require '../common' +request = require '../request' describe 'Level Thang Component', -> diff --git a/spec/server/functional/level_thang_type.spec.coffee b/spec/server/functional/level_thang_type.spec.coffee index 7d31d8747..957f2072f 100644 --- a/spec/server/functional/level_thang_type.spec.coffee +++ b/spec/server/functional/level_thang_type.spec.coffee @@ -1,4 +1,5 @@ require '../common' +request = require '../request' describe 'Level Thang Type', -> diff --git a/spec/server/functional/mail.spec.coffee b/spec/server/functional/mail.spec.coffee index 87127865b..141e8e05b 100644 --- a/spec/server/functional/mail.spec.coffee +++ b/spec/server/functional/mail.spec.coffee @@ -1,6 +1,7 @@ require '../common' mail = require '../../../server/routes/mail' -User = require '../../../server/users/User' +User = require '../../../server/models/User' +request = require '../request' testPost = data: diff --git a/spec/server/functional/nocked.spec.coffee b/spec/server/functional/nocked.spec.coffee index dac0270a2..3c02c0b9f 100644 --- a/spec/server/functional/nocked.spec.coffee +++ b/spec/server/functional/nocked.spec.coffee @@ -1,6 +1,7 @@ require '../common' config = require '../../../server_config' nockUtils = require('../nock-utils') +request = require '../request' xdescribe 'nock-utils', -> afterEach nockUtils.teardownNock diff --git a/spec/server/functional/patch.spec.coffee b/spec/server/functional/patch.spec.coffee index 723a9586a..a5516cefd 100644 --- a/spec/server/functional/patch.spec.coffee +++ b/spec/server/functional/patch.spec.coffee @@ -1,4 +1,8 @@ require '../common' +User = require '../../../server/models/User' +Article = require '../../../server/models/Article' +Patch = require '../../../server/models/Patch' +request = require '../request' describe '/db/patch', -> async = require 'async' diff --git a/spec/server/functional/payment.spec.coffee b/spec/server/functional/payment.spec.coffee index 4e342de2f..7a69388eb 100644 --- a/spec/server/functional/payment.spec.coffee +++ b/spec/server/functional/payment.spec.coffee @@ -3,6 +3,9 @@ testReceipt = 'MIIVEQYJKoZIhvcNAQcCoIIVAjCCFP4CAQExCzAJBgUrDgMCGgUAMIIEwgYJKoZIh config = require '../../../server_config' require '../common' nockUtils = require '../nock-utils' +User = require '../../../server/models/User' +Payment = require '../../../server/models/Payment' +request = require '../request' describe '/db/payment', -> diff --git a/spec/server/functional/prepaid.spec.coffee b/spec/server/functional/prepaid.spec.coffee index 328b03cf9..ee25f7613 100644 --- a/spec/server/functional/prepaid.spec.coffee +++ b/spec/server/functional/prepaid.spec.coffee @@ -6,6 +6,12 @@ async = require 'async' nockUtils = require '../nock-utils' utils = require '../utils' Promise = require 'bluebird' +Payment = require '../../../server/models/Payment' +Prepaid = require '../../../server/models/Prepaid' +User = require '../../../server/models/User' +Course = require '../../../server/models/Course' +CourseInstance = require '../../../server/models/CourseInstance' +request = require '../request' describe '/db/prepaid', -> prepaidURL = getURL('/db/prepaid') diff --git a/spec/server/functional/queue.spec.coffee b/spec/server/functional/queue.spec.coffee index a290168fa..4f622d310 100644 --- a/spec/server/functional/queue.spec.coffee +++ b/spec/server/functional/queue.spec.coffee @@ -1,4 +1,5 @@ require '../common' +request = require '../request' describe 'queue', -> someURL = getURL('/queue/') diff --git a/spec/server/functional/subscription.spec.coffee b/spec/server/functional/subscription.spec.coffee index 44b562665..08425668e 100644 --- a/spec/server/functional/subscription.spec.coffee +++ b/spec/server/functional/subscription.spec.coffee @@ -5,6 +5,10 @@ utils = require '../../../app/core/utils' # Must come after require /common mongoose = require 'mongoose' TRAVIS = process.env.COCO_TRAVIS_TEST nockUtils = require '../nock-utils' +User = require '../../../server/models/User' +Payment = require '../../../server/models/Payment' +Prepaid = require '../../../server/models/Prepaid' +request = require '../request' subPrice = 100 subGems = 3500 diff --git a/spec/server/functional/trial_request.spec.coffee b/spec/server/functional/trial_request.spec.coffee index ac9638044..4482378d4 100644 --- a/spec/server/functional/trial_request.spec.coffee +++ b/spec/server/functional/trial_request.spec.coffee @@ -2,6 +2,10 @@ require '../common' utils = require '../utils' _ = require 'lodash' Promise = require 'bluebird' +User = require '../../../server/models/User' +TrialRequest = require '../../../server/models/TrialRequest' +Prepaid = require '../../../server/models/Prepaid' +request = require '../request' fixture = { type: 'subscription' diff --git a/spec/server/functional/user.spec.coffee b/spec/server/functional/user.spec.coffee index c217cd148..e77832708 100644 --- a/spec/server/functional/user.spec.coffee +++ b/spec/server/functional/user.spec.coffee @@ -1,7 +1,9 @@ require '../common' utils = require '../utils' urlUser = '/db/user' - +User = require '../../../server/models/User' +Classroom = require '../../../server/models/Classroom' +request = require '../request' describe 'Server user object', -> @@ -362,13 +364,13 @@ describe 'DELETE /db/user', -> done() describe 'Statistics', -> - LevelSession = require '../../../server/levels/sessions/LevelSession' - Article = require '../../../server/articles/Article' - Level = require '../../../server/levels/Level' - LevelSystem = require '../../../server/levels/systems/LevelSystem' - LevelComponent = require '../../../server/levels/components/LevelComponent' - ThangType = require '../../../server/levels/thangs/ThangType' - User = require '../../../server/users/User' + LevelSession = require '../../../server/models/LevelSession' + Article = require '../../../server/models/Article' + Level = require '../../../server/models/Level' + LevelSystem = require '../../../server/models/LevelSystem' + LevelComponent = require '../../../server/models/LevelComponent' + ThangType = require '../../../server/models/ThangType' + User = require '../../../server/models/User' UserHandler = require '../../../server/users/user_handler' it 'keeps track of games completed', (done) -> diff --git a/spec/server/init.coffee b/spec/server/init.coffee index 912ff6b1a..3653d3a43 100644 --- a/spec/server/init.coffee +++ b/spec/server/init.coffee @@ -1,3 +1,8 @@ +User = require '../../server/models/User' +Classroom = require '../../server/models/Classroom' +CourseInstance = require '../../server/models/CourseInstance' +Course = require '../../server/models/Course' +Prepaid = require '../../server/models/Prepaid' module.exports.course = (properties) -> properties ?= {} diff --git a/spec/server/integration/models/Level.spec.coffee b/spec/server/integration/models/Level.spec.coffee index 1067da955..4a6690f9f 100644 --- a/spec/server/integration/models/Level.spec.coffee +++ b/spec/server/integration/models/Level.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +Level = require '../../../../server/models/Level' describe 'Level', -> diff --git a/spec/server/integration/models/LevelComponent.spec.coffee b/spec/server/integration/models/LevelComponent.spec.coffee index 782721cd5..0c802dc84 100644 --- a/spec/server/integration/models/LevelComponent.spec.coffee +++ b/spec/server/integration/models/LevelComponent.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +LevelComponent = require '../../../../server/models/LevelComponent' describe 'LevelComponent', -> diff --git a/spec/server/integration/models/LevelSession.spec.coffee b/spec/server/integration/models/LevelSession.spec.coffee index 1b3f6afd9..cb86a4d63 100644 --- a/spec/server/integration/models/LevelSession.spec.coffee +++ b/spec/server/integration/models/LevelSession.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +LevelSession = require '../../../../server/models/LevelSession' describe 'LevelSession', -> diff --git a/spec/server/integration/models/LevelSystem.spec.coffee b/spec/server/integration/models/LevelSystem.spec.coffee index 15cbbe474..0727c9d61 100644 --- a/spec/server/integration/models/LevelSystem.spec.coffee +++ b/spec/server/integration/models/LevelSystem.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +LevelSystem = require '../../../../server/models/LevelSystem' describe 'LevelSystem', -> diff --git a/spec/server/integration/models/LevelThangType.spec.coffee b/spec/server/integration/models/LevelThangType.spec.coffee index 97e42c756..6fbc5116a 100644 --- a/spec/server/integration/models/LevelThangType.spec.coffee +++ b/spec/server/integration/models/LevelThangType.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +LevelThangType = require '../../../../server/models/LevelThangType' describe 'LevelThangType', -> diff --git a/spec/server/integration/models/article.spec.coffee b/spec/server/integration/models/article.spec.coffee index 6ce3fb047..32edf4264 100644 --- a/spec/server/integration/models/article.spec.coffee +++ b/spec/server/integration/models/article.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +Article = require '../../../../server/models/Article' describe 'Article', -> diff --git a/spec/server/integration/models/plugins.spec.coffee b/spec/server/integration/models/plugins.spec.coffee index df4882a59..f83114957 100644 --- a/spec/server/integration/models/plugins.spec.coffee +++ b/spec/server/integration/models/plugins.spec.coffee @@ -1,4 +1,5 @@ require '../../common' +Article = require '../../../../server/models/Article' describe 'NamePlugin', -> diff --git a/spec/server/request.coffee b/spec/server/request.coffee new file mode 100644 index 000000000..1da973570 --- /dev/null +++ b/spec/server/request.coffee @@ -0,0 +1,4 @@ +request = require('request').defaults({jar: true}) +Promise = require 'bluebird' +Promise.promisifyAll(request, {multiArgs: true}) +module.exports = request \ No newline at end of file diff --git a/spec/server/require-files.spec.coffee b/spec/server/require-files.spec.coffee new file mode 100644 index 000000000..4c4646e25 --- /dev/null +++ b/spec/server/require-files.spec.coffee @@ -0,0 +1,23 @@ +fs = require 'fs' + +walkFiles = (path, cb) -> + list = fs.readdirSync(path) + for item in list + subPath = path + '/' + item + stat = fs.lstatSync(subPath) + if stat.isFile() + cb(subPath) + else if stat.isDirectory() + walkFiles(subPath, cb) + +describe 'each file in /server', -> + it 'can be required', -> + walkFiles 'server', (path) -> + # TODO: These two files should not break on require in testing or dev + if _.str.endsWith(path, 'LockManager.coffee') + return + if _.str.endsWith(path, 'picoctf.coffee') + return + if _.str.endsWith(path, '.coffee') + requirePath = '../../'+path.slice(0, path.length-7) + res = require(requirePath) diff --git a/spec/server/unit/analytics.spec.coffee b/spec/server/unit/analytics.spec.coffee index bae58bfc6..c6dbc2605 100644 --- a/spec/server/unit/analytics.spec.coffee +++ b/spec/server/unit/analytics.spec.coffee @@ -1,9 +1,10 @@ GLOBAL._ = require 'lodash' require '../common' -AnalyticsUsersActive = require '../../../server/analytics/AnalyticsUsersActive' -LevelSession = require '../../../server/levels/sessions/LevelSession' -User = require '../../../server/users/User' +AnalyticsUsersActive = require '../../../server/models/AnalyticsUsersActive' +LevelSession = require '../../../server/models/LevelSession' +User = require '../../../server/models/User' +mongoose = require 'mongoose' # TODO: these tests have some rerun/cleanup issues # TODO: add tests for purchase, payment, subscribe, unsubscribe, and earned achievements diff --git a/spec/server/unit/patch.spec.coffee b/spec/server/unit/patch.spec.coffee index e7ce13ddd..0745615c9 100644 --- a/spec/server/unit/patch.spec.coffee +++ b/spec/server/unit/patch.spec.coffee @@ -1,4 +1,6 @@ require '../common' +Patch = require '../../../server/models/Patch' + describe 'schema methods', -> patch = new Patch diff --git a/spec/server/unit/user.spec.coffee b/spec/server/unit/user.spec.coffee index e5173146d..8acd4351f 100644 --- a/spec/server/unit/user.spec.coffee +++ b/spec/server/unit/user.spec.coffee @@ -1,6 +1,6 @@ GLOBAL._ = require 'lodash' -User = require '../../../server/users/User' +User = require '../../../server/models/User' describe 'user', -> diff --git a/spec/server/utils.coffee b/spec/server/utils.coffee index 97140883e..157ccdfc7 100644 --- a/spec/server/utils.coffee +++ b/spec/server/utils.coffee @@ -2,6 +2,8 @@ async = require 'async' utils = require '../../server/lib/utils' co = require 'co' Promise = require 'bluebird' +User = require '../../server/models/User' + module.exports = mw = getURL: (path) -> 'http://localhost:3001' + path