def test_has_instructors(self, client, admin_session): """Admins can see instructor changes that might disrupt scheduled recordings.""" with test_approvals_workflow(app): meeting_days, meeting_start_time, meeting_end_time = SisSection.get_meeting_times( term_id=self.term_id, section_id=section_3_id, ) instructor_uids = SisSection.get_instructor_uids(term_id=self.term_id, section_id=section_3_id) Scheduled.create( cross_listed_section_ids=[], instructor_uids=instructor_uids + ['999999'], meeting_days=meeting_days, meeting_start_time=meeting_start_time, meeting_end_time=meeting_end_time, publish_type_='canvas', recording_type_='presenter_audio', room_id=Room.get_room_id(section_id=section_3_id, term_id=self.term_id), section_id=section_3_id, term_id=self.term_id, ) std_commit(allow_test_environment=True) api_json = self._api_course_changes(client, term_id=self.term_id) course = _find_course(api_json=api_json, section_id=section_3_id) assert course assert course['scheduled']['hasObsoleteRoom'] is False assert course['scheduled']['hasObsoleteMeetingTimes'] is False assert course['scheduled']['hasObsoleteInstructors'] is True
def unschedule(): params = request.get_json() term_id = params.get('termId') section_id = params.get('sectionId') course = SisSection.get_course(term_id, section_id, include_deleted=True) if (term_id and section_id) else None if not course: raise BadRequestError('Required params missing or invalid') if not (course['scheduled'] or course['hasNecessaryApprovals']): raise BadRequestError(f'Section id {section_id}, term id {term_id} is not currently scheduled or queued for scheduling') Approval.delete(term_id=term_id, section_id=section_id) Scheduled.delete(term_id=term_id, section_id=section_id) event_id = (course.get('scheduled') or {}).get('kalturaScheduleId') if event_id: try: Kaltura().delete(event_id) except (KalturaClientException, KalturaException) as e: message = f'Failed to delete Kaltura schedule: {event_id}' app.logger.error(message) app.logger.exception(e) send_system_error_email( message=f'{message}\n\n<pre>{traceback.format_exc()}</pre>', subject=message, ) CoursePreference.update_opt_out( term_id=term_id, section_id=section_id, opt_out=True, ) return tolerant_jsonify(SisSection.get_course(term_id, section_id, include_deleted=True))
def _load_courses(): term_id = app.config['CURRENT_TERM_ID'] with open(f"{app.config['BASE_DIR']}/fixtures/sis/courses.json", 'r') as file: sis_sections = json.loads(file.read()) SisSection.refresh(sis_sections=sis_sections, term_id=term_id) std_commit(allow_test_environment=True) _load_supplemental_course_data(term_id=term_id)
def approve(): term_id = app.config['CURRENT_TERM_ID'] term_name = term_name_for_sis_id(term_id) params = request.get_json() publish_type = params.get('publishType') recording_type = params.get('recordingType') section_id = params.get('sectionId') course = SisSection.get_course(term_id, section_id) if section_id else None if not course or publish_type not in get_all_publish_types() or recording_type not in get_all_recording_types(): raise BadRequestError('One or more required params are missing or invalid') if not current_user.is_admin and current_user.uid not in [i['uid'] for i in course['instructors']]: raise ForbiddenRequestError('Sorry, request unauthorized') if Approval.get_approval(approved_by_uid=current_user.uid, section_id=section_id, term_id=term_id): raise ForbiddenRequestError(f'You have already approved recording of {course["courseName"]}, {term_name}') meetings = course.get('meetings', {}).get('eligible', []) if len(meetings) != 1: raise BadRequestError('Unique eligible meeting pattern not found for course') meeting = meetings[0] location = meeting and meeting.get('location') room = Room.find_room(location=location) if not room: raise BadRequestError(f'{location} is not eligible for Course Capture.') previous_approvals = Approval.get_approvals_per_section_ids(section_ids=[section_id], term_id=term_id) approval = Approval.create( approved_by_uid=current_user.uid, approver_type_='admin' if current_user.is_admin else 'instructor', course_display_name=course['label'], publish_type_=publish_type, recording_type_=recording_type, room_id=room.id, section_id=section_id, term_id=term_id, ) if previous_approvals: # Compare the current approval with preferences submitted in previous approval previous_approval = previous_approvals[-1] if (approval.publish_type, approval.recording_type) != (previous_approval.publish_type, previous_approval.recording_type): notify_instructors_of_changes(course, approval, previous_approvals) all_approvals = previous_approvals + [approval] if len(course['instructors']) > len(all_approvals): approval_uids = [a.approved_by_uid for a in all_approvals] pending_instructors = [i for i in course['instructors'] if i['uid'] not in approval_uids] last_approver = next((i for i in course['instructors'] if i['uid'] == approval.approved_by_uid), None) if last_approver: notify_instructor_waiting_for_approval(course, last_approver, pending_instructors) return tolerant_jsonify(_after_approval(course=SisSection.get_course(term_id, section_id)))
def _run(self): self.term_id = app.config['CURRENT_TERM_ID'] self.courses = SisSection.get_course_changes(term_id=self.term_id) self._date_change_alerts() self._instructor_change_alerts() self._multiple_meeting_pattern_alerts() self._room_change_alerts()
def _assert_schedule_is_obsolete( self, expect_obsolete_dates, expect_obsolete_times, meeting, override_days=None, override_end_date=None, override_end_time=None, override_start_date=None, override_start_time=None, ): with test_approvals_workflow(app): with override_config(app, 'CURRENT_TERM_RECORDINGS_BEGIN', meeting['startDate']): with override_config(app, 'CURRENT_TERM_RECORDINGS_END', meeting['endDate']): mock_scheduled( meeting=meeting, override_days=override_days, override_end_date=override_end_date, override_end_time=override_end_time, override_start_date=override_start_date, override_start_time=override_start_time, section_id=self.section_id, term_id=self.term_id, ) course = SisSection.get_course(section_id=self.section_id, term_id=self.term_id) scheduled = course['scheduled'] assert are_scheduled_dates_obsolete(meeting=meeting, scheduled=scheduled) is expect_obsolete_dates assert are_scheduled_times_obsolete(meeting=meeting, scheduled=scheduled) is expect_obsolete_times
def test_admin_approval(self): """Course is scheduled for recording if an admin user has approved.""" with test_approvals_workflow(app): section_id = 50005 term_id = app.config['CURRENT_TERM_ID'] course = SisSection.get_course(section_id=section_id, term_id=term_id) instructors = course['instructors'] assert len(instructors) == 2 # Verify that course is not scheduled assert Scheduled.get_scheduled(section_id=section_id, term_id=term_id) is None Approval.create( approved_by_uid=admin_uid, approver_type_='admin', course_display_name=course['label'], publish_type_='kaltura_my_media', recording_type_='presentation_audio', room_id=Room.find_room('Barker 101').id, section_id=section_id, term_id=term_id, ) KalturaJob(simply_yield).run() std_commit(allow_test_environment=True) # Admin approval is all we need. assert Scheduled.get_scheduled(section_id=section_id, term_id=term_id)
def test_currently_no_person_teaching_course(self): """If course does not have a proper instructor then the email remains queued.""" def _emails_sent(): return _get_emails_sent(email_template_type=email_template_type, section_id=section_id, term_id=term_id) term_id = app.config['CURRENT_TERM_ID'] section_id = 22460 email_template_type = 'invitation' # Courses with no proper instructor are excluded from query results. assert not SisSection.get_course(term_id=term_id, section_id=section_id) queued_email = QueuedEmail.create(section_id, email_template_type, term_id) std_commit(allow_test_environment=True) emails_sent_before = _emails_sent() # Run the job QueuedEmailsJob(app.app_context).run() std_commit(allow_test_environment=True) # Expect no email sent emails_sent_after = _emails_sent() assert len(emails_sent_after) == len(emails_sent_before) # Assert that email is still queued assert section_id in QueuedEmail.get_all_section_ids( template_type=email_template_type, term_id=term_id) # Clean up QueuedEmail.delete(queued_email)
def _run(self, args=None): term_id = app.config['CURRENT_TERM_ID'] for queued_email in QueuedEmail.get_all(term_id): course = SisSection.get_course(term_id, queued_email.section_id, include_deleted=True) if not course: app.logger.warn( f'Email will remain queued until course data is present: {queued_email}' ) continue if course['hasOptedOut']: QueuedEmail.delete(queued_email) continue if BConnected().send( message=queued_email.message, recipient=queued_email.recipient, section_id=queued_email.section_id, subject_line=queued_email.subject_line, template_type=queued_email.template_type, term_id=term_id, ): QueuedEmail.delete(queued_email) else: # If send() fails then report the error and DO NOT delete the queued item. app.logger.error(f'Failed to send email: {queued_email}')
def _update_already_scheduled_events(): kaltura = Kaltura() for course in SisSection.get_courses_scheduled( term_id=app.config['CURRENT_TERM_ID']): course_name = course['label'] scheduled = course['scheduled'] kaltura_schedule = kaltura.get_event( event_id=scheduled['kalturaScheduleId']) if kaltura_schedule: if course['canvasCourseSites'] and scheduled[ 'publishType'] == 'kaltura_media_gallery': # From Kaltura, get Canvas course sites (categories) currently mapped to the course. template_entry_id = kaltura_schedule['templateEntryId'] categories = kaltura.get_categories(template_entry_id) for s in course['canvasCourseSites']: canvas_course_site_id = str(s['courseSiteId']) if canvas_course_site_id not in [ c['name'] for c in categories ]: _update_kaltura_category(canvas_course_site_id, course_name, kaltura, template_entry_id) else: app.logger.warn( f'The previously scheduled {course_name} has no schedule_event in Kaltura.' )
def test_email_template(template_id): email_template = EmailTemplate.get_template(template_id) if email_template: course = SisSection.get_course(term_id=app.config['CURRENT_TERM_ID'], section_id='12597') template = EmailTemplate.get_template(template_id) subject_line = interpolate_email_content( course=course, recipient_name=current_user.name, templated_string=template.subject_line, ) message = interpolate_email_content( course=course, recipient_name=current_user.name, templated_string=template.message, ) BConnected().send( recipients=[ { 'email': current_user.email_address, 'name': current_user.name, 'uid': current_user.uid, }, ], message=message, subject_line=subject_line, ) return tolerant_jsonify( {'message': f'Email sent to {current_user.email_address}'}), 200 else: raise ResourceNotFoundError('No such email_template')
def get_courses_ready_to_schedule(approvals, term_id): ready_to_schedule = [] scheduled_section_ids = [ s.section_id for s in Scheduled.get_all_scheduled(term_id=term_id) ] unscheduled_approvals = [ approval for approval in approvals if approval.section_id not in scheduled_section_ids ] if unscheduled_approvals: courses = SisSection.get_courses( section_ids=[a.section_id for a in unscheduled_approvals], term_id=term_id) courses_per_section_id = dict( (int(course['sectionId']), course) for course in courses) admin_user_uids = set([ user.uid for user in AdminUser.all_admin_users(include_deleted=True) ]) for section_id, uids in _get_uids_per_section_id( approvals=unscheduled_approvals).items(): if admin_user_uids.intersection(set(uids)): ready_to_schedule.append(courses_per_section_id[section_id]) else: course = courses_per_section_id[section_id] necessary_uids = [i['uid'] for i in course['instructors']] if all(uid in uids for uid in necessary_uids): ready_to_schedule.append( courses_per_section_id[section_id]) return ready_to_schedule
def refresh_rooms(): locations = SisSection.get_distinct_meeting_locations() existing_locations = Room.get_all_locations() new_locations = [ location for location in locations if location not in existing_locations ] if new_locations: app.logger.info(f'Creating {len(new_locations)} new rooms') for location in new_locations: Room.create(location=location) def _normalize(room_location): return re.sub(r'[\W_]+', '', room_location).lower() kaltura_resource_ids_per_room = {} all_rooms = Room.all_rooms() for resource in Kaltura().get_schedule_resources(): location = _normalize(resource['name']) if location: for room in all_rooms: if _normalize(room.location) == location: kaltura_resource_ids_per_room[room.id] = resource['id'] break if kaltura_resource_ids_per_room: Room.update_kaltura_resource_mappings(kaltura_resource_ids_per_room)
def test_admin_approval(self): """Course is scheduled for recording if an admin user has approved.""" with test_approvals_workflow(app): section_id = 22287 term_id = app.config['CURRENT_TERM_ID'] course = SisSection.get_course(section_id=section_id, term_id=term_id) instructors = course['instructors'] assert len(instructors) == 2 # Verify that course is not scheduled assert Scheduled.get_scheduled(section_id=section_id, term_id=term_id) is None Approval.create( approved_by_uid=admin_uid, approver_type_='admin', cross_listed_section_ids=[], publish_type_='canvas', recording_type_='presentation_audio', room_id=Room.find_room('Barker 101').id, section_id=section_id, term_id=term_id, ) KalturaJob(app.app_context).run() std_commit(allow_test_environment=True) # Admin approval is all we need. assert Scheduled.get_scheduled(section_id=section_id, term_id=term_id)
def test_email_template(template_id): email_template = EmailTemplate.get_template(template_id) if email_template: course = SisSection.get_random_co_taught_course(app.config['CURRENT_TERM_ID']) template = EmailTemplate.get_template(template_id) publish_types = get_all_publish_types() recording_types = get_all_recording_types() def _get_interpolated_content(templated_string): return interpolate_content( course=course, pending_instructors=course['instructors'], previous_publish_type_name=NAMES_PER_PUBLISH_TYPE[publish_types[0]], previous_recording_type_name=NAMES_PER_RECORDING_TYPE[recording_types[0]], publish_type_name=NAMES_PER_PUBLISH_TYPE[publish_types[1]], recording_type_name=NAMES_PER_RECORDING_TYPE[recording_types[1]], recipient_name=current_user.name, templated_string=templated_string, ) BConnected().send( recipient={ 'email': current_user.email_address, 'name': current_user.name, 'uid': current_user.uid, }, message=_get_interpolated_content(template.message), subject_line=_get_interpolated_content(template.subject_line), ) return tolerant_jsonify({'message': f'Email sent to {current_user.email_address}'}), 200 else: raise ResourceNotFoundError('No such email_template')
def _room_change_alert(self): template_type = 'room_change_no_longer_eligible' all_scheduled = list( filter( lambda s: template_type not in (s.alerts or []), Scheduled.get_all_scheduled(term_id=self.term_id), ), ) if all_scheduled: email_template = EmailTemplate.get_template_by_type(template_type) courses = SisSection.get_courses( term_id=self.term_id, section_ids=[s.section_id for s in all_scheduled], include_deleted=True, ) courses_per_section_id = dict( (course['sectionId'], course) for course in courses) for scheduled in all_scheduled: course = courses_per_section_id.get(scheduled.section_id) if course: if self._has_moved_to_ineligible_room( course, scheduled) or course['deletedAt']: if email_template: for instructor in course['instructors']: def _get_interpolate_content(template): return interpolate_content( course=course, publish_type_name=course.get( 'scheduled', {}).get('publishTypeName'), recipient_name=instructor['name'], recording_type_name=course.get( 'scheduled', {}).get('recordingTypeName'), templated_string=template, ) QueuedEmail.create( message=_get_interpolate_content( email_template.message), recipient=instructor, section_id=course['sectionId'], subject_line=_get_interpolate_content( email_template.subject_line), template_type=template_type, term_id=self.term_id, ) Scheduled.add_alert( scheduled_id=course['scheduled']['id'], template_type=template_type) else: send_system_error_email(f""" No '{template_type}' email template available. We are unable to notify {course['label']} instructors of room change. """) else: subject = f'Scheduled course has no SIS data (section_id={scheduled.section_id})' message = f'{subject}\n\nScheduled:<pre>{scheduled}</pre>' app.logger.error(message) send_system_error_email(message=message, subject=subject)
def test_admin_alert_multiple_meeting_patterns(self): """Emails admin if course is scheduled with weird start/end dates.""" with test_approvals_workflow(app): with enabled_job(job_key=AdminEmailsJob.key()): term_id = app.config['CURRENT_TERM_ID'] section_id = 50014 room_id = Room.find_room('Barker 101').id # The course has two instructors. instructor_uid = get_instructor_uids(section_id=section_id, term_id=term_id)[0] approval = Approval.create( approved_by_uid=instructor_uid, approver_type_='instructor', publish_type_='kaltura_my_media', recording_type_='presenter_audio', room_id=room_id, section_id=section_id, term_id=term_id, ) # Uh oh! Only one of them has been scheduled. meeting = get_eligible_meeting(section_id=section_id, term_id=term_id) Scheduled.create( instructor_uids=[instructor_uid], kaltura_schedule_id=random.randint(1, 10), meeting_days=meeting['days'], meeting_end_date=get_recording_end_date(meeting), meeting_end_time=meeting['endTime'], meeting_start_date=get_recording_start_date( meeting, return_today_if_past_start=True), meeting_start_time=meeting['startTime'], publish_type_=approval.publish_type, recording_type_=approval.recording_type, room_id=room_id, section_id=section_id, term_id=term_id, ) courses = SisSection.get_courses_scheduled_nonstandard_dates( term_id=term_id) course = next( (c for c in courses if c['sectionId'] == section_id), None) assert course # Message queued but not sent. admin_uid = app.config['EMAIL_DIABLO_ADMIN_UID'] AdminEmailsJob(simply_yield).run() queued_messages = QueuedEmail.query.filter_by( section_id=section_id).all() assert len(queued_messages) == 1 for queued_message in queued_messages: assert '2020-08-26 to 2020-10-02' in queued_message.message # Message sent. QueuedEmailsJob(simply_yield).run() emails_sent = SentEmail.get_emails_sent_to(uid=admin_uid) assert len(emails_sent) == 1 assert emails_sent[ 0].template_type == 'admin_alert_multiple_meeting_patterns' assert emails_sent[0].section_id == section_id
def get_course(term_id, section_id): course = SisSection.get_course(term_id, section_id) if not course: raise ResourceNotFoundError(f'No section for term_id = {term_id} and section_id = {section_id}') if not current_user.is_admin and current_user.uid not in [i['uid'] for i in course['instructors']]: raise ForbiddenRequestError(f'Sorry, you are unauthorized to view the course {course["label"]}.') return tolerant_jsonify(course)
def _schedule(): mock_scheduled( override_room_id=Room.find_room('Barker 101').id, section_id=section_id, term_id=term_id, ) course = SisSection.get_course(section_id=section_id, term_id=term_id) assert course['scheduled']['hasObsoleteRoom'] is True
def test_room_change_no_longer_eligible(self, db_session): section_id = 50004 term_id = app.config['CURRENT_TERM_ID'] def _move_course(meeting_location): db.session.execute( text( 'UPDATE sis_sections SET meeting_location = :meeting_location WHERE term_id = :term_id AND section_id = :section_id' ), { 'meeting_location': meeting_location, 'section_id': section_id, 'term_id': term_id, }, ) with enabled_job(job_key=InstructorEmailsJob.key()): with test_approvals_workflow(app): course = SisSection.get_course(section_id=section_id, term_id=term_id) eligible_meetings = course.get('meetings', {}).get('eligible', []) assert len(eligible_meetings) == 1 original_room = eligible_meetings[0]['room'] assert original_room['location'] == 'Li Ka Shing 145' # Schedule _schedule(original_room['id'], section_id) _run_instructor_emails_job() _assert_email_count(0, section_id, 'room_change_no_longer_eligible') # Move course to some other eligible room. _move_course('Barker 101') _run_instructor_emails_job() _assert_email_count(0, section_id, 'room_change_no_longer_eligible') # Move course to an ineligible room. ineligible_room = 'Wheeler 150' _move_course(ineligible_room) _run_instructor_emails_job() _assert_email_count(1, section_id, 'room_change_no_longer_eligible') # Move course back to its original location _move_course(original_room['location']) # Finally, let's pretend the course is scheduled to a room that was previously eligible. Scheduled.delete(section_id=section_id, term_id=term_id) _schedule(Room.find_room(ineligible_room).id, section_id) _run_instructor_emails_job() # Expect email. _assert_email_count(2, section_id, 'room_change_no_longer_eligible') Scheduled.delete(section_id=section_id, term_id=term_id)
def after_sis_data_refresh(cls, term_id): distinct_instructor_uids = SisSection.get_distinct_instructor_uids() insert_or_update_instructors(distinct_instructor_uids) app.logger.info(f'{len(distinct_instructor_uids)} instructors updated') refresh_rooms() app.logger.info('RDS indexes updated.') refresh_cross_listings(term_id=term_id) app.logger.info('Cross-listings updated.')
def test_interpolate_email_content(self): user = get_calnet_user_for_uid(app, '8765432') course = SisSection.get_course(app.config['CURRENT_TERM_ID'], '28165') interpolated = interpolate_email_content( course=course, recipient_name=user['name'], templated_string=_get_email_template(), ) actual = _normalize(interpolated) expected = _normalize(_get_expected_email()) assert expected == actual
def get_user(uid): user = get_calnet_user_for_uid(app=app, uid=uid) if user.get('isExpiredPerLdap', True): raise ResourceNotFoundError('No such user') else: courses = SisSection.get_courses_per_instructor_uid( term_id=app.config['CURRENT_TERM_ID'], instructor_uid=uid, ) user['courses'] = courses return tolerant_jsonify(user)
def get_room(room_id): room = Room.get_room(room_id) if room: api_json = room.to_api_json() api_json['courses'] = SisSection.get_courses_per_location( term_id=app.config['CURRENT_TERM_ID'], location=room.location, ) return tolerant_jsonify(api_json) else: raise ResourceNotFoundError('No such room')
def test_currently_no_person_teaching_course(self): """Refuse to queue emails for a course without a proper instructor.""" term_id = app.config['CURRENT_TERM_ID'] section_id = 50006 email_template_type = 'invitation' # Courses with no proper instructor are excluded from query results. assert not SisSection.get_course(term_id=term_id, section_id=section_id) # Queued email creation fails. assert not QueuedEmail.create(section_id, email_template_type, term_id, recipient=None) assert section_id not in QueuedEmail.get_all_section_ids(template_type=email_template_type, term_id=term_id)
def email_new_invites(self): for course in SisSection.get_courses(term_id=self.term_id): if not course['hasOptedOut'] and len(course.get('meetings', {}).get('eligible', [])) == 1: for i in course['instructors']: if not i['wasSentInvite']: QueuedEmail.create( recipient=i, section_id=course['sectionId'], template_type='invitation', term_id=self.term_id, )
def test_alert_admin_of_instructor_change(self): """Emails admin when a scheduled course gets a new instructor.""" with test_approvals_workflow(app): term_id = app.config['CURRENT_TERM_ID'] section_id = 22287 approved_by_uid = '8765432' room_id = Room.find_room('Barker 101').id approval = Approval.create( approved_by_uid=approved_by_uid, approver_type_='instructor', cross_listed_section_ids=[], publish_type_='canvas', recording_type_='presenter_audio', room_id=room_id, section_id=section_id, term_id=term_id, ) meeting_days, meeting_start_time, meeting_end_time = SisSection.get_meeting_times( term_id=term_id, section_id=section_id, ) Scheduled.create( cross_listed_section_ids=approval.cross_listed_section_ids, instructor_uids=SisSection.get_instructor_uids( term_id=term_id, section_id=section_id), meeting_days=meeting_days, meeting_start_time=meeting_start_time, meeting_end_time=meeting_end_time, publish_type_=approval.publish_type, recording_type_=approval.recording_type, room_id=room_id, section_id=section_id, term_id=term_id, ) admin_uid = app.config['EMAIL_DIABLO_ADMIN_UID'] email_count = _get_email_count(admin_uid) std_commit(allow_test_environment=True) AdminEmailsJob(app.app_context).run() std_commit(allow_test_environment=True) assert _get_email_count(admin_uid) > email_count
def approve(): term_id = app.config['CURRENT_TERM_ID'] term_name = term_name_for_sis_id(term_id) params = request.get_json() publish_type = params.get('publishType') recording_type = params.get('recordingType') section_id = params.get('sectionId') course = SisSection.get_course(term_id, section_id) if section_id else None if not course or publish_type not in get_all_publish_types() or recording_type not in get_all_recording_types(): raise BadRequestError('One or more required params are missing or invalid') if not current_user.is_admin and current_user.uid not in [i['uid'] for i in course['instructors']]: raise ForbiddenRequestError('Sorry, request unauthorized') if Approval.get_approval(approved_by_uid=current_user.uid, section_id=section_id, term_id=term_id): raise ForbiddenRequestError(f'You have already approved recording of {course["courseName"]}, {term_name}') location = course['meetingLocation'] room = Room.find_room(location=location) if not room: raise BadRequestError(f'{location} is not eligible for Course Capture.') previous_approvals = Approval.get_approvals_per_section_ids(section_ids=[section_id], term_id=term_id) approval = Approval.create( approved_by_uid=current_user.uid, approver_type_='admin' if current_user.is_admin else 'instructor', cross_listed_section_ids=[c['sectionId'] for c in course['crossListings']], publish_type_=publish_type, recording_type_=recording_type, room_id=room.id, section_id=section_id, term_id=term_id, ) _notify_instructors_of_approval( approval=approval, course=course, previous_approvals=previous_approvals, ) return tolerant_jsonify(SisSection.get_course(term_id, section_id))
def find_courses(): params = request.get_json() term_id = params.get('termId') filter_ = params.get('filter', 'Not Invited') if filter_ not in get_search_filter_options() or not term_id: raise BadRequestError('One or more required params are missing or invalid') if filter_ == 'Do Not Email': courses = SisSection.get_courses_opted_out(term_id) elif filter_ == 'Invited': courses = SisSection.get_courses_invited(term_id) elif filter_ == 'Not Invited': courses = SisSection.get_eligible_courses_not_invited(term_id) elif filter_ == 'Partially Approved': courses = SisSection.get_courses_partially_approved(term_id) elif filter_ == 'Scheduled': courses = SisSection.get_courses_scheduled(term_id) else: raise BadRequestError(f'Invalid filter: {filter_}') return tolerant_jsonify(courses)
def get_course(term_id, section_id): course = SisSection.get_course(term_id, section_id, include_deleted=True) if not course: raise ResourceNotFoundError(f'No section for term_id = {term_id} and section_id = {section_id}') if not current_user.is_admin and current_user.uid not in [i['uid'] for i in course['instructors']]: raise ForbiddenRequestError(f'Sorry, you are unauthorized to view the course {course["label"]}.') if current_user.is_admin and course['scheduled']: # When debugging, the raw Kaltura-provided JSON is useful. event_id = course['scheduled'].get('kalturaScheduleId') course['scheduled']['kalturaSchedule'] = Kaltura().get_event(event_id) return tolerant_jsonify(course)