def mock_note(): user = AuthorizedUser.find_by_uid(coe_advisor_read_write_uid) template = DegreeProgressTemplate.create( advisor_dept_codes=['COENG'], created_by=user.id, degree_name='I am a mock template, made for a mock note', ) return DegreeProgressNote.upsert( body='A mock note.', template_id=template.id, updated_by=user.id, )
def set_demo_mode(): if app.config['DEMO_MODE_AVAILABLE']: in_demo_mode = request.get_json().get('demoMode', None) if in_demo_mode is None: raise errors.BadRequestError('Parameter \'demoMode\' not found') user = AuthorizedUser.find_by_id(current_user.get_id()) user.in_demo_mode = bool(in_demo_mode) current_user.flush_cached() app.login_manager.reload_user() return tolerant_jsonify(current_user.to_api_json()) else: raise errors.ResourceNotFoundError('Unknown path')
def test_reserve_appointment(self, app, client, fake_auth): """Drop-in advisor can reserve an appointment.""" dept_code = 'QCADV' advisor = DropInAdvisor.advisors_for_dept_code(dept_code)[0] user = AuthorizedUser.find_by_id(advisor.authorized_user_id) fake_auth.login(user.uid) waiting = AppointmentTestUtil.create_appointment(client, dept_code) appointment = self._reserve_appointment(client, waiting['id']) assert appointment['status'] == 'reserved' assert appointment['statusDate'] is not None assert appointment['statusBy']['id'] == user.id Appointment.delete(appointment['id'])
def test_not_authenticated(self, app, client): """Returns 401 if not authenticated.""" assert _api_note_create( app=app, author_id=AuthorizedUser.get_id_per_uid(coe_advisor_uid), body= 'This is the last night of the fair, And the grease in the hair', client=client, expected_status_code=401, sids=[coe_student['sid']], subject='Rusholme Ruffians', )
def test_load_admin_user(self): """Returns authorization record to Flask-Login for recognized UID.""" admin_uid = '2040' loaded_user = AuthorizedUser.find_by_uid(admin_uid) assert loaded_user.is_active assert loaded_user.get_id() == admin_uid assert loaded_user.is_admin assert len(loaded_user.cohort_filters) > 0 owners = loaded_user.cohort_filters[0].owners assert len(owners) > 0 assert loaded_user in owners
def _get_coe_profiles(): users = list( filter(lambda _user: '******' in _get_dept_codes(_user), AuthorizedUser.get_all_active_users())) profiles = [] for user in authorized_users_api_feed(users): uid = user['uid'] first_name = user.get('firstName') last_name = user.get('lastName') name = f'{first_name} {last_name}' if first_name or last_name else f'UID: {uid}' profiles.append({'name': name, 'value': uid}) return sorted(profiles, key=lambda p: p['name'])
def add_university_dept_membership(): params = request.get_json() or {} dept = UniversityDept.find_by_dept_code(params.get('deptCode', None)) user = AuthorizedUser.find_by_uid(params.get('uid', None)) membership = UniversityDeptMember.create_or_update_membership( university_dept=dept, authorized_user=user, is_advisor=params.get('isAdvisor', False), is_director=params.get('isDirector', False), is_scheduler=params.get('isScheduler', False), automate_membership=params.get('automateMembership', True), ) return tolerant_jsonify(membership.to_api_json())
def test_updated_date_is_none_when_note_create(self, app, client, fake_auth): """Create a note and expect none updated_at.""" fake_auth.login(coe_advisor_uid) note = _api_note_create( app, client, author_id=AuthorizedUser.get_id_per_uid(coe_advisor_uid), sids=[coe_student['sid']], subject='Creating is not updating', body=None, ) assert note['createdAt'] is not None assert note['updatedAt'] is None
def test_create_and_delete_cohort(self): """cohort_filter record to Flask-Login for recognized UID""" owner = AuthorizedUser.find_by_uid('2040') shared_with = AuthorizedUser.find_by_uid('1133399') # Check validity of UIDs assert owner assert shared_with # Create and share cohort cohort = CohortFilter.create(label='High-risk Badminton', team_codes=['MBK', 'WBK'], uid=owner.uid) cohort = CohortFilter.share(cohort['id'], shared_with.uid) assert len(cohort['owners']) == 2 assert owner, shared_with in cohort['owners'] # Delete cohort and verify previous_owner_count = cohort_count(owner) previous_shared_count = cohort_count(shared_with) CohortFilter.delete(cohort['id']) assert cohort_count(owner) == previous_owner_count - 1 assert cohort_count(shared_with) == previous_shared_count - 1
def test_user_without_advising_data_access(self, app, client, fake_auth): """Denies access to a user who cannot access notes and appointments.""" fake_auth.login(coe_advisor_no_advising_data_uid) user = AuthorizedUser.find_by_uid(coe_advisor_no_advising_data_uid) _api_batch_note_create( app, client, author_id=user.id, subject='Verboten', body='Diese Aktion ist nicht zulässig.', sids=self.sids, expected_status_code=401, )
def test_create_note_prefers_ldap_dept_affiliation(self, app, client, fake_auth): fake_auth.login(l_s_major_advisor_uid) new_note = _api_note_create( app, client, author_id=AuthorizedUser.get_id_per_uid(l_s_major_advisor_uid), sid=coe_student['sid'], subject='A dreaded sunny day', body='Keats and Yeats are on your side', ) assert new_note['author']['departments'][0][ 'name'] == 'Department of English'
def test_get_note_template_by_id(self, app, client, fake_auth): """Returns note templates created by current user.""" fake_auth.login(l_s_major_advisor_uid) creator_id = AuthorizedUser.get_id_per_uid(l_s_major_advisor_uid) names = ['Johnny', 'Tommy', 'Joey', 'Dee Dee'] for i in range(0, 4): NoteTemplate.create(creator_id=creator_id, title=f'{names[i]}', subject=f'Subject {i}') api_json = self._api_my_note_templates(client=client) expected_order = [template['title'] for template in api_json] expected_order.sort() assert expected_order == [template['title'] for template in api_json]
def test_unauthorized_private_note(self, app, client, fake_auth): """Non-CE3 advisor cannot create a private note.""" fake_auth.login(coe_advisor_uid) _api_note_create( app=app, author_id=AuthorizedUser.get_id_per_uid(coe_advisor_uid), body='She drove a Plymouth Satellite', client=client, expected_status_code=403, is_private=True, sids=[coe_student['sid']], subject='Planet Claire', )
def test_admin_user_is_not_authorized(self, app, client, fake_auth): """Returns 401 if user is an admin.""" fake_auth.login(admin_uid) admin = AuthorizedUser.find_by_uid(admin_uid) assert _api_note_create( app, client, author_id=admin.id, sids=[coe_student['sid']], subject='Rusholme Ruffians', body='This is the last night of the fair, And the grease in the hair', expected_status_code=403, )
def test_scheduler_is_not_authorized(self, app, client, fake_auth): """Returns 401 if user is a scheduler.""" fake_auth.login(coe_scheduler_uid) admin = AuthorizedUser.find_by_uid(coe_scheduler_uid) assert _api_note_create( app, client, author_id=admin.id, sids=[coe_student['sid']], subject='Gobbledygook', body='Language made unintelligible by excessive use of abstruse technical terms.', expected_status_code=401, )
def refresh_department_memberships(): from boac.models.authorized_user import AuthorizedUser from boac.models.authorized_user_extension import DropInAdvisor, SameDayAdvisor, Scheduler from boac.models.university_dept import UniversityDept from boac.models.university_dept_member import UniversityDeptMember depts = UniversityDept.query.all() for dept in depts: dept.delete_automated_members() std_commit(allow_test_environment=True) for dept in depts: for membership in dept.memberships_from_loch(): # A non-numeric "uid" indicates a row from SIS advising tables best ignored. uid = membership['uid'] if not re.match(r'^\d+$', uid): continue user = AuthorizedUser.find_by_uid(uid, ignore_deleted=False) if user and not user.automate_degree_progress_permission: degree_progress_permission = user.degree_progress_permission else: degree_progress_permission = membership[ 'degree_progress_permission'] user = AuthorizedUser.create_or_restore( can_access_advising_data=membership[ 'can_access_advising_data'], can_access_canvas_data=membership['can_access_canvas_data'], created_by='0', degree_progress_permission=degree_progress_permission, uid=uid, ) if user: UniversityDeptMember.create_or_update_membership( university_dept_id=dept.id, authorized_user_id=user.id, role='advisor', ) DropInAdvisor.delete_orphans() SameDayAdvisor.delete_orphans() Scheduler.delete_orphans()
def get_coe_profiles(): users = list( filter(lambda _user: '******' in _get_dept_codes(_user), AuthorizedUser.get_all_active_users())) calnet_users = get_calnet_users_for_uids(app, [u.uid for u in users]) profiles = [] for user in users: uid = user.uid calnet_user = calnet_users[uid] first_name = calnet_user.get('firstName') last_name = calnet_user.get('lastName') name = f'{first_name} {last_name}' if first_name or last_name else f'UID: {uid}' profiles.append({'name': name, 'value': uid}) return sorted(profiles, key=lambda p: p['name'])
def test_update_university_dept_membership(self, client, fake_auth): """Updates a UniversityDeptMember record.""" fake_auth.login(admin_uid) self._api_add(client) membership = self._api_update(client, is_advisor=False, is_director=True) assert membership[ 'universityDeptId'] == UniversityDept.find_by_dept_code('ZZZZZ').id assert membership['authorizedUserId'] == AuthorizedUser.find_by_uid( coe_advisor_uid).id assert membership['isAdvisor'] is False assert membership['isDirector'] is True assert membership['automateMembership'] is False
def test_curated_cohort_includes_alert_count(self, asc_advisor, client, create_alerts): """Successfully fetches curated_cohort with alert count per student.""" user_id = AuthorizedUser.find_by_uid(asc_advisor_uid).id cohorts = CuratedCohort.get_curated_cohorts_by_owner_id(user_id) response = client.get(f'/api/curated_cohort/{cohorts[0].id}') students = response.json.get('students') assert students for student in students: assert isinstance(student.get('alertCount'), int) student_with_alerts = next( (s for s in students if s['sid'] == '11667051'), None) assert student_with_alerts assert student_with_alerts['alertCount'] == 3
def test_update_note_template_topics(self, app, client, fake_auth, mock_note_template): """Update note template title.""" user = AuthorizedUser.find_by_id(mock_note_template.creator_id) fake_auth.login(user.uid) expected_title = 'As cool as Kim Deal' api_json = self._api_note_template_rename( client, note_template_id=mock_note_template.id, title=expected_title, ) assert api_json['title'] == expected_title assert NoteTemplate.find_by_id( mock_note_template.id).title == expected_title
def test_create_private_note(self, app, client, fake_auth): """CE3 advisor can create a private note.""" fake_auth.login(ce3_advisor_uid) note = _api_note_create( app=app, author_id=AuthorizedUser.get_id_per_uid(ce3_advisor_uid), body='Somebody went under a dock and there they saw a rock.', client=client, is_private=True, sids=[coe_student['sid']], subject='Rock Lobster', ) assert note['isPrivate'] is True assert 'rock' in note['body']
def test_get_note_by_id(self, app, client, fake_auth, new_coe_note): """Returns note in JSON compatible with BOA front-end.""" fake_auth.login(coe_advisor_uid) note = self._api_note_by_id(client=client, note_id=new_coe_note.id) assert note assert 'id' in note assert note['type'] == 'note' assert note['body'] == note['message'] assert note['read'] is False # Mark as read and re-test NoteRead.find_or_create(AuthorizedUser.get_id_per_uid(coe_advisor_uid), note['id']) assert self._api_note_by_id(client=client, note_id=new_coe_note.id)['read'] is True
def test_get_topic_usage_statistics(self, client, fake_auth): """Admin user can update a topic.""" fake_auth.login(admin_uid) api_json = self._api_usage_statistics(client) assert list(api_json.keys()) == ['appointments', 'notes'] assert len(api_json['appointments']) # Verify counts admin_user_id = AuthorizedUser.get_id_per_uid(uid=admin_uid) all_appointments = Appointment.query.filter(Appointment.deleted_at == None).all() # noqa: E711 all_appointments = [a.to_api_json(current_user_id=admin_user_id) for a in all_appointments] for topic_id, count in api_json['appointments'].items(): topic = Topic.find_by_id(topic_id) matches = list(filter(lambda a: topic.topic in a['topics'], all_appointments)) assert len(matches) == count
def remove_appointment_scheduler_from_dept(dept_code): _verify_membership_and_appointments_enabled(current_user, dept_code) params = request.get_json() or {} uid = params.get('uid') user = uid and AuthorizedUser.find_by_uid(uid) if not user: raise errors.BadRequestError(f'UID {uid} missing or invalid') scheduler_membership = next(( d for d in user.department_memberships if d.university_dept.dept_code == dept_code and d.role == 'scheduler'), None) if not scheduler_membership: raise errors.BadRequestError( f'UID {uid} is not a scheduler for department {dept_code}') UniversityDeptMember.delete_membership( university_dept_id=scheduler_membership.university_dept_id, authorized_user_id=user.id, ) Scheduler.delete(authorized_user_id=user.id, dept_code=dept_code) if not len(user.department_memberships): AuthorizedUser.delete(uid) return tolerant_jsonify( _get_appointment_scheduler_list(current_user, dept_code))
def test_feature_flag(self, client, fake_auth, app): """Appointments feature is false.""" dept_code = 'QCADV' advisor = DropInAdvisor.advisors_for_dept_code(dept_code)[0] fake_auth.login( AuthorizedUser.find_by_id(advisor.authorized_user_id).uid) appointment = AppointmentTestUtil.create_appointment(client, dept_code) with override_config(app, 'FEATURE_FLAG_ADVISOR_APPOINTMENTS', False): self._cancel_appointment( client, appointment_id=appointment['id'], cancel_reason='Canceled by the power of the mind', expected_status_code=401, )
def test_steal_appointment_reservation(self, app, client, fake_auth): """Reserve an appointment that another advisor has reserved.""" dept_code = 'COENG' advisor_1 = DropInAdvisor.advisors_for_dept_code(dept_code)[0] user_1 = AuthorizedUser.find_by_id(advisor_1.authorized_user_id) fake_auth.login(user_1.uid) waiting = AppointmentTestUtil.create_appointment(client, dept_code) appointment = self._reserve_appointment(client, waiting['id']) assert appointment['status'] == 'reserved' assert appointment['statusDate'] is not None assert appointment['statusBy']['id'] == user_1.id client.get('/api/auth/logout') # Another advisor comes along... advisor_2 = DropInAdvisor.advisors_for_dept_code(dept_code)[1] user_2 = AuthorizedUser.find_by_id(advisor_2.authorized_user_id) fake_auth.login(user_2.uid) appointment = self._reserve_appointment(client, waiting['id']) assert appointment['status'] == 'reserved' assert appointment['statusDate'] is not None assert appointment['statusBy']['id'] == user_2.id # Clean up Appointment.delete(appointment['id'])
def test_create_or_restore_new(self): """Creates a new user if it doesn't already exist.""" new_user = AuthorizedUser.create_or_restore( unknown_uid, created_by='0', is_admin=False, can_access_advising_data=True, can_access_canvas_data=False, ) assert new_user.is_admin is False assert new_user.can_access_advising_data is True assert new_user.can_access_canvas_data is False assert new_user.in_demo_mode is False assert new_user.created_by == '0'
def _create_waiting_appointments(): coe_advisor_user_id = AuthorizedUser.get_id_per_uid('90412') coe_scheduler_user_id = AuthorizedUser.get_id_per_uid('6972201') l_s_director_user_id = AuthorizedUser.get_id_per_uid('53791') Appointment.create( appointment_type='Drop-in', created_by=coe_scheduler_user_id, dept_code='COENG', details='Meet me at the crossroads.', student_sid='3456789012', topics=['Topic for appointments, 2'], ) Appointment.create( appointment_type='Drop-in', created_by=coe_advisor_user_id, dept_code='COENG', details='Life is what happens while you\'re making appointments.', student_sid='5678901234', topics=['Good Show'], ) # L&S College Advising Appointment.create( appointment_type='Drop-in', created_by=l_s_director_user_id, dept_code='QCADV', details='C-c-catch the wave!', student_sid='5678901234', topics=['Topic for appointments, 1', 'Good Show'], ) Appointment.create( appointment_type='Drop-in', created_by=l_s_director_user_id, dept_code='QCADV', details='You be you.', student_sid='11667051', topics=['Topic for appointments, 1'], )
def test_respects_automate_memberships_flag(self, app, db): dept_coe = UniversityDept.query.filter_by(dept_code='COENG').first() manually_added_user = AuthorizedUser.create_or_restore( uid='1024', created_by='2040', degree_progress_permission='read_write', ) manual_membership = UniversityDeptMember.create_or_update_membership( dept_coe.id, manually_added_user.id, role='advisor', automate_membership=False, ) from boac.api.cache_utils import refresh_department_memberships refresh_department_memberships() std_commit(allow_test_environment=True) coe_users = [au.authorized_user for au in dept_coe.authorized_users] coe_user_count = len(coe_users) assert coe_user_count assert next(u for u in coe_users if u.uid == '1024') user = AuthorizedUser.find_by_uid(uid='1024') assert user assert user.degree_progress_permission == 'read_write' manual_membership.automate_membership = True db.session.add(manual_membership) std_commit(allow_test_environment=True) refresh_department_memberships() std_commit(allow_test_environment=True) coe_users = [au.authorized_user for au in dept_coe.authorized_users] assert len(coe_users) == coe_user_count - 1 assert next((u for u in coe_users if u.uid == '1024'), None) is None assert not AuthorizedUser.find_by_uid(uid='1024')
def test_create_note_with_raw_url_in_body(self, app, client, fake_auth): """Create a note with topics.""" fake_auth.login(coe_advisor_uid) note = _api_note_create( app, client, author_id=AuthorizedUser.get_id_per_uid(coe_advisor_uid), sids=[coe_student['sid']], subject='Get rich quick', body='Get an online degree at send.money.edu university', ) expected_body = 'Get an online degree at <a href="http://send.money.edu" target="_blank">send.money.edu</a> university' assert note.get('body') == expected_body assert note['createdAt'] is not None assert note['updatedAt'] is None