mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Add class invite system
This commit is contained in:
parent
212ee8a65a
commit
3a90356f59
7 changed files with 90 additions and 17 deletions
|
@ -875,6 +875,10 @@
|
|||
play_time: "Play time:"
|
||||
completed: "Completed:"
|
||||
invite_students: "Invite students to join this class."
|
||||
invite_link_header: "Link to join course"
|
||||
invite_link_p_1: "Give this link to students you would like to have join the course."
|
||||
invite_link_p_2: "Or have us email them directly:"
|
||||
capacity_used: "Course slots used:"
|
||||
enter_emails: "Enter student emails to invite, one per line"
|
||||
send_invites: "Send Invites"
|
||||
title: "Title"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#course-details-view
|
||||
|
||||
.invite-emails
|
||||
#invite-emails-textarea
|
||||
width: 50%
|
||||
|
||||
.progress-cell
|
||||
|
|
|
@ -247,18 +247,24 @@ mixin progress-members-popup-started(i, level)
|
|||
|
||||
mixin invite-tab
|
||||
p(data-i18n="courses.invite_students")
|
||||
// TODO: finalize text here and then i18n it
|
||||
h3 Link to join course
|
||||
p Give this link to students you would like to have join the course.
|
||||
a= document.location.origin + "/account/prepaid?_ppc=" + view.prepaid.get('code')
|
||||
p Or have us email them directly:
|
||||
textarea.invite-emails(rows=3, data-i18n="[placeholder]courses.enter_emails", placeholder="Enter student emails to invite, one per line")
|
||||
div(style='margin-top:10px;')
|
||||
button.btn.btn-success.btn-invite(data-i18n="courses.send_invites")
|
||||
h3(data-i18n="courses.invite_link_header")
|
||||
p(data-i18n="courses.invite_link_p_1")
|
||||
.alert.alert-info
|
||||
strong= document.location.origin + "/account/prepaid?_ppc=" + view.prepaid.get('code')
|
||||
p(data-i18n="courses.invite_link_p_2")
|
||||
.form
|
||||
.form-group
|
||||
textarea#invite-emails-textarea.form-control(
|
||||
rows=3, data-i18n="[placeholder]courses.enter_emails", placeholder="Enter student emails to invite, one per line")
|
||||
.form-group
|
||||
button#invite-btn.btn.btn-success(data-i18n="courses.send_invites")
|
||||
#invite-emails-sending-alert.alert.alert-info.hide(data-i18n="common.sending")
|
||||
#invite-emails-success-alert.alert.alert-success.hide(data-i18n="play_level.done")
|
||||
|
||||
h3 Class Capacity
|
||||
if view.prepaid.loaded
|
||||
p
|
||||
span.spr Course slots used:
|
||||
span.spr(data-i18n="courses.capacity_used")
|
||||
span #{view.prepaid.get('redeemers').length} / #{view.prepaid.get('maxRedeemers')}.
|
||||
|
||||
mixin levels-tab
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
'click .progress-level-cell': 'onClickProgressLevelCell'
|
||||
'mouseenter .progress-level-cell': 'onMouseEnterPoint'
|
||||
'mouseleave .progress-level-cell': 'onMouseLeavePoint'
|
||||
'click .btn-invite': 'onClickButtonInvite'
|
||||
'click #invite-btn': 'onClickInviteButton'
|
||||
|
||||
constructor: (options, @courseID, @courseInstanceID) ->
|
||||
super options
|
||||
|
@ -123,11 +123,7 @@ module.exports = class CourseDetailsView extends RootView
|
|||
@members = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/members", model: User, comparator: 'nameLower' })
|
||||
@listenToOnce @members, 'sync', @onMembersSync
|
||||
@supermodel.loadCollection @members, 'members', cache: false
|
||||
if @adminMode
|
||||
prepaidID = @course.get('prepaidID')
|
||||
if not prepaidID
|
||||
prepaidID = '560ef835444e5c9a847e0218'
|
||||
# TODO: Just abort if no prepaidID
|
||||
if @adminMode and prepaidID = @courseInstance.get('prepaidID')
|
||||
@prepaid = @supermodel.getModel(Prepaid, prepaidID) or new Prepaid _id: prepaidID
|
||||
@listenTo @prepaid, 'sync', @onPrepaidSync
|
||||
if @prepaid.loaded
|
||||
|
@ -244,8 +240,25 @@ module.exports = class CourseDetailsView extends RootView
|
|||
viewArgs: [{}, levelSlug]
|
||||
}
|
||||
|
||||
onClickButtonInvite: (e) ->
|
||||
onClickInviteButton: (e) ->
|
||||
emails = @$('#invite-emails-textarea').val()
|
||||
emails = emails.split('\n')
|
||||
emails = _.filter((_.string.trim(email) for email in emails))
|
||||
if not emails.length
|
||||
return
|
||||
url = @courseInstance.url() + '/invite_students'
|
||||
@$('#invite-btn, #invite-emails-textarea').addClass('hide')
|
||||
@$('#invite-emails-sending-alert').removeClass('hide')
|
||||
|
||||
$.ajax({
|
||||
url: url
|
||||
data: {emails: emails}
|
||||
method: 'POST'
|
||||
context: @
|
||||
success: ->
|
||||
@$('#invite-emails-sending-alert').addClass('hide')
|
||||
@$('#invite-emails-success-alert').removeClass('hide')
|
||||
})
|
||||
|
||||
onMouseEnterPoint: (e) ->
|
||||
$('.progress-popup-container').hide()
|
||||
|
|
|
@ -9,6 +9,7 @@ PrepaidHandler = require '../prepaids/prepaid_handler'
|
|||
User = require '../users/User'
|
||||
UserHandler = require '../users/user_handler'
|
||||
utils = require '../../app/core/utils'
|
||||
sendwithus = require '../sendwithus'
|
||||
|
||||
CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
||||
modelClass: CourseInstance
|
||||
|
@ -31,6 +32,7 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
return @createAPI(req, res) if relationship is 'create'
|
||||
return @getLevelSessionsAPI(req, res, args[0]) if args[1] is 'level_sessions'
|
||||
return @getMembersAPI(req, res, args[0]) if args[1] is 'members'
|
||||
return @inviteStudents(req, res, args[0]) if relationship is 'invite_students'
|
||||
super arguments...
|
||||
|
||||
createAPI: (req, res) ->
|
||||
|
@ -101,4 +103,28 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
cleandocs = (UserHandler.formatEntity(req, doc) for doc in users)
|
||||
@sendSuccess(res, cleandocs)
|
||||
|
||||
inviteStudents: (req, res, courseInstanceID) ->
|
||||
if not req.body.emails
|
||||
return @sendBadInputError(res, 'Emails not included')
|
||||
CourseInstance.findById courseInstanceID, (err, courseInstance) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless courseInstance
|
||||
return @sendForbiddenError(res) unless @hasAccessToDocument(req, courseInstance)
|
||||
|
||||
Prepaid.findById courseInstance.get('prepaidID'), (err, prepaid) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless prepaid
|
||||
return @sendForbiddenError(res) unless prepaid.get('maxRedeemers') > prepaid.get('redeemers').length
|
||||
for email in req.body.emails
|
||||
context =
|
||||
email_id: sendwithus.templates.course_invite_email
|
||||
recipient:
|
||||
address: email
|
||||
email_data:
|
||||
class_name: courseInstance.get('name')
|
||||
join_link: "https://codecombat.com/account/prepaid?_ppc=" + prepaid.get('code')
|
||||
sendwithus.api.send context, _.noop
|
||||
return @sendSuccess(res, {})
|
||||
|
||||
|
||||
module.exports = new CourseInstanceHandler()
|
||||
|
|
|
@ -22,3 +22,5 @@ module.exports.templates =
|
|||
generic_email: 'tem_JhRnQ4pvTS4KdQjYoZdbei'
|
||||
plain_text_email: 'tem_85UvKDCCNPXsFckERTig6Y'
|
||||
next_steps_email: 'tem_RDHhTG5inXQi8pthyqWr5D'
|
||||
course_invite_email: 'tem_u6D2EFWYC5Ptk38bSykjsU'
|
||||
|
||||
|
|
|
@ -196,3 +196,25 @@ describe 'CourseInstance', ->
|
|||
expect(prepaid.get('maxRedeemers')).toEqual(50)
|
||||
expect(prepaid.get('properties')?.courseIDs?.length).toEqual(courses.length)
|
||||
done()
|
||||
|
||||
describe 'Invite to course', ->
|
||||
it 'takes a list of emails and sends invites', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
createCourse 0, (err, course) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
createCourseInstances user1, course.get('_id'), 1, token.id, (err, courseInstances) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(courseInstances.length).toEqual(1)
|
||||
inviteStudentsURL = getURL("/db/course_instance/#{courseInstances[0]._id}/invite_students")
|
||||
requestBody = {
|
||||
emails: ['test@test.com']
|
||||
}
|
||||
request.post { uri: inviteStudentsURL, json: requestBody }, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
done()
|
||||
|
|
Loading…
Reference in a new issue