mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Fix bugquest bugs
Hide TeachersContactModal after sending message Fix GET /db/level/:handle/session, more extensively test Fix EnrollmentView number of students input to stop losing focus on input Fix EnrollmentsView syntax Fix ActivateLicensesModal "Get Enrollments" button when already in the enrollments page Update EnrollmentsView with new credit numbers when ActivateLicensesModal closes Hide search box in TeacherClassView "Enrollment Status" tab Tweak EnrollmentsView styling Fix EnrollmentsView tests Fix AnalyticsView Make EnrollmentsView more explicitly handle undefined and empty array prepaid groups Remove log CoursesView handles JoinClassModal cancel Re-enable EditStudentModal set password button when the form changes Fix course instance tests, next level endpoint bug Fix EditStudentModal tests
This commit is contained in:
parent
3d705e5d70
commit
8dbc86ca04
19 changed files with 111 additions and 46 deletions
|
@ -32,9 +32,9 @@
|
||||||
border-radius: 5px
|
border-radius: 5px
|
||||||
|
|
||||||
#students-input
|
#students-input
|
||||||
width: 180px
|
width: 220px
|
||||||
height: 80px
|
height: 80px
|
||||||
font-size: 60px
|
font-size: 50px
|
||||||
|
|
||||||
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button
|
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button
|
||||||
-webkit-appearance: none
|
-webkit-appearance: none
|
||||||
|
|
|
@ -48,14 +48,14 @@ block content
|
||||||
.row.m-t-3
|
.row.m-t-3
|
||||||
if anyPrepaids
|
if anyPrepaids
|
||||||
#prepaids-col.col-md-9
|
#prepaids-col.col-md-9
|
||||||
if available
|
if _.size(available) > 0
|
||||||
h5.m-b-1(data-i18n="teacher.available_credits")
|
h5.m-b-1(data-i18n="teacher.available_credits")
|
||||||
.row
|
.row
|
||||||
for prepaid in available
|
for prepaid in available
|
||||||
.col-sm-4.col-xs-6
|
.col-sm-4.col-xs-6
|
||||||
+prepaidCard(prepaid)
|
+prepaidCard(prepaid)
|
||||||
|
|
||||||
if pending
|
if _.size(pending) > 0
|
||||||
h5.m-b-1.m-t-3(data-i18n="teacher.pending_credits")
|
h5.m-b-1.m-t-3(data-i18n="teacher.pending_credits")
|
||||||
.row
|
.row
|
||||||
for prepaid in pending
|
for prepaid in pending
|
||||||
|
|
|
@ -378,14 +378,17 @@ mixin bulkAssignControls
|
||||||
span(data-i18n='teacher.enroll_selected_students')
|
span(data-i18n='teacher.enroll_selected_students')
|
||||||
|
|
||||||
mixin enrollmentStatusTab
|
mixin enrollmentStatusTab
|
||||||
form.form-inline.text-center.m-t-3
|
// TODO: Have search input in all tabs
|
||||||
#search-form-group.form-group
|
|
||||||
label(for="student-search") Search for student:
|
|
||||||
input#student-search.form-control.m-l-1(type="search")
|
|
||||||
span.glyphicon.glyphicon-search.form-control-feedback
|
|
||||||
|
|
||||||
table.table#enrollment-status-table.table-condensed
|
//form.form-inline.text-center.m-t-3
|
||||||
|
// #search-form-group.form-group
|
||||||
|
// label(for="student-search") Search for student:
|
||||||
|
// input#student-search.form-control.m-l-1(type="search")
|
||||||
|
// span.glyphicon.glyphicon-search.form-control-feedback
|
||||||
|
|
||||||
|
table.table#enrollment-status-table.table-condensed.m-t-3
|
||||||
thead
|
thead
|
||||||
|
// Checkbox code works, but don't need it yet.
|
||||||
//th.checkbox-col.select-all
|
//th.checkbox-col.select-all
|
||||||
.checkbox-flat
|
.checkbox-flat
|
||||||
input(type='checkbox' id='checkbox-all-students')
|
input(type='checkbox' id='checkbox-all-students')
|
||||||
|
|
|
@ -7,28 +7,28 @@ block modal-header-content
|
||||||
block modal-body-content
|
block modal-body-content
|
||||||
p Send us a message and our classroom success team will be in touch to help find the best solution for your students' needs!
|
p Send us a message and our classroom success team will be in touch to help find the best solution for your students' needs!
|
||||||
form
|
form
|
||||||
- var sending = view.state.get('sendingState') === 'sending';
|
- var sending = view.state.get('sendingState') === 'sending'
|
||||||
|
- var sent = view.state.get('sendingState') === 'sent';
|
||||||
- var values = view.state.get('formValues');
|
- var values = view.state.get('formValues');
|
||||||
- var errors = view.state.get('formErrors');
|
- var errors = view.state.get('formErrors');
|
||||||
|
|
||||||
.form-group(class=errors.email ? 'has-error' : '')
|
.form-group(class=errors.email ? 'has-error' : '')
|
||||||
label.control-label(for="email" data-i18n="general.email")
|
label.control-label(for="email" data-i18n="general.email")
|
||||||
+formErrors(errors.email)
|
+formErrors(errors.email)
|
||||||
input.form-control(name="email", type="email", value=values.email || '', tabindex=1, disabled=sending)
|
input.form-control(name="email", type="email", value=values.email || '', tabindex=1, disabled=sending || sent)
|
||||||
|
|
||||||
.form-group(class=errors.message ? 'has-error' : '')
|
.form-group(class=errors.message ? 'has-error' : '')
|
||||||
label.control-label(for="message" data-i18n="general.message")
|
label.control-label(for="message" data-i18n="general.message")
|
||||||
+formErrors(errors.message)
|
+formErrors(errors.message)
|
||||||
textarea.form-control(name="message", tabindex=1 disabled=sending)= values.message
|
textarea.form-control(name="message", tabindex=1 disabled=sending || sent)= values.message
|
||||||
|
|
||||||
if view.state.get('sendingState') === 'error'
|
if view.state.get('sendingState') === 'error'
|
||||||
.alert.alert-danger Could not send message.
|
.alert.alert-danger Could not send message.
|
||||||
|
|
||||||
if view.state.get('sendingState') === 'sent'
|
if sent
|
||||||
.alert.alert-success Message sent!
|
.alert.alert-success Message sent!
|
||||||
|
|
||||||
.text-right
|
.text-right
|
||||||
- var sent = view.state.get('sendingState') === 'sent';
|
|
||||||
button#submit-btn.btn.btn-navy.btn-lg(type='submit' disabled=sending || sent) Submit
|
button#submit-btn.btn.btn-navy.btn-lg(type='submit' disabled=sending || sent) Submit
|
||||||
|
|
||||||
block modal-footer
|
block modal-footer
|
||||||
|
|
|
@ -290,7 +290,7 @@ module.exports = class AnalyticsView extends RootView
|
||||||
prepaidUserMap = {}
|
prepaidUserMap = {}
|
||||||
for user in data.students
|
for user in data.students
|
||||||
continue unless studentPaidStatusMap[user._id]
|
continue unless studentPaidStatusMap[user._id]
|
||||||
if prepaidID = user.coursePrepaidID or user.course.coursePrepaid?._id # TODO: make sure this works for coursePrepaid
|
if prepaidID = user.coursePrepaidID or user.coursePrepaid?._id
|
||||||
studentPaidStatusMap[user._id] = 'paid'
|
studentPaidStatusMap[user._id] = 'paid'
|
||||||
prepaidUserMap[prepaidID] ?= []
|
prepaidUserMap[prepaidID] ?= []
|
||||||
prepaidUserMap[prepaidID].push(user._id)
|
prepaidUserMap[prepaidID].push(user._id)
|
||||||
|
|
|
@ -16,6 +16,7 @@ module.exports = class ActivateLicensesModal extends ModalView
|
||||||
'change input[type="checkbox"][name="user"]': 'updateSelectedStudents'
|
'change input[type="checkbox"][name="user"]': 'updateSelectedStudents'
|
||||||
'change select.classroom-select': 'replaceStudentList'
|
'change select.classroom-select': 'replaceStudentList'
|
||||||
'submit form': 'onSubmitForm'
|
'submit form': 'onSubmitForm'
|
||||||
|
'click #get-more-licenses-btn': 'onClickGetMoreLicensesButton'
|
||||||
|
|
||||||
getInitialState: (options) ->
|
getInitialState: (options) ->
|
||||||
selectedUsers = options.selectedUsers or options.users
|
selectedUsers = options.selectedUsers or options.users
|
||||||
|
@ -113,3 +114,6 @@ module.exports = class ActivateLicensesModal extends ModalView
|
||||||
|
|
||||||
finishRedeemUsers: ->
|
finishRedeemUsers: ->
|
||||||
@trigger 'redeem-users', @state.get('selectedUsers')
|
@trigger 'redeem-users', @state.get('selectedUsers')
|
||||||
|
|
||||||
|
onClickGetMoreLicensesButton: ->
|
||||||
|
@hide?() # In case this is opened in /teachers/enrollments itself, otherwise the button does nothing
|
||||||
|
|
|
@ -102,6 +102,9 @@ module.exports = class CoursesView extends RootView
|
||||||
@openModalView modal
|
@openModalView modal
|
||||||
@listenTo modal, 'join:success', @onJoinClassroomSuccess
|
@listenTo modal, 'join:success', @onJoinClassroomSuccess
|
||||||
@listenTo modal, 'join:error', @onJoinClassroomError
|
@listenTo modal, 'join:error', @onJoinClassroomError
|
||||||
|
@listenTo modal, 'hidden', ->
|
||||||
|
@state = null
|
||||||
|
@renderSelectors '#join-class-form'
|
||||||
|
|
||||||
onJoinClassroomError: (classroom, jqxhr, options) ->
|
onJoinClassroomError: (classroom, jqxhr, options) ->
|
||||||
@state = null
|
@state = null
|
||||||
|
|
|
@ -44,8 +44,9 @@ module.exports = class EnrollmentsView extends RootView
|
||||||
@prepaids.comparator = '_id'
|
@prepaids.comparator = '_id'
|
||||||
@supermodel.trackRequest @prepaids.fetchByCreator(me.id)
|
@supermodel.trackRequest @prepaids.fetchByCreator(me.id)
|
||||||
@debouncedRender = _.debounce @render, 0
|
@debouncedRender = _.debounce @render, 0
|
||||||
@listenTo @prepaids, 'all', -> @state.set('prepaidGroups', @prepaids.groupBy((p) -> p.status()))
|
@listenTo @prepaids, 'sync', @updatePrepaidGroups
|
||||||
@listenTo(@state, 'all', @debouncedRender)
|
@listenTo(@state, 'all', @debouncedRender)
|
||||||
|
@listenTo(me, 'change:enrollmentRequestSent', @debouncedRender)
|
||||||
|
|
||||||
onceClassroomsSync: ->
|
onceClassroomsSync: ->
|
||||||
for classroom in @classrooms.models
|
for classroom in @classrooms.models
|
||||||
|
@ -56,6 +57,9 @@ module.exports = class EnrollmentsView extends RootView
|
||||||
@state.set('totalCourses', @courses.size())
|
@state.set('totalCourses', @courses.size())
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
updatePrepaidGroups: ->
|
||||||
|
@state.set('prepaidGroups', @prepaids.groupBy((p) -> p.status()))
|
||||||
|
|
||||||
calculateEnrollmentStats: ->
|
calculateEnrollmentStats: ->
|
||||||
@removeDeletedStudents()
|
@removeDeletedStudents()
|
||||||
|
|
||||||
|
@ -95,10 +99,13 @@ module.exports = class EnrollmentsView extends RootView
|
||||||
if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input))
|
if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input))
|
||||||
@$('#students-input').val(@state.get('numberOfStudents'))
|
@$('#students-input').val(@state.get('numberOfStudents'))
|
||||||
else
|
else
|
||||||
@state.set('numberOfStudents', Math.max(parseInt(@$('#students-input').val()) or 0, 0))
|
@state.set({'numberOfStudents': Math.max(parseInt(@$('#students-input').val()) or 0, 0)}, {silent: true}) # do not re-render
|
||||||
|
|
||||||
numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000
|
numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000
|
||||||
|
|
||||||
onClickEnrollStudentsButton: ->
|
onClickEnrollStudentsButton: ->
|
||||||
modal = new ActivateLicensesModal({ selectedUsers: @notEnrolledUsers, users: @members })
|
modal = new ActivateLicensesModal({ selectedUsers: @notEnrolledUsers, users: @members })
|
||||||
@openModalView(modal)
|
@openModalView(modal)
|
||||||
|
modal.once 'hidden', =>
|
||||||
|
@prepaids.add(modal.prepaids.models, { merge: true })
|
||||||
|
@debouncedRender() # Because one changed model does not a collection update make
|
||||||
|
|
|
@ -272,7 +272,6 @@ module.exports = class TeacherClassView extends RootView
|
||||||
@students.sort()
|
@students.sort()
|
||||||
|
|
||||||
onKeyPressStudentSearch: (e) ->
|
onKeyPressStudentSearch: (e) ->
|
||||||
console.log 'emit event'
|
|
||||||
@state.set('searchTerm', $(e.target).val())
|
@state.set('searchTerm', $(e.target).val())
|
||||||
|
|
||||||
getSelectedStudentIDs: ->
|
getSelectedStudentIDs: ->
|
||||||
|
|
|
@ -37,4 +37,9 @@ module.exports = class EditStudentModal extends ModalView
|
||||||
@classroom.setStudentPassword(@user, @state.get('newPassword'))
|
@classroom.setStudentPassword(@user, @state.get('newPassword'))
|
||||||
|
|
||||||
onChangeNewPasswordInput: (e) ->
|
onChangeNewPasswordInput: (e) ->
|
||||||
@state.set { newPassword: $(e.currentTarget).val() }, { silent: true }
|
@state.set {
|
||||||
|
newPassword: $(e.currentTarget).val()
|
||||||
|
emailSent: false
|
||||||
|
passwordChanged: false
|
||||||
|
}, { silent: true }
|
||||||
|
@renderSelectors('.change-password-btn')
|
||||||
|
|
|
@ -10,7 +10,6 @@ module.exports = class TeachersContactModal extends ModalView
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'submit form': 'onSubmitForm'
|
'submit form': 'onSubmitForm'
|
||||||
'change form': 'onChangeForm'
|
|
||||||
|
|
||||||
initialize: (options={}) ->
|
initialize: (options={}) ->
|
||||||
@state = new State({
|
@state = new State({
|
||||||
|
@ -40,10 +39,6 @@ module.exports = class TeachersContactModal extends ModalView
|
||||||
@state.set('formValues', { email, message })
|
@state.set('formValues', { email, message })
|
||||||
super()
|
super()
|
||||||
|
|
||||||
onChangeForm: ->
|
|
||||||
# Want to re-render without losing form focus. TODO: figure out how in state system.
|
|
||||||
@$('#submit-btn').attr('disabled', false)
|
|
||||||
|
|
||||||
onSubmitForm: (e) ->
|
onSubmitForm: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return if @state.get('sendingState') is 'sending'
|
return if @state.get('sendingState') is 'sending'
|
||||||
|
@ -64,7 +59,12 @@ module.exports = class TeachersContactModal extends ModalView
|
||||||
contact.send({
|
contact.send({
|
||||||
data
|
data
|
||||||
context: @
|
context: @
|
||||||
success: -> @state.set({ sendingState: 'sent' })
|
success: ->
|
||||||
|
@state.set({ sendingState: 'sent' })
|
||||||
|
me.set('enrollmentRequestSent', true)
|
||||||
|
setTimeout(=>
|
||||||
|
@hide?()
|
||||||
|
, 3000)
|
||||||
error: -> @state.set({ sendingState: 'error' })
|
error: -> @state.set({ sendingState: 'error' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ module.exports =
|
||||||
throw new errors.NotFound('Level original ObjectId not found in Classroom courses')
|
throw new errors.NotFound('Level original ObjectId not found in Classroom courses')
|
||||||
|
|
||||||
if not nextLevelOriginal
|
if not nextLevelOriginal
|
||||||
res.status(200).send({})
|
return res.status(200).send({})
|
||||||
|
|
||||||
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
|
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
|
||||||
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
|
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
|
||||||
|
@ -137,7 +137,7 @@ module.exports =
|
||||||
for courseInstance in courseInstances
|
for courseInstance in courseInstances
|
||||||
if members = courseInstance.get('members')
|
if members = courseInstance.get('members')
|
||||||
userIDs.push(userID) for userID in members
|
userIDs.push(userID) for userID in members
|
||||||
users = yield User.find({_id: {$in: userIDs}}, {coursePrepaid: 1})
|
users = yield User.find({_id: {$in: userIDs}}, {coursePrepaid: 1, coursePrepaidID: 1})
|
||||||
|
|
||||||
prepaidIDs = []
|
prepaidIDs = []
|
||||||
for user in users
|
for user in users
|
||||||
|
|
|
@ -50,12 +50,13 @@ module.exports =
|
||||||
courseID = null
|
courseID = null
|
||||||
classroomMap = {}
|
classroomMap = {}
|
||||||
classroomMap[classroom.id] = classroom for classroom in classrooms
|
classroomMap[classroom.id] = classroom for classroom in classrooms
|
||||||
|
levelOriginal = level.get('original')
|
||||||
for courseInstance in courseInstances
|
for courseInstance in courseInstances
|
||||||
classroom = classroomMap[courseInstance.get('classroomID').toString()]
|
classroom = classroomMap[courseInstance.get('classroomID').toString()]
|
||||||
courseID = courseInstance.get('courseID')
|
courseID = courseInstance.get('courseID')
|
||||||
classroomCourse = _.find(classroom.get('courses'), (c) -> c._id.equals(courseID))
|
classroomCourse = _.find(classroom.get('courses'), (c) -> c._id.equals(courseID))
|
||||||
for courseLevel in classroomCourse.levels
|
for courseLevel in classroomCourse.levels
|
||||||
if courseLevel.original.equals(level._id)
|
if courseLevel.original.equals(levelOriginal)
|
||||||
classroomWithLevel = classroom
|
classroomWithLevel = classroom
|
||||||
break
|
break
|
||||||
break if classroomWithLevel
|
break if classroomWithLevel
|
||||||
|
@ -67,7 +68,7 @@ module.exports =
|
||||||
unless course.get('free') or req.user.isEnrolled()
|
unless course.get('free') or req.user.isEnrolled()
|
||||||
throw new errors.PaymentRequired('You must be enrolled to access this content')
|
throw new errors.PaymentRequired('You must be enrolled to access this content')
|
||||||
|
|
||||||
lang = classroomWithLevel.get('aceConfig').language
|
lang = classroomWithLevel.get('aceConfig')?.language
|
||||||
attrs.codeLanguage = lang if lang
|
attrs.codeLanguage = lang if lang
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
|
@ -73,7 +73,7 @@ module.exports.setup = (app) ->
|
||||||
app.get('/db/course/:handle', mw.rest.getByHandle(Course))
|
app.get('/db/course/:handle', mw.rest.getByHandle(Course))
|
||||||
app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel)
|
app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel)
|
||||||
|
|
||||||
app.get('/db/course_instance/-/recent', mw.auth.checkHasPermission(['admin']), mw.courseInstances.fetchRecent)
|
app.post('/db/course_instance/-/recent', mw.auth.checkHasPermission(['admin']), mw.courseInstances.fetchRecent)
|
||||||
app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel)
|
app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel)
|
||||||
app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers)
|
app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers)
|
||||||
app.get('/db/course_instance/:handle/classroom', mw.auth.checkLoggedIn(), mw.courseInstances.fetchClassroom)
|
app.get('/db/course_instance/:handle/classroom', mw.auth.checkLoggedIn(), mw.courseInstances.fetchClassroom)
|
||||||
|
|
|
@ -361,7 +361,7 @@ describe 'GET /db/course_instance/:handle/classroom', ->
|
||||||
expect(res.statusCode).toBe(403)
|
expect(res.statusCode).toBe(403)
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe 'GET /db/course_instance/-/recent', ->
|
describe 'POST /db/course_instance/-/recent', ->
|
||||||
|
|
||||||
url = getURL('/db/course_instance/-/recent')
|
url = getURL('/db/course_instance/-/recent')
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ describe 'GET /db/course_instance/-/recent', ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'returns all non-HoC course instances and their related users and prepaids', utils.wrap (done) ->
|
it 'returns all non-HoC course instances and their related users and prepaids', utils.wrap (done) ->
|
||||||
[res, body] = yield request.getAsync(url, { json: true })
|
[res, body] = yield request.postAsync(url, { json: true })
|
||||||
expect(res.statusCode).toBe(200)
|
expect(res.statusCode).toBe(200)
|
||||||
expect(res.body.courseInstances[0]._id).toBe(@courseInstance.id)
|
expect(res.body.courseInstances[0]._id).toBe(@courseInstance.id)
|
||||||
expect(res.body.students[0]._id).toBe(@student.id)
|
expect(res.body.students[0]._id).toBe(@student.id)
|
||||||
|
@ -393,23 +393,23 @@ describe 'GET /db/course_instance/-/recent', ->
|
||||||
it 'returns course instances within a specified range', utils.wrap (done) ->
|
it 'returns course instances within a specified range', utils.wrap (done) ->
|
||||||
startDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
|
startDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
|
||||||
endDay = moment().add(1, 'day').format('YYYY-MM-DD')
|
endDay = moment().add(1, 'day').format('YYYY-MM-DD')
|
||||||
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } })
|
[res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
|
||||||
expect(res.body.courseInstances.length).toBe(1)
|
expect(res.body.courseInstances.length).toBe(1)
|
||||||
|
|
||||||
startDay = moment().add(1, 'day').format('YYYY-MM-DD')
|
startDay = moment().add(1, 'day').format('YYYY-MM-DD')
|
||||||
endDay = moment().add(2, 'day').format('YYYY-MM-DD')
|
endDay = moment().add(2, 'day').format('YYYY-MM-DD')
|
||||||
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } })
|
[res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
|
||||||
expect(res.body.courseInstances.length).toBe(0)
|
expect(res.body.courseInstances.length).toBe(0)
|
||||||
|
|
||||||
startDay = moment().subtract(2, 'day').format('YYYY-MM-DD')
|
startDay = moment().subtract(2, 'day').format('YYYY-MM-DD')
|
||||||
endDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
|
endDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
|
||||||
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } })
|
[res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
|
||||||
expect(res.body.courseInstances.length).toBe(0)
|
expect(res.body.courseInstances.length).toBe(0)
|
||||||
|
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'returns 403 if not an admin', utils.wrap (done) ->
|
it 'returns 403 if not an admin', utils.wrap (done) ->
|
||||||
yield utils.loginUser(@teacher)
|
yield utils.loginUser(@teacher)
|
||||||
[res, body] = yield request.getAsync(url, { json: true })
|
[res, body] = yield request.postAsync(url, { json: true })
|
||||||
expect(res.statusCode).toBe(403)
|
expect(res.statusCode).toBe(403)
|
||||||
done()
|
done()
|
||||||
|
|
|
@ -8,6 +8,7 @@ User = require '../../../server/models/User'
|
||||||
request = require '../request'
|
request = require '../request'
|
||||||
utils = require '../utils'
|
utils = require '../utils'
|
||||||
moment = require 'moment'
|
moment = require 'moment'
|
||||||
|
mongoose = require 'mongoose'
|
||||||
|
|
||||||
describe 'Level', ->
|
describe 'Level', ->
|
||||||
|
|
||||||
|
@ -42,13 +43,18 @@ describe 'Level', ->
|
||||||
|
|
||||||
describe 'GET /db/level/:handle/session', ->
|
describe 'GET /db/level/:handle/session', ->
|
||||||
|
|
||||||
describe 'when level is a course level', ->
|
describe 'when level IS a course level', ->
|
||||||
|
|
||||||
beforeEach utils.wrap (done) ->
|
beforeEach utils.wrap (done) ->
|
||||||
yield utils.clearModels([Campaign, Course, CourseInstance, Level, User])
|
yield utils.clearModels([Campaign, Course, CourseInstance, Level, User])
|
||||||
admin = yield utils.initAdmin()
|
admin = yield utils.initAdmin()
|
||||||
yield utils.loginUser(admin)
|
yield utils.loginUser(admin)
|
||||||
@level = yield utils.makeLevel({type: 'course'})
|
@level = yield utils.makeLevel({type: 'course'})
|
||||||
|
|
||||||
|
# To ensure test compares original, not id, make them different. TODO: Make factories do this normally?
|
||||||
|
@level.set('original', new mongoose.Types.ObjectId())
|
||||||
|
@level.save()
|
||||||
|
|
||||||
@campaign = yield utils.makeCampaign({}, {levels: [@level]})
|
@campaign = yield utils.makeCampaign({}, {levels: [@level]})
|
||||||
@course = yield utils.makeCourse({free: true}, {campaign: @campaign})
|
@course = yield utils.makeCourse({free: true}, {campaign: @campaign})
|
||||||
@student = yield utils.initUser({role: 'student'})
|
@student = yield utils.initUser({role: 'student'})
|
||||||
|
@ -67,6 +73,14 @@ describe 'GET /db/level/:handle/session', ->
|
||||||
expect(body.codeLanguage).toBe('javascript')
|
expect(body.codeLanguage).toBe('javascript')
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it 'works if the classroom has no aceConfig', utils.wrap (done) ->
|
||||||
|
@classroom.set('aceConfig', undefined)
|
||||||
|
yield @classroom.save()
|
||||||
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
|
expect(res.statusCode).toBe(200)
|
||||||
|
expect(body.codeLanguage).toBe('python')
|
||||||
|
done()
|
||||||
|
|
||||||
it 'returns 402 if the user is not in a course with that level', utils.wrap (done) ->
|
it 'returns 402 if the user is not in a course with that level', utils.wrap (done) ->
|
||||||
otherStudent = yield utils.initUser({role: 'student'})
|
otherStudent = yield utils.initUser({role: 'student'})
|
||||||
yield utils.loginUser(otherStudent)
|
yield utils.loginUser(otherStudent)
|
||||||
|
@ -136,3 +150,31 @@ describe 'GET /db/level/:handle/session', ->
|
||||||
[res, body] = yield request.getAsync { uri: @url, json: true }
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
expect(body._id).toBe(sessionID)
|
expect(body._id).toBe(sessionID)
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
describe 'when the level is not free', ->
|
||||||
|
beforeEach utils.wrap (done) ->
|
||||||
|
yield @level.update({$set: {requiresSubscription: true}})
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'returns 402 for normal users', utils.wrap (done) ->
|
||||||
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
|
expect(res.statusCode).toBe(402)
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'returns 200 for admins', utils.wrap (done) ->
|
||||||
|
yield @player.update({$set: {permissions: ['admin']}})
|
||||||
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
|
expect(res.statusCode).toBe(200)
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'returns 200 for adventurer levels', utils.wrap (done) ->
|
||||||
|
yield @level.update({$set: {adventurer: true}})
|
||||||
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
|
expect(res.statusCode).toBe(200)
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'returns 200 for subscribed users', utils.wrap (done) ->
|
||||||
|
yield @player.update({$set: {stripe: {free: true}}})
|
||||||
|
[res, body] = yield request.getAsync { uri: @url, json: true }
|
||||||
|
expect(res.statusCode).toBe(200)
|
||||||
|
done()
|
||||||
|
|
|
@ -11,6 +11,7 @@ describe 'EnrollmentsView', ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
me.set('anonymous', false)
|
me.set('anonymous', false)
|
||||||
me.set('role', 'teacher')
|
me.set('role', 'teacher')
|
||||||
|
me.set('enrollmentRequestSent', false)
|
||||||
@view = new EnrollmentsView()
|
@view = new EnrollmentsView()
|
||||||
|
|
||||||
# Make three classrooms, sharing users from a pool of 10, 5 of which are enrolled
|
# Make three classrooms, sharing users from a pool of 10, 5 of which are enrolled
|
||||||
|
@ -92,7 +93,8 @@ describe 'EnrollmentsView', ->
|
||||||
|
|
||||||
describe 'when there are no prepaids to show', ->
|
describe 'when there are no prepaids to show', ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
@view.prepaids.reset()
|
@view.prepaids.reset([])
|
||||||
|
@view.updatePrepaidGroups()
|
||||||
_.defer(done)
|
_.defer(done)
|
||||||
|
|
||||||
it 'fills the void with the rest of the page content', ->
|
it 'fills the void with the rest of the page content', ->
|
||||||
|
|
|
@ -45,9 +45,6 @@ describe 'TeachersContactModal', ->
|
||||||
it 'shows a success message', ->
|
it 'shows a success message', ->
|
||||||
expect(@modal.$('.alert-success').length).toBe(1)
|
expect(@modal.$('.alert-success').length).toBe(1)
|
||||||
|
|
||||||
describe 'submit button', ->
|
it 'disables the submit button', ->
|
||||||
it 'is disabled until one of the inputs changes', ->
|
|
||||||
expect(@modal.$('#submit-btn').is(':disabled')).toBe(true)
|
expect(@modal.$('#submit-btn').is(':disabled')).toBe(true)
|
||||||
@modal.$('input[name="email"]').trigger('change')
|
|
||||||
expect(@modal.$('#submit-btn').is(':disabled')).toBe(false)
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ describe 'EditStudentModal', ->
|
||||||
describe 'for a verified user', ->
|
describe 'for a verified user', ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
user = factories.makeUser({ email, emailVerified: true })
|
user = factories.makeUser({ email, emailVerified: true })
|
||||||
modal = new EditStudentModal({ user })
|
classroom = factories.makeClassroom()
|
||||||
|
modal = new EditStudentModal({ user, classroom })
|
||||||
request = jasmine.Ajax.requests.mostRecent()
|
request = jasmine.Ajax.requests.mostRecent()
|
||||||
request.respondWith({ status: 200, responseText: JSON.stringify(user) })
|
request.respondWith({ status: 200, responseText: JSON.stringify(user) })
|
||||||
jasmine.demoModal(modal)
|
jasmine.demoModal(modal)
|
||||||
|
@ -37,7 +38,8 @@ describe 'EditStudentModal', ->
|
||||||
describe 'for an unverified user', ->
|
describe 'for an unverified user', ->
|
||||||
beforeEach (done) ->
|
beforeEach (done) ->
|
||||||
user = factories.makeUser({ email , emailVerified: false })
|
user = factories.makeUser({ email , emailVerified: false })
|
||||||
modal = new EditStudentModal({ user })
|
classroom = factories.makeClassroom()
|
||||||
|
modal = new EditStudentModal({ user, classroom })
|
||||||
request = jasmine.Ajax.requests.mostRecent()
|
request = jasmine.Ajax.requests.mostRecent()
|
||||||
request.respondWith({ status: 200, responseText: JSON.stringify(user) })
|
request.respondWith({ status: 200, responseText: JSON.stringify(user) })
|
||||||
jasmine.demoModal(modal)
|
jasmine.demoModal(modal)
|
||||||
|
|
Loading…
Reference in a new issue