Пример #1
0
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))
Пример #2
0
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)))
Пример #3
0
 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
Пример #4
0
    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)
Пример #5
0
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')
Пример #6
0
    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)
Пример #7
0
    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)
Пример #8
0
 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}')
Пример #9
0
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)
Пример #10
0
 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)
Пример #12
0
    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)
Пример #13
0
 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
Пример #14
0
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))
Пример #15
0
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)
 def test_email_alert_when_canceled_course(self, db_session):
     term_id = app.config['CURRENT_TERM_ID']
     with enabled_job(job_key=InstructorEmailsJob.key()):
         with test_approvals_workflow(app):
             course = SisSection.get_course(section_id=deleted_section_id,
                                            term_id=term_id,
                                            include_deleted=True)
             room = course.get('meetings', {}).get('eligible',
                                                   [])[0]['room']
             _schedule(room['id'], deleted_section_id)
             _run_instructor_emails_job()
             _assert_email_count(1, deleted_section_id,
                                 'room_change_no_longer_eligible')
Пример #17
0
def save_mock_courses(json_file_path):
    courses = _load_mock_courses(json_file_path)
    if courses:
        for course in courses:
            section_id = course['section_id']
            if SisSection.get_course(term_id=course['term_id'],
                                     section_id=section_id):
                db.session.execute(
                    text(
                        f'DELETE FROM sis_sections WHERE section_id = {section_id}'
                    ))
        _save_courses(sis_sections=courses)
        std_commit(allow_test_environment=True)
Пример #18
0
 def create(cls, section_id, template_type, term_id, recipient, message=None, subject_line=None):
     course = SisSection.get_course(term_id, section_id, include_deleted=True)
     if not course:
         app.logger.error(f'Attempt to queue email for unknown course (term_id={term_id}, section_id={section_id})')
         return
     if not course['instructors']:
         app.logger.error(f'Attempt to queue email for course without instructors (term_id={term_id}, section_id={section_id})')
         return
     queued_email = cls(
         section_id=section_id,
         template_type=template_type,
         term_id=term_id,
         recipient=recipient,
         message=message,
         subject_line=subject_line,
     )
     course = SisSection.get_course(term_id, queued_email.section_id, include_deleted=True)
     if not queued_email.is_interpolated() and not queued_email.interpolate(course):
         app.logger.error(f'Failed to interpolate all required values for queued email ({queued_email})')
         return
     db.session.add(queued_email)
     std_commit()
     return queued_email
Пример #19
0
 def _schedule():
     mock_scheduled(
         meeting=meeting,
         override_end_time='16:59',
         override_start_time='08:00',
         section_id=section_id,
         term_id=term_id,
     )
     course = SisSection.get_course(
         section_id=section_id, term_id=term_id)
     scheduled = course['scheduled']
     assert are_scheduled_dates_obsolete(
         meeting=meeting, scheduled=scheduled) is False
     assert are_scheduled_times_obsolete(
         meeting=meeting, scheduled=scheduled) is True
Пример #20
0
def queue_emails():
    params = request.get_json()
    term_id = params.get('termId')
    section_id = params.get('sectionId')
    template_type = params.get('emailTemplateType')

    if not (term_id and section_id and template_type):
        raise BadRequestError('Required parameters are missing.')
    course = SisSection.get_course(term_id=term_id, section_id=section_id)
    for instructor in course['instructors']:
        if not QueuedEmail.create(section_id=section_id, recipient=instructor, template_type=template_type, term_id=term_id):
            raise BadRequestError(f"Failed to queue email of type '{template_type}'.")
    return tolerant_jsonify({
        'message': f"An email of type '{template_type}' has been queued.",
    })
Пример #21
0
 def test_instructor_of_cross_listing(self, client, fake_auth):
     """If section X and Y are cross-listed then /course page of X must be reachable by instructor of Y."""
     section_id = 50012
     cross_listed_section_id = 50013
     instructor_uid = '10010'
     # Confirm that cross-listed section was deleted during sis_data_refresh job
     assert not SisSection.get_course(section_id=cross_listed_section_id, term_id=self.term_id)
     # Log in as instructor of cross-listed section
     fake_auth.login(uid=instructor_uid)
     api_json = api_get_course(
         client,
         term_id=self.term_id,
         section_id=section_id,
     )
     assert len(api_json['crossListings']) == 1
     assert cross_listed_section_id == api_json['crossListings'][0]['sectionId']
     assert instructor_uid in [i['uid'] for i in api_json['instructors']]
Пример #22
0
 def test_series_description(self):
     """Series description for cross-listed course."""
     cross_listed_section_id = 50012
     term_id = app.config['CURRENT_TERM_ID']
     course = SisSection.get_course(
         section_id=cross_listed_section_id,
         term_id=term_id,
     )
     description = get_series_description(
         course_label=course['label'],
         instructors=course['instructors'],
         term_name=term_name_for_sis_id(term_id),
     )
     assert 'MATH C51, LEC 001 | STAT C151, COL 001' in description
     assert 'Fall 2021' in description
     assert 'Rudolf Schündler and Arthur Storch' in description
     assert '2021' in description
Пример #23
0
def update_opt_out():
    params = request.get_json()
    term_id = params.get('termId')
    section_id = params.get('sectionId')

    course = SisSection.get_course(term_id, section_id) if (term_id and section_id) else None
    opt_out = params.get('optOut')
    if not course or opt_out is None:
        raise BadRequestError('Required params missing or invalid')
    if course['scheduled']:
        raise BadRequestError('Cannot update opt-out on scheduled course')

    preferences = CoursePreference.update_opt_out(
        term_id=term_id,
        section_id=section_id,
        opt_out=opt_out,
    )
    return tolerant_jsonify(preferences.to_api_json())
Пример #24
0
    def run(self, args=None):
        term_id = app.config['CURRENT_TERM_ID']
        for queued_email in QueuedEmail.get_all(term_id):
            template_type = queued_email.template_type
            course = SisSection.get_course(term_id, queued_email.section_id)
            if course:
                if course['hasOptedOut']:
                    # Do not send email; delete the item from queue.
                    QueuedEmail.delete(queued_email)
                else:
                    if template_type in [
                            'invitation',
                            'notify_instructor_of_changes',
                            'recordings_scheduled',
                            'room_change_no_longer_eligible',
                            'waiting_for_approval',
                    ]:
                        recipients = course['instructors']
                    elif template_type in [
                            'admin_alert_instructor_change',
                            'admin_alert_room_change'
                    ]:
                        recipients = get_admin_alert_recipients()
                    else:
                        raise BackgroundJobError(
                            f'Email template type not supported: {template_type}'
                        )

                    # If send() returns False then report the error and DO NOT delete the queued item.
                    if send_course_related_email(
                            course=course,
                            recipients=recipients,
                            template_type=template_type,
                            term_id=term_id,
                    ):
                        QueuedEmail.delete(queued_email)
                    else:
                        app.logger.error(
                            f'Failed to send email: {queued_email}')
            else:
                app.logger.warn(
                    f'Email will remain queued until course gets proper instructor: {queued_email}'
                )
Пример #25
0
    def test_has_obsolete_room(self, client, admin_session):
        """Admins can see room changes that might disrupt scheduled recordings."""
        course = SisSection.get_course(term_id=self.term_id, section_id=section_2_id)
        actual_room_id = course['room']['id']
        obsolete_room = Room.find_room('Barker 101')

        assert obsolete_room
        assert actual_room_id != obsolete_room.id

        _schedule_recordings(
            section_id=section_2_id,
            term_id=self.term_id,
            room_id=obsolete_room.id,
        )
        api_json = self._api_course_changes(client, term_id=self.term_id)
        course = _find_course(api_json=api_json, section_id=section_2_id)
        assert course
        assert course['scheduled']['hasObsoleteRoom'] is True
        assert course['scheduled']['hasObsoleteMeetingTimes'] is False
        assert course['scheduled']['hasObsoleteInstructors'] is False
Пример #26
0
    def test_download_csv(self, client, admin_session):
        """Admin users can download courses CSV file."""
        term_id = app.config['CURRENT_TERM_ID']
        csv_string = self._api_courses_csv(client).decode('utf-8')
        reader = csv.reader(StringIO(csv_string), delimiter=',')
        for index, row in enumerate(reader):
            section_id = row[1]
            meeting_type = row[6]
            sign_up_url = row[9]
            instructors = row[-2]
            instructor_uids = row[-1]
            if index == 0:
                assert section_id == 'Section Id'
                assert meeting_type == 'Meeting Type'
                assert sign_up_url == 'Sign-up URL'
                assert instructors == 'Instructors'
                assert instructor_uids == 'Instructor UIDs'
            else:
                course = SisSection.get_course(section_id=section_id, term_id=term_id)
                assert int(section_id) == course['sectionId']
                for snippet in [app.config['DIABLO_BASE_URL'], section_id, str(term_id)]:
                    assert snippet in sign_up_url

                expected_uids = [instructor['uid'] for instructor in course['instructors']]
                if expected_uids:
                    assert set(instructor_uids.split(', ')) == set(expected_uids)
                else:
                    assert instructor_uids == ''
                for instructor in course['instructors']:
                    assert instructor['email'] in instructors
                    assert instructor['name'] in instructors

                if len(course['meetings']['eligible']) > 1:
                    assert meeting_type == 'D'
                elif course['nonstandardMeetingDates']:
                    assert meeting_type == 'C'
                elif len(course['meetings']['eligible'] + course['meetings']['ineligible']) > 1:
                    assert meeting_type == 'B'
                else:
                    assert meeting_type == 'A'
Пример #27
0
def _after_approval(course):
    section_id = course['sectionId']
    term_id = course['termId']
    approvals = Approval.get_approvals(section_id=section_id, term_id=term_id)

    if get_courses_ready_to_schedule(approvals=approvals, term_id=term_id):
        # Queuing course for scheduling wipes any opt-out preference.
        if course['hasOptedOut']:
            CoursePreference.update_opt_out(
                term_id=term_id,
                section_id=section_id,
                opt_out=False,
            )
        if app.config['FEATURE_FLAG_SCHEDULE_RECORDINGS_SYNCHRONOUSLY']:
            # Feature flag intended for dev workstation ONLY. Do not enable in diablo-dev|qa|prod.
            schedule_recordings(
                all_approvals=approvals,
                course=course,
            )
        return SisSection.get_course(section_id=course['sectionId'], term_id=course['termId'])
    else:
        return course
Пример #28
0
    def test_are_scheduled_dates_obsolete_handles_nulls(self):
        with test_approvals_workflow(app):
            meeting = _create_meeting(
                days='MO',
                end_date=_format(datetime.now() + timedelta(days=100)),
                end_time='10:59',
                start_date=_format(datetime.now() - timedelta(days=100)),
                start_time='10:00',
            )
            with override_config(app, 'CURRENT_TERM_RECORDINGS_BEGIN', meeting['startDate']):
                with override_config(app, 'CURRENT_TERM_RECORDINGS_END', meeting['endDate']):
                    mock_scheduled(meeting=meeting, 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']

                    meeting = _create_meeting(
                        days=None,
                        end_date=None,
                        end_time=None,
                        start_date=None,
                        start_time=None,
                    )
            assert are_scheduled_dates_obsolete(meeting, scheduled) is True
Пример #29
0
 def test_invited_filter(self, client, db, admin_session):
     """Invited filter: Course in an eligible room, have received invitation. No approvals. Not scheduled."""
     with test_approvals_workflow(app):
         # First, send invitations
         SentEmail.create(
             section_id=section_4_id,
             recipient_uids=_get_instructor_uids(section_id=section_4_id, term_id=self.term_id),
             template_type='invitation',
             term_id=self.term_id,
         )
         section_5_instructor_uids = _get_instructor_uids(section_id=section_5_id, term_id=self.term_id)
         SentEmail.create(
             section_id=section_5_id,
             recipient_uids=section_5_instructor_uids,
             template_type='invitation',
             term_id=self.term_id,
         )
         # The section with approval will NOT show up in search results
         Approval.create(
             approved_by_uid=section_5_instructor_uids[0],
             approver_type_='instructor',
             cross_listed_section_ids=[],
             publish_type_='canvas',
             recording_type_='presentation_audio',
             room_id=SisSection.get_course(term_id=self.term_id, section_id=section_5_id)['room']['id'],
             section_id=section_5_id,
             term_id=self.term_id,
         )
         std_commit(allow_test_environment=True)
         api_json = self._api_courses(client, term_id=self.term_id, filter_='Invited')
         # Section with ZERO approvals will show up in search results
         course = _find_course(api_json=api_json, section_id=section_4_id)
         assert course
         assert course['label'] == 'CHEM C110L, LAB 001'
         # The section with approval will NOT show up in search results
         assert not _find_course(api_json=api_json, section_id=section_5_id)
Пример #30
0
def _is_course_in_enabled_room(section_id, term_id):
    eligible_meetings = SisSection.get_course(term_id=term_id, section_id=section_id)['meetings']['eligible']
    return eligible_meetings and eligible_meetings[0]['room']['capability'] is not None