mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-13 09:11:22 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
9555a12e5c
8 changed files with 0 additions and 98 deletions
|
@ -1367,7 +1367,6 @@
|
||||||
earliest_incomplete: "Earliest incomplete level"
|
earliest_incomplete: "Earliest incomplete level"
|
||||||
latest_complete: "Latest completed level"
|
latest_complete: "Latest completed level"
|
||||||
enroll_student: "Enroll student"
|
enroll_student: "Enroll student"
|
||||||
revoke_enrollment: "Revoke Enrollment"
|
|
||||||
adding_students: "Adding students"
|
adding_students: "Adding students"
|
||||||
course_progress: "Course Progress"
|
course_progress: "Course Progress"
|
||||||
not_applicable: "N/A"
|
not_applicable: "N/A"
|
||||||
|
@ -1438,8 +1437,6 @@
|
||||||
status_expired: "Expired on {{date}}"
|
status_expired: "Expired on {{date}}"
|
||||||
status_not_enrolled: "Not Enrolled"
|
status_not_enrolled: "Not Enrolled"
|
||||||
status_enrolled: "Expires on {{date}}"
|
status_enrolled: "Expires on {{date}}"
|
||||||
revoke_confirm: "Are you sure you want to revoke enrollment from {{student_name}}?"
|
|
||||||
revoking: "Revoking..."
|
|
||||||
|
|
||||||
classes:
|
classes:
|
||||||
archmage_title: "Archmage"
|
archmage_title: "Archmage"
|
||||||
|
|
|
@ -40,10 +40,3 @@ module.exports = class Prepaid extends CocoModel
|
||||||
options.data ?= {}
|
options.data ?= {}
|
||||||
options.data.userID = user.id or user
|
options.data.userID = user.id or user
|
||||||
@fetch(options)
|
@fetch(options)
|
||||||
|
|
||||||
revoke: (user, options={}) ->
|
|
||||||
options.url = _.result(@, 'url')+'/redeemers'
|
|
||||||
options.type = 'DELETE'
|
|
||||||
options.data ?= {}
|
|
||||||
options.data.userID = user.id or user
|
|
||||||
@fetch(options)
|
|
||||||
|
|
|
@ -308,7 +308,5 @@
|
||||||
width: 300px
|
width: 300px
|
||||||
.enroll-col
|
.enroll-col
|
||||||
width: 140px
|
width: 140px
|
||||||
.revoke-col
|
|
||||||
width: 170px
|
|
||||||
td
|
td
|
||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
|
|
|
@ -419,6 +419,3 @@ mixin enrollmentStatusTab
|
||||||
td.enroll-col
|
td.enroll-col
|
||||||
if status !== 'enrolled'
|
if status !== 'enrolled'
|
||||||
button.enroll-student-button.btn.btn-navy(data-i18n="teacher.enroll_student", data-user-id=student.id)
|
button.enroll-student-button.btn.btn-navy(data-i18n="teacher.enroll_student", data-user-id=student.id)
|
||||||
td.revoke-col
|
|
||||||
if status === 'enrolled'
|
|
||||||
button.revoke-student-button.btn.btn-burgandy-alt(data-i18n="teacher.revoke_enrollment", data-user-id=student.id)
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
'click .remove-student-link': 'onClickRemoveStudentLink'
|
'click .remove-student-link': 'onClickRemoveStudentLink'
|
||||||
'click .assign-student-button': 'onClickAssignStudentButton'
|
'click .assign-student-button': 'onClickAssignStudentButton'
|
||||||
'click .enroll-student-button': 'onClickEnrollStudentButton'
|
'click .enroll-student-button': 'onClickEnrollStudentButton'
|
||||||
'click .revoke-student-button': 'onClickRevokeStudentButton'
|
|
||||||
'click .assign-to-selected-students': 'onClickBulkAssign'
|
'click .assign-to-selected-students': 'onClickBulkAssign'
|
||||||
'click .enroll-selected-students': 'onClickBulkEnroll'
|
'click .enroll-selected-students': 'onClickBulkEnroll'
|
||||||
'click .export-student-progress-btn': 'onClickExportStudentProgress'
|
'click .export-student-progress-btn': 'onClickExportStudentProgress'
|
||||||
|
@ -372,23 +371,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
|
|
||||||
onClickRevokeStudentButton: (e) ->
|
|
||||||
button = $(e.currentTarget)
|
|
||||||
userID = button.data('user-id')
|
|
||||||
user = @students.get(userID)
|
|
||||||
s = $.i18n.t('teacher.revoke_confirm').replace('{{student_name}}', user.broadName())
|
|
||||||
return unless confirm(s)
|
|
||||||
prepaid = user.makeCoursePrepaid()
|
|
||||||
button.text($.i18n.t('teacher.revoking'))
|
|
||||||
prepaid.revoke(user, {
|
|
||||||
success: =>
|
|
||||||
user.unset('coursePrepaid')
|
|
||||||
error: (prepaid, jqxhr) =>
|
|
||||||
msg = jqxhr.responseJSON.message
|
|
||||||
noty text: msg, layout: 'center', type: 'error', killer: true, timeout: 3000
|
|
||||||
complete: => @render()
|
|
||||||
})
|
|
||||||
|
|
||||||
onClickSelectAll: (e) ->
|
onClickSelectAll: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
checkboxes = @$('.student-checkbox input')
|
checkboxes = @$('.student-checkbox input')
|
||||||
|
|
|
@ -90,49 +90,7 @@ module.exports =
|
||||||
redeemers.push({ date: new Date(), userID: user._id })
|
redeemers.push({ date: new Date(), userID: user._id })
|
||||||
prepaid.set('redeemers', redeemers)
|
prepaid.set('redeemers', redeemers)
|
||||||
res.status(201).send(prepaid.toObject({req: req}))
|
res.status(201).send(prepaid.toObject({req: req}))
|
||||||
|
|
||||||
|
|
||||||
revoke: wrap (req, res) ->
|
|
||||||
if not req.user?.isTeacher()
|
|
||||||
throw new errors.Forbidden('Must be a teacher to use enrollments')
|
|
||||||
|
|
||||||
prepaid = yield database.getDocFromHandle(req, Prepaid)
|
|
||||||
if not prepaid
|
|
||||||
throw new errors.NotFound('Prepaid not found.')
|
|
||||||
|
|
||||||
unless prepaid.get('creator').equals(req.user._id)
|
|
||||||
throw new errors.Forbidden('You may not revoke enrollments you do not own.')
|
|
||||||
unless prepaid.get('type') is 'course'
|
|
||||||
throw new errors.Forbidden('This prepaid is not of type "course".')
|
|
||||||
if prepaid.get('endDate') and new Date(prepaid.get('endDate')) < new Date()
|
|
||||||
throw new errors.Forbidden('This prepaid is expired.')
|
|
||||||
|
|
||||||
user = yield User.findById(req.body?.userID)
|
|
||||||
if not user
|
|
||||||
throw new errors.NotFound('User not found.')
|
|
||||||
|
|
||||||
if not user.isEnrolled()
|
|
||||||
throw new errors.UnprocessableEntity('User to revoke must be enrolled first.')
|
|
||||||
if not _.any(prepaid.get('redeemers'), (obj) -> obj.userID.equals(user._id))
|
|
||||||
throw new errors.UnprocessableEntity('User was not enrolled with this set of enrollments')
|
|
||||||
|
|
||||||
query =
|
|
||||||
_id: prepaid._id
|
|
||||||
'redeemers.userID': { $eq: user._id }
|
|
||||||
update = { $pull: { redeemers : { userID: user._id } }}
|
|
||||||
result = yield Prepaid.update(query, update)
|
|
||||||
if result.nModified is 0
|
|
||||||
@logError(req.user, "POST prepaid redeemer lost race on maxRedeemers")
|
|
||||||
throw new errors.UnprocessableEntity('User was not enrolled with this set of enrollments (race)')
|
|
||||||
|
|
||||||
user.set('coursePrepaid', undefined)
|
|
||||||
yield user.save()
|
|
||||||
|
|
||||||
# return prepaid with new redeemer added locally
|
|
||||||
prepaid.set('redeemers', _.filter(prepaid.get('redeemers') or [], (obj) -> not obj.userID.equals(user._id)))
|
|
||||||
res.status(200).send(prepaid.toObject({req: req}))
|
|
||||||
|
|
||||||
|
|
||||||
fetchByCreator: wrap (req, res, next) ->
|
fetchByCreator: wrap (req, res, next) ->
|
||||||
creator = req.query.creator
|
creator = req.query.creator
|
||||||
return next() if not creator
|
return next() if not creator
|
||||||
|
|
|
@ -91,7 +91,6 @@ module.exports.setup = (app) ->
|
||||||
app.get('/db/prepaid', mw.auth.checkLoggedIn(), mw.prepaids.fetchByCreator)
|
app.get('/db/prepaid', mw.auth.checkLoggedIn(), mw.prepaids.fetchByCreator)
|
||||||
app.post('/db/prepaid', mw.auth.checkHasPermission(['admin']), mw.prepaids.post)
|
app.post('/db/prepaid', mw.auth.checkHasPermission(['admin']), mw.prepaids.post)
|
||||||
app.post('/db/prepaid/:handle/redeemers', mw.prepaids.redeem)
|
app.post('/db/prepaid/:handle/redeemers', mw.prepaids.redeem)
|
||||||
app.delete('/db/prepaid/:handle/redeemers', mw.prepaids.revoke)
|
|
||||||
|
|
||||||
app.get '/db/products', require('./db/product').get
|
app.get '/db/products', require('./db/product').get
|
||||||
|
|
||||||
|
|
|
@ -113,25 +113,3 @@ describe 'TeacherClassView', ->
|
||||||
users = @view.enrollStudents.calls.argsFor(0)[0]
|
users = @view.enrollStudents.calls.argsFor(0)[0]
|
||||||
expect(users.size()).toBe(1)
|
expect(users.size()).toBe(1)
|
||||||
expect(users.first().id).toBe(@view.students.first().id)
|
expect(users.first().id).toBe(@view.students.first().id)
|
||||||
|
|
||||||
describe 'Revoke button', ->
|
|
||||||
it 'opens a confirm modal once clicked', ->
|
|
||||||
spyOn(window, 'confirm').and.returnValue(true)
|
|
||||||
@view.$('.revoke-student-button:first').click()
|
|
||||||
expect(window.confirm).toHaveBeenCalled()
|
|
||||||
|
|
||||||
describe 'once the prepaid is successfully revoked', ->
|
|
||||||
beforeEach ->
|
|
||||||
spyOn(window, 'confirm').and.returnValue(true)
|
|
||||||
button = @view.$('.revoke-student-button:first')
|
|
||||||
@revokedUser = @view.students.get(button.data('user-id'))
|
|
||||||
@view.$('.revoke-student-button:first').click()
|
|
||||||
request = jasmine.Ajax.requests.mostRecent()
|
|
||||||
request.respondWith({
|
|
||||||
status: 200
|
|
||||||
responseText: '{}'
|
|
||||||
})
|
|
||||||
|
|
||||||
it 'updates the user and rerenders the page', ->
|
|
||||||
if @view.$(".enroll-student-button[data-user-id='#{@revokedUser.id}']").length isnt 1
|
|
||||||
fail('Could not find enroll student button for user whose enrollment was revoked')
|
|
||||||
|
|
Loading…
Reference in a new issue