def get_students_with_alerts(curated_group_id): offset = get_param(request.args, 'offset', 0) limit = get_param(request.args, 'limit', 50) benchmark = get_benchmarker( f'curated group {curated_group_id} students_with_alerts') benchmark('begin') curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'Sorry, no curated group found with id {curated_group_id}.') if not _can_current_user_view_curated_group(curated_group): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, cannot view curated group {curated_group.id}' ) students = Alert.include_alert_counts_for_students( benchmark=benchmark, viewer_user_id=current_user.get_id(), group={'sids': CuratedGroup.get_all_sids(curated_group_id)}, count_only=True, offset=offset, limit=limit, ) alert_count_per_sid = {} for s in list(filter(lambda s: s.get('alertCount') > 0, students)): sid = s.get('sid') alert_count_per_sid[sid] = s.get('alertCount') sids = list(alert_count_per_sid.keys()) benchmark('begin profile query') students_with_alerts = get_student_profile_summaries(sids=sids) benchmark('end profile query') for student in students_with_alerts: student['alertCount'] = alert_count_per_sid[student['sid']] benchmark('end') return tolerant_jsonify(students_with_alerts)
def _get_curated_groups_ids_and_sids(advisor): sids = [] curated_group_ids = [] for curated_group in CuratedGroup.get_curated_groups_by_owner_id(advisor.id): curated_group_ids.append(curated_group.id) sids = sids + CuratedGroup.get_all_sids(curated_group.id) return curated_group_ids, sids
def test_distinct_sids(self, client, fake_auth): """Get distinct SIDs across cohorts and curated groups.""" user_id = AuthorizedUser.get_id_per_uid(coe_advisor_uid) cohort_ids = [] sids = set() for cohort in CohortFilter.get_cohorts(user_id): cohort_id = cohort['id'] cohort_ids.append(cohort_id) sids.update(set(CohortFilter.get_sids(cohort_id))) assert len(sids) > 1 curated_group = CuratedGroup.create( user_id, 'Like a lemon to a lime, a lime to a lemon') curated_group_ids = [curated_group.id] # We use SIDs from cohorts (above). Therefore, we expect no increase in 'batch_distinct_student_count'. for sid in sids: CuratedGroup.add_student(curated_group.id, sid) # A specific student (SID) that is in neither cohorts nor curated groups. some_other_sid = '5678901234' assert some_other_sid not in sids # Log in as authorized user fake_auth.login(coe_advisor_uid) data = self._api_distinct_sids( client, cohort_ids=cohort_ids, curated_group_ids=curated_group_ids, sids=[some_other_sid], ) assert sids.union({some_other_sid}) == set(data['sids'])
def remove_student_from_curated_group(curated_group_id, sid): curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'No curated group found with id: {curated_group_id}') if curated_group.owner_id != current_user.get_id(): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, does not own curated group {curated_group.id}' ) CuratedGroup.remove_student(curated_group_id, sid) return tolerant_jsonify(curated_group.to_api_json(include_students=False))
def create_curated_group(): params = request.get_json() name = params.get('name', None) if not name: raise BadRequestError('Curated group creation requires \'name\'') curated_group = CuratedGroup.create(current_user.get_id(), name) # Optionally, add students if 'sids' in params: sids = [sid for sid in set(params.get('sids')) if sid.isdigit()] CuratedGroup.add_students(curated_group_id=curated_group.id, sids=sids) return tolerant_jsonify(curated_group.to_api_json())
def update_curated_group_lists(): """Remove no-longer-accessible students from curated group lists.""" from boac.models.curated_group import CuratedGroup for curated_group in CuratedGroup.query.all(): all_sids = CuratedGroupStudent.get_sids(curated_group.id) available_students = [s['sid'] for s in data_loch.get_student_profiles(all_sids)] if len(all_sids) > len(available_students): unavailable_sids = set(all_sids) - set(available_students) app.logger.info(f'Deleting inaccessible SIDs from curated group {curated_group.id}: {unavailable_sids}') for sid in unavailable_sids: CuratedGroup.remove_student(curated_group.id, sid)
def delete_curated_group(curated_group_id): curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'No curated group found with id: {curated_group_id}') if curated_group.owner_id != current_user.get_id(): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, does not own curated group {curated_group.id}' ) CuratedGroup.delete(curated_group_id) return tolerant_jsonify( {'message': f'Curated group {curated_group_id} has been deleted'}), 200
def download_csv(curated_group_id): benchmark = get_benchmarker( f'curated group {curated_group_id} download_csv') benchmark('begin') curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'No curated group found with id: {curated_group_id}') if curated_group.owner_id != current_user.get_id(): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, does not own curated group {curated_group.id}' ) return response_with_students_csv_download( sids=CuratedGroup.get_all_sids(curated_group_id), benchmark=benchmark)
def rename_curated_group(): params = request.get_json() name = params['name'] if not name: raise BadRequestError( 'Requested curated group name is empty or invalid') curated_group_id = params['id'] curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group or curated_group.owner_id != current_user.get_id(): raise BadRequestError( 'Curated group does not exist or is not available to you') CuratedGroup.rename(curated_group_id=curated_group.id, name=name) return tolerant_jsonify( CuratedGroup.find_by_id(curated_group_id).to_api_json())
def get_my_curated_groups(): curated_groups = [] user_id = current_user.get_id() for curated_group in CuratedGroup.get_curated_groups_by_owner_id(user_id): api_json = curated_group.to_api_json(include_students=False) students = [{'sid': sid} for sid in CuratedGroup.get_all_sids(curated_group.id)] students_with_alerts = Alert.include_alert_counts_for_students( viewer_user_id=user_id, group={'students': students}, count_only=True, ) api_json['alertCount'] = sum(s['alertCount'] for s in students_with_alerts) api_json['totalStudentCount'] = len(students) curated_groups.append(api_json) return curated_groups
def _curated_group_with_complete_student_profiles(curated_group_id, order_by='last_name', offset=0, limit=50): benchmark = get_benchmarker( f'curated group {curated_group_id} with student profiles') benchmark('begin') curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'Sorry, no curated group found with id {curated_group_id}.') if curated_group.owner_id != current_user.get_id(): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, does not own curated group {curated_group.id}' ) api_json = curated_group.to_api_json(order_by=order_by, offset=offset, limit=limit) sids = [s['sid'] for s in api_json['students']] benchmark('begin profile query') api_json['students'] = get_summary_student_profiles(sids) benchmark('begin alerts query') Alert.include_alert_counts_for_students( viewer_user_id=current_user.get_id(), group=api_json) benchmark('end') return api_json
def _curated_group_with_complete_student_profiles(curated_group_id, order_by='last_name', term_id=None, offset=0, limit=50): benchmark = get_benchmarker( f'curated group {curated_group_id} with student profiles') benchmark('begin') curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'Sorry, no curated group found with id {curated_group_id}.') if not _can_current_user_view_curated_group(curated_group): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, cannot view curated group {curated_group.id}' ) api_json = curated_group.to_api_json(order_by=order_by, offset=offset, limit=limit) sids = [s['sid'] for s in api_json['students']] benchmark('begin profile query') api_json['students'] = get_summary_student_profiles( sids, term_id=term_id, include_historical=True) benchmark('begin alerts query') Alert.include_alert_counts_for_students( viewer_user_id=current_user.get_id(), group=api_json) benchmark('end') benchmark('begin get_referencing_cohort_ids') api_json[ 'referencingCohortIds'] = curated_group.get_referencing_cohort_ids() benchmark('end') return api_json
def create_curated_group(): params = request.get_json() domain = get_param(params, 'domain', 'default') if is_unauthorized_domain(domain): raise ForbiddenRequestError( f'You are unauthorized to use the \'{domain}\' domain') name = params.get('name', None) if not name: raise BadRequestError('Curated group creation requires \'name\'') curated_group = CuratedGroup.create(domain=domain, name=name, owner_id=current_user.get_id()) # Optionally, add students if 'sids' in params: sids = [sid for sid in set(params.get('sids')) if sid.isdigit()] CuratedGroup.add_students(curated_group_id=curated_group.id, sids=sids) return tolerant_jsonify(curated_group.to_api_json(include_students=True))
def test_curated_groups_by_sid(self, client, coe_advisor, coe_advisor_groups): """API delivers accurate set of student SIDs.""" sids = CuratedGroup.get_all_sids( curated_group_id=coe_advisor_groups[0].id) sample_sid = sids[0] assert self._api_my_curated_groups_by_sid( client, sid=sample_sid) == [coe_advisor_groups[0].id]
def download_csv(curated_group_id): benchmark = get_benchmarker( f'curated group {curated_group_id} download_csv') benchmark('begin') curated_group = CuratedGroup.find_by_id(curated_group_id) params = request.get_json() fieldnames = get_param(params, 'csvColumnsSelected', []) if not curated_group: raise ResourceNotFoundError( f'No curated group found with id: {curated_group_id}') if not _can_current_user_view_curated_group(curated_group): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, cannot view curated group {curated_group.id}' ) return response_with_students_csv_download( sids=CuratedGroup.get_all_sids(curated_group_id), fieldnames=fieldnames, benchmark=benchmark)
def test_update_curated_group_lists(self, app): from boac.api.cache_utils import update_curated_group_lists curated_group = CuratedGroup.create( owner_id=AuthorizedUser.find_by_uid('6446').id, name='This group has one student not in Data Loch', ) original_sids = ['3456789012', '5678901234', '7890123456'] for sid in original_sids: CuratedGroup.add_student(curated_group.id, sid) sid_not_in_data_loch = '19040616' CuratedGroup.add_student(curated_group.id, sid_not_in_data_loch) std_commit(allow_test_environment=True) revised_sids = CuratedGroupStudent.get_sids(curated_group.id) assert sid_not_in_data_loch in revised_sids update_curated_group_lists() std_commit(allow_test_environment=True) final_sids = CuratedGroupStudent.get_sids(curated_group.id) assert sid_not_in_data_loch not in final_sids assert set(final_sids) == set(original_sids)
def get_my_curated_groups(): benchmark = get_benchmarker('my_curated_groups') curated_groups = [] user_id = current_user.get_id() for curated_group in CuratedGroup.get_curated_groups(owner_id=user_id): students = [{ 'sid': sid } for sid in CuratedGroup.get_all_sids(curated_group.id)] students_with_alerts = Alert.include_alert_counts_for_students( benchmark=benchmark, viewer_user_id=user_id, group={'students': students}, count_only=True, ) curated_groups.append({ **curated_group.to_api_json(include_students=False), 'alertCount': sum(s['alertCount'] for s in students_with_alerts), 'sids': [student['sid'] for student in students], 'totalStudentCount': len(students), }) return curated_groups
def add_students_to_curated_group(): params = request.get_json() curated_group_id = params.get('curatedGroupId') return_student_profiles = params.get('returnStudentProfiles') sids = [sid for sid in set(params.get('sids')) if sid.isdigit()] if not curated_group_id or not len(sids): raise BadRequestError( 'The required parameters are \'curatedGroupId\' and \'sids\'.') curated_group = CuratedGroup.find_by_id(curated_group_id) if not curated_group: raise ResourceNotFoundError( f'No curated group found where id={curated_group_id}') if curated_group.owner_id != current_user.get_id(): raise ForbiddenRequestError( f'Current user, {current_user.get_uid()}, does not own curated group {curated_group.id}' ) CuratedGroup.add_students(curated_group_id=curated_group_id, sids=sids) if return_student_profiles: return tolerant_jsonify( _curated_group_with_complete_student_profiles( curated_group_id=curated_group_id)) else: group = CuratedGroup.find_by_id(curated_group_id) return tolerant_jsonify(group.to_api_json(include_students=False))
def all_curated_groups(): scope = get_query_scope(current_user) uids = AuthorizedUser.get_all_uids_in_scope(scope) groups_per_uid = dict((uid, []) for uid in uids) for group in CuratedGroup.get_groups_owned_by_uids(uids=uids): groups_per_uid[group['ownerUid']].append(group) api_json = [] for uid, user in calnet.get_calnet_users_for_uids(app, uids).items(): groups = groups_per_uid[uid] api_json.append({ 'user': user, 'groups': sorted(groups, key=lambda g: g['name']), }) api_json = sorted( api_json, key=lambda v: v['user']['name'] or f"UID: {v['user']['uid']}") return tolerant_jsonify(api_json)
def admin_curated_groups(): user = AuthorizedUser.find_by_uid(admin_uid) return CuratedGroup.get_curated_groups_by_owner_id(user.id)
def asc_curated_groups(): advisor = AuthorizedUser.find_by_uid(asc_advisor_uid) return CuratedGroup.get_curated_groups(advisor.id)
def curated_group_ids_per_sid(sid): return tolerant_jsonify( CuratedGroup.curated_group_ids_per_sid(user_id=current_user.get_id(), sid=sid))
def coe_advisor_groups(): advisor = AuthorizedUser.find_by_uid(coe_advisor_uid) return CuratedGroup.get_curated_groups_by_owner_id(advisor.id)
def _create_curated_groups(): admin_user = AuthorizedUser.find_by_uid('2040') CuratedGroup.create(admin_user.id, 'My Students') asc_advisor = AuthorizedUser.find_by_uid('6446') CuratedGroup.create(asc_advisor.id, 'My Students') curated_group = CuratedGroup.create(asc_advisor.id, 'Four students') CuratedGroup.add_student(curated_group.id, '3456789012') CuratedGroup.add_student(curated_group.id, '5678901234') CuratedGroup.add_student(curated_group.id, '11667051') CuratedGroup.add_student(curated_group.id, '7890123456') coe_advisor = AuthorizedUser.find_by_uid('1133399') curated_group = CuratedGroup.create(coe_advisor.id, 'I have one student') CuratedGroup.add_student(curated_group.id, '7890123456') std_commit(allow_test_environment=True)
def _get_sids_per_curated_groups(curated_group_ids=None): sids = set() for curated_group_id in curated_group_ids or (): if curated_group_id: sids = sids.union(CuratedGroup.get_all_sids(curated_group_id)) return sids