Classroom invite codes are now real words like BigFrogFarm

This commit is contained in:
Nick Winter 2015-11-22 07:47:28 -08:00
parent 83051ac1fe
commit e0011ee5d0
5 changed files with 22 additions and 15 deletions

View file

@ -8,6 +8,7 @@ _.extend ClassroomSchema.properties,
ownerID: c.objectId() ownerID: c.objectId()
description: {type: 'string'} description: {type: 'string'}
code: c.shortString(title: "Unique code to redeem") code: c.shortString(title: "Unique code to redeem")
codeCamel: c.shortString(title: "UpperCamelCase version of code for display purposes")
aceConfig: aceConfig:
language: {type: 'string', 'enum': ['python', 'javascript']} language: {type: 'string', 'enum': ['python', 'javascript']}

View file

@ -10,7 +10,7 @@ block modal-body-content
p(data-i18n="courses.invite_link_p_1") p(data-i18n="courses.invite_link_p_1")
.alert.alert-info .alert.alert-info
strong= document.location.origin + "/courses/students?_cc=" + view.classroom.get('code') strong= document.location.origin + "/courses/students?_cc=" + (view.classroom.get('codeCamel') || view.classroom.get('code'))
p(data-i18n="courses.invite_link_p_2") p(data-i18n="courses.invite_link_p_2")
.form .form
.form-group .form-group

View file

@ -28,7 +28,7 @@ module.exports = class StudentCoursesView extends RootView
@supermodel.loadCollection(@classrooms, 'classrooms', { data: {memberID: me.id} }) @supermodel.loadCollection(@classrooms, 'classrooms', { data: {memberID: me.id} })
@courses = new CocoCollection([], { url: "/db/course", model: Course}) @courses = new CocoCollection([], { url: "/db/course", model: Course})
@supermodel.loadCollection(@courses, 'courses') @supermodel.loadCollection(@courses, 'courses')
onLoaded: -> onLoaded: ->
if (@classCode = utils.getQueryVariable('_cc', false)) and not me.isAnonymous() if (@classCode = utils.getQueryVariable('_cc', false)) and not me.isAnonymous()
@joinClass() @joinClass()
@ -63,17 +63,17 @@ module.exports = class StudentCoursesView extends RootView
onJoinClassroomSuccess: (data, textStatus, jqxhr) -> onJoinClassroomSuccess: (data, textStatus, jqxhr) ->
classroom = new Classroom(data) classroom = new Classroom(data)
application.tracker?.trackEvent 'Joined classroom', { application.tracker?.trackEvent 'Joined classroom', {
classroomID: classroom.id, classroomID: classroom.id,
classroomName: classroom.get('name') classroomName: classroom.get('name')
ownerID: classroom.get('ownerID') ownerID: classroom.get('ownerID')
} }
@classrooms.add(classroom) @classrooms.add(classroom)
@render() @render()
classroomCourseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance }) classroomCourseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance })
classroomCourseInstances.fetch({ data: {classroomID: classroom.id} }) classroomCourseInstances.fetch({ data: {classroomID: classroom.id} })
@listenToOnce classroomCourseInstances, 'sync', -> @listenToOnce classroomCourseInstances, 'sync', ->
# join any course instances in the classroom which are free to join # join any course instances in the classroom which are free to join
jqxhrs = [] jqxhrs = []
for courseInstance in classroomCourseInstances.models for courseInstance in classroomCourseInstances.models

View file

@ -14,12 +14,16 @@ ClassroomSchema.statics.editableProperties = [
'aceConfig' 'aceConfig'
] ]
# 250 words; will want to use 4 code words once we get past 10M classrooms.
words = 'angry apple arm army art baby back bad bag ball bath bean bear bed bell best big bird bite blue boat book box boy bread burn bus cake car cat chair city class clock cloud coat coin cold cook cool corn crash cup dark day deep desk dish dog door down draw dream drink drop dry duck dust east eat egg enemy eye face false farm fast fear fight find fire flag floor fly food foot fork fox free fruit full fun funny game gate gift glass goat gold good green hair half hand happy heart heavy help hide hill home horse house ice idea iron jelly job jump key king lamp large last late lazy leaf left leg life light lion lock long luck map mean milk mix moon more most mouth music name neck net new next nice night north nose old only open page paint pan paper park party path pig pin pink place plane plant plate play point pool power pull push queen rain ready red rest rice ride right ring road rock room run sad safe salt same sand sell shake shape share sharp sheep shelf ship shirt shoe shop short show sick side silly sing sink sit size sky sleep slow small snow sock soft soup south space speed spell spoon star start step stone stop sweet swim sword table team thick thin thing think today tooth top town tree true turn type under want warm watch water west wide win word yes zoo'.split(' ')
ClassroomSchema.statics.generateNewCode = (done) -> ClassroomSchema.statics.generateNewCode = (done) ->
tryCode = -> tryCode = ->
code = _.sample("abcdefghijklmnopqrstuvwxyz0123456789", 8).join('') codeCamel = _.map(_.sample(words, 3), (s) -> s[0].toUpperCase() + s.slice(1)).join('')
code = codeCamel.toLowerCase()
Classroom.findOne code: code, (err, classroom) -> Classroom.findOne code: code, (err, classroom) ->
return done() if err return done() if err
return done(code) unless classroom return done(code, codeCamel) unless classroom
tryCode() tryCode()
tryCode() tryCode()
@ -27,14 +31,15 @@ ClassroomSchema.statics.generateNewCode = (done) ->
ClassroomSchema.pre('save', (next) -> ClassroomSchema.pre('save', (next) ->
return next() if @get('code') return next() if @get('code')
Classroom.generateNewCode (code) => Classroom.generateNewCode (code, codeCamel) =>
@set 'code', code @set 'code', code
@set 'codeCamel', codeCamel
next() next()
) )
ClassroomSchema.methods.isOwner = (userID) -> ClassroomSchema.methods.isOwner = (userID) ->
return userID.equals(@get('ownerID')) return userID.equals(@get('ownerID'))
ClassroomSchema.methods.isMember = (userID) -> ClassroomSchema.methods.isMember = (userID) ->
return _.any @get('members') or [], (memberID) -> userID.equals(memberID) return _.any @get('members') or [], (memberID) -> userID.equals(memberID)

View file

@ -51,7 +51,8 @@ ClassroomHandler = class ClassroomHandler extends Handler
joinClassroomAPI: (req, res, classroomID) -> joinClassroomAPI: (req, res, classroomID) ->
return @sendBadInputError(res, 'Need an object with a code') unless req.body?.code return @sendBadInputError(res, 'Need an object with a code') unless req.body?.code
Classroom.findOne {code: req.body.code}, (err, classroom) => code = req.body.code.toLowerCase()
Classroom.findOne {code: code}, (err, classroom) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) if not classroom return @sendNotFoundError(res) if not classroom
members = _.clone(classroom.get('members')) members = _.clone(classroom.get('members'))
@ -63,16 +64,16 @@ ClassroomHandler = class ClassroomHandler extends Handler
members.push req.user.get('_id') members.push req.user.get('_id')
classroom.set('members', members) classroom.set('members', members)
return @sendSuccess(res, @formatEntity(req, classroom)) return @sendSuccess(res, @formatEntity(req, classroom))
formatEntity: (req, doc) -> formatEntity: (req, doc) ->
if req.user?.isAdmin() or req.user?.get('_id').equals(doc.get('ownerID')) if req.user?.isAdmin() or req.user?.get('_id').equals(doc.get('ownerID'))
return doc.toObject() return doc.toObject()
return _.omit(doc.toObject(), 'code') return _.omit(doc.toObject(), 'code', 'codeCamel')
inviteStudents: (req, res, classroomID) -> inviteStudents: (req, res, classroomID) ->
if not req.body.emails if not req.body.emails
return @sendBadInputError(res, 'Emails not included') return @sendBadInputError(res, 'Emails not included')
Classroom.findById classroomID, (err, classroom) => Classroom.findById classroomID, (err, classroom) =>
return @sendDatabaseError(res, err) if err return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless classroom return @sendNotFoundError(res) unless classroom
@ -86,10 +87,10 @@ ClassroomHandler = class ClassroomHandler extends Handler
email_data: email_data:
class_name: classroom.get('name') class_name: classroom.get('name')
# TODO: join_link # TODO: join_link
join_link: "https://codecombat.com/courses/students?_cc=" + classroom.get('code') join_link: "https://codecombat.com/courses/students?_cc=" + (classroom.get('codeCamel') or classroom.get('code'))
sendwithus.api.send context, _.noop sendwithus.api.send context, _.noop
return @sendSuccess(res, {}) return @sendSuccess(res, {})
get: (req, res) -> get: (req, res) ->
if ownerID = req.query.ownerID if ownerID = req.query.ownerID
return @sendForbiddenError(res) unless req.user and (req.user.isAdmin() or ownerID is req.user.id) return @sendForbiddenError(res) unless req.user and (req.user.isAdmin() or ownerID is req.user.id)