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"
|
||||
latest_complete: "Latest completed level"
|
||||
enroll_student: "Enroll student"
|
||||
revoke_enrollment: "Revoke Enrollment"
|
||||
adding_students: "Adding students"
|
||||
course_progress: "Course Progress"
|
||||
not_applicable: "N/A"
|
||||
|
@ -1438,8 +1437,6 @@
|
|||
status_expired: "Expired on {{date}}"
|
||||
status_not_enrolled: "Not Enrolled"
|
||||
status_enrolled: "Expires on {{date}}"
|
||||
revoke_confirm: "Are you sure you want to revoke enrollment from {{student_name}}?"
|
||||
revoking: "Revoking..."
|
||||
|
||||
classes:
|
||||
archmage_title: "Archmage"
|
||||
|
|
|
@ -40,10 +40,3 @@ module.exports = class Prepaid extends CocoModel
|
|||
options.data ?= {}
|
||||
options.data.userID = user.id or user
|
||||
@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
|
||||
.enroll-col
|
||||
width: 140px
|
||||
.revoke-col
|
||||
width: 170px
|
||||
td
|
||||
vertical-align: middle
|
||||
|
|
|
@ -419,6 +419,3 @@ mixin enrollmentStatusTab
|
|||
td.enroll-col
|
||||
if status !== 'enrolled'
|
||||
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 .assign-student-button': 'onClickAssignStudentButton'
|
||||
'click .enroll-student-button': 'onClickEnrollStudentButton'
|
||||
'click .revoke-student-button': 'onClickRevokeStudentButton'
|
||||
'click .assign-to-selected-students': 'onClickBulkAssign'
|
||||
'click .enroll-selected-students': 'onClickBulkEnroll'
|
||||
'click .export-student-progress-btn': 'onClickExportStudentProgress'
|
||||
|
@ -372,23 +371,6 @@ module.exports = class TeacherClassView extends RootView
|
|||
}
|
||||
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) ->
|
||||
e.preventDefault()
|
||||
checkboxes = @$('.student-checkbox input')
|
||||
|
|
|
@ -90,49 +90,7 @@ module.exports =
|
|||
redeemers.push({ date: new Date(), userID: user._id })
|
||||
prepaid.set('redeemers', redeemers)
|
||||
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) ->
|
||||
creator = req.query.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.post('/db/prepaid', mw.auth.checkHasPermission(['admin']), mw.prepaids.post)
|
||||
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
|
||||
|
||||
|
|
|
@ -113,25 +113,3 @@ describe 'TeacherClassView', ->
|
|||
users = @view.enrollStudents.calls.argsFor(0)[0]
|
||||
expect(users.size()).toBe(1)
|
||||
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