mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Refactor server models into /server/models, remove request and mongoose from test globals
This commit is contained in:
parent
debc337dd5
commit
c3e5416166
144 changed files with 957 additions and 872 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Achievement = require './Achievement'
|
||||
Achievement = require './../models/Achievement'
|
||||
Handler = require '../commons/Handler'
|
||||
|
||||
class AchievementHandler extends Handler
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
AnalyticsString = require './AnalyticsString'
|
||||
AnalyticsString = require './../models/AnalyticsString'
|
||||
Handler = require '../commons/Handler'
|
||||
|
||||
class AnalyticsStringHandler extends Handler
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Handler = require '../commons/Handler'
|
||||
AnalyticsStripeInvoice = require './AnalyticsStripeInvoice'
|
||||
AnalyticsStripeInvoice = require './../models/AnalyticsStripeInvoice'
|
||||
|
||||
class AnalyticsStripeInvoiceHandler extends Handler
|
||||
modelClass: AnalyticsStripeInvoice
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
AnalyticsUsersActive = require './AnalyticsUsersActive'
|
||||
AnalyticsUsersActive = require './../models/AnalyticsUsersActive'
|
||||
Handler = require '../commons/Handler'
|
||||
|
||||
class AnalyticsUsersActiveHandler extends Handler
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
|
@ -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'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
LevelComponent = require './LevelComponent'
|
||||
LevelComponent = require './../../models/LevelComponent'
|
||||
Handler = require '../../commons/Handler'
|
||||
mongoose = require 'mongoose'
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
LevelFeedback = require './LevelFeedback'
|
||||
LevelFeedback = require './../../models/LevelFeedback'
|
||||
Handler = require '../../commons/Handler'
|
||||
|
||||
class LevelFeedbackHandler extends Handler
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
LevelSession = require './LevelSession'
|
||||
LevelSession = require './../../models/LevelSession'
|
||||
Handler = require '../../commons/Handler'
|
||||
log = require 'winston'
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
LevelSystem = require './LevelSystem'
|
||||
LevelSystem = require './../../models/LevelSystem'
|
||||
Handler = require '../../commons/Handler'
|
||||
|
||||
LevelSystemHandler = class LevelSystemHandler extends Handler
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ThangType = require './ThangType'
|
||||
ThangType = require './../../models/ThangType'
|
||||
Handler = require '../../commons/Handler'
|
||||
|
||||
ThangTypeHandler = class ThangTypeHandler extends Handler
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
log = require 'winston'
|
||||
Payment = require '../payments/Payment'
|
||||
Payment = require '../models/Payment'
|
||||
PaymentHandler = require '../payments/payment_handler'
|
||||
|
||||
module.exports =
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
AnalyticsString = require '../analytics/AnalyticsString'
|
||||
AnalyticsString = require '../models/AnalyticsString'
|
||||
log = require 'winston'
|
||||
mongoose = require 'mongoose'
|
||||
config = require '../../server_config'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
MailSent = require './MailSent'
|
||||
MailSent = require './../../models/MailSent'
|
||||
Handler = require '../../commons/Handler'
|
||||
|
||||
class MailSentHandler extends Handler
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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) ->
|
|
@ -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'
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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:
|
|
@ -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')
|
|
@ -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
|
|
@ -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'}
|
|
@ -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:
|
|
@ -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'
|
||||
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)
|
||||
|
|
|
@ -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 {
|
|
@ -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,
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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'
|
||||
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)
|
||||
|
|
|
@ -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}
|
||||
|
|
@ -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)
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
UserPollsRecord = require './UserPollsRecord'
|
||||
UserPollsRecord = require './../models/UserPollsRecord'
|
||||
Handler = require '../commons/Handler'
|
||||
async = require 'async'
|
||||
mongoose = require 'mongoose'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
UserCodeProblem = require './UserCodeProblem'
|
||||
UserCodeProblem = require './../models/UserCodeProblem'
|
||||
Handler = require '../commons/Handler'
|
||||
utils = require '../lib/utils'
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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) ->
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue