Esempio n. 1
0
def validate_sids():
    params = request.get_json()
    sids = [sid.strip() for sid in list(params.get('sids'))]
    domain = params.get('domain') or 'default'
    if is_unauthorized_domain(domain):
        raise ForbiddenRequestError(
            f'You are unauthorized to query the \'{domain}\' domain')
    if sids:
        if next((sid for sid in sids if not sid.isnumeric()), None):
            raise BadRequestError('Each SID must be numeric')
        else:
            summary = []
            if domain == 'admitted_students':
                available_sids = [
                    row['sid']
                    for row in get_admitted_students_by_sids(offset=0,
                                                             sids=sids)
                ]
            else:
                available_sids = query_students(
                    sids=sids, sids_only=True,
                    academic_career_status=('all'))['sids']
            for sid in sids:
                summary.append({
                    'sid': sid,
                    'status': 200 if sid in available_sids else 404,
                })
            return tolerant_jsonify(summary)
    else:
        raise BadRequestError('Requires \'sids\' param')
Esempio n. 2
0
 def to_api_json(self, include_students, order_by='last_name', offset=0, limit=50):
     benchmark = get_benchmarker(f'CuratedGroup {self.id} to_api_json')
     benchmark('begin')
     sids = CuratedGroupStudent.get_sids(curated_group_id=self.id)
     feed = {
         'domain': self.domain,
         'id': self.id,
         'name': self.name,
         'ownerId': self.owner_id,
         'sids': sids,
         'totalStudentCount': len(sids),
     }
     if include_students:
         if sids:
             if self.domain == 'admitted_students':
                 feed['students'] = get_admitted_students_by_sids(
                     limit=limit,
                     offset=offset,
                     order_by=order_by,
                     sids=sids,
                 )
             else:
                 result = query_students(
                     sids=sids,
                     academic_career_status=('all'),
                     include_profiles=False,
                     order_by=order_by,
                     offset=offset,
                     limit=limit,
                 )
                 feed['students'] = result['students']
         else:
             feed['students'] = []
     benchmark('end')
     return feed
Esempio n. 3
0
 def to_api_json(self, order_by='last_name', offset=0, limit=50, include_students=True):
     feed = {
         'id': self.id,
         'ownerId': self.owner_id,
         'name': self.name,
     }
     if include_students:
         sids = CuratedGroupStudent.get_sids(curated_group_id=self.id)
         if sids:
             result = query_students(sids=sids, order_by=order_by, offset=offset, limit=limit, include_profiles=False)
             feed['students'] = result['students']
             feed['studentCount'] = result['totalStudentCount']
         else:
             feed['students'] = []
             feed['studentCount'] = 0
     return feed
Esempio n. 4
0
def validate_sids():
    params = request.get_json()
    sids = [sid.strip() for sid in list(params.get('sids'))]
    if sids:
        if next((sid for sid in sids if not sid.isnumeric()), None):
            raise BadRequestError(f'Each SID must be numeric')
        else:
            summary = []
            available_sids = query_students(sids=sids, sids_only=True)['sids']
            for sid in sids:
                summary.append({
                    'sid': sid,
                    'status': 200 if sid in available_sids else 404,
                })
            return tolerant_jsonify(summary)
    else:
        raise BadRequestError('Requires \'sids\' param')
Esempio n. 5
0
def get_students():
    params = request.get_json()
    if is_unauthorized_search(params):
        raise ForbiddenRequestError(
            'You are unauthorized to access student data managed by other departments'
        )
    results = query_students(
        advisor_ldap_uids=util.get(params, 'advisorLdapUids'),
        coe_prep_statuses=util.get(params, 'coePrepStatuses'),
        ethnicities=util.get(params, 'ethnicities'),
        genders=util.get(params, 'genders'),
        gpa_ranges=util.get(params, 'gpaRanges'),
        group_codes=util.get(params, 'groupCodes'),
        include_profiles=True,
        is_active_asc=_convert_asc_inactive_arg(
            util.get(params, 'isInactiveAsc')),
        in_intensive_cohort=util.to_bool_or_none(
            util.get(params, 'inIntensiveCohort')),
        last_name_range=_get_name_range_boundaries(
            util.get(params, 'lastNameRange')),
        levels=util.get(params, 'levels'),
        limit=util.get(params, 'limit', 50),
        majors=util.get(params, 'majors'),
        offset=util.get(params, 'offset', 0),
        order_by=util.get(params, 'orderBy', None),
        underrepresented=util.get(params, 'underrepresented'),
        unit_ranges=util.get(params, 'unitRanges'),
    )
    if results is None:
        raise BadRequestError('Invalid search criteria')
    alert_counts = Alert.current_alert_counts_for_viewer(current_user.id)
    students = results['students'] if results else []
    add_alert_counts(alert_counts, students)
    return tolerant_jsonify({
        'students':
        students,
        'totalStudentCount':
        results['totalStudentCount'] if results else 0,
    })
Esempio n. 6
0
 def to_api_json(self,
                 order_by='last_name',
                 offset=0,
                 limit=50,
                 include_students=True):
     feed = {
         'id': self.id,
         'ownerId': self.owner_id,
         'name': self.name,
     }
     if include_students:
         sids = CuratedGroupStudent.get_sids(curated_group_id=self.id)
         if sids:
             result = query_students(sids=sids,
                                     order_by=order_by,
                                     offset=offset,
                                     limit=limit,
                                     include_profiles=False)
             feed['students'] = result['students']
             feed['totalStudentCount'] = result['totalStudentCount']
             # Attempt to supplement with historical student rows if we seem to be missing something.
             if result['totalStudentCount'] < len(sids):
                 remaining_sids = list(set(sids) - set(result['sids']))
                 historical_sid_rows = query_historical_sids(remaining_sids)
                 if len(historical_sid_rows):
                     for row in historical_sid_rows:
                         ManuallyAddedAdvisee.find_or_create(row['sid'])
                     feed['totalStudentCount'] += len(historical_sid_rows)
                     page_shortfall = max(0,
                                          limit - len(result['students']))
                     feed[
                         'students'] += historical_sid_rows[:page_shortfall]
         else:
             feed['students'] = []
             feed['totalStudentCount'] = 0
     return feed
Esempio n. 7
0
    def to_api_json(
        self,
        order_by=None,
        offset=0,
        limit=50,
        alert_offset=None,
        alert_limit=None,
        include_sids=False,
        include_students=True,
        include_profiles=False,
        include_alerts_for_user_id=None,
    ):
        benchmark = get_benchmarker(f'CohortFilter {self.id} to_api_json')
        benchmark('begin')
        c = self.filter_criteria
        c = c if isinstance(c, dict) else json.loads(c)
        coe_advisor_ldap_uids = util.get(c, 'coeAdvisorLdapUids')
        if not isinstance(coe_advisor_ldap_uids, list):
            coe_advisor_ldap_uids = [coe_advisor_ldap_uids
                                     ] if coe_advisor_ldap_uids else None
        cohort_name = self.name
        cohort_json = {
            'id': self.id,
            'code': self.id,
            'name': cohort_name,
            'owners': [],
            'alertCount': self.alert_count,
        }
        for owner in self.owners:
            cohort_json['owners'].append({
                'uid':
                owner.uid,
                'deptCodes': [
                    m.university_dept.dept_code
                    for m in owner.department_memberships
                ],
            })
        coe_ethnicities = c.get('coeEthnicities')
        coe_genders = c.get('coeGenders')
        coe_prep_statuses = c.get('coePrepStatuses')
        coe_probation = util.to_bool_or_none(c.get('coeProbation'))
        coe_underrepresented = util.to_bool_or_none(
            c.get('coeUnderrepresented'))
        cohort_owner_academic_plans = util.get(c, 'cohortOwnerAcademicPlans')
        entering_terms = c.get('enteringTerms')
        ethnicities = c.get('ethnicities')
        expected_grad_terms = c.get('expectedGradTerms')
        genders = c.get('genders')
        gpa_ranges = c.get('gpaRanges')
        group_codes = c.get('groupCodes')
        in_intensive_cohort = util.to_bool_or_none(c.get('inIntensiveCohort'))
        is_inactive_asc = util.to_bool_or_none(c.get('isInactiveAsc'))
        is_inactive_coe = util.to_bool_or_none(c.get('isInactiveCoe'))
        last_name_ranges = c.get('lastNameRanges')
        last_term_gpa_ranges = c.get('lastTermGpaRanges')
        levels = c.get('levels')
        majors = c.get('majors')
        midpoint_deficient_grade = util.to_bool_or_none(
            c.get('midpointDeficient'))
        team_groups = athletics.get_team_groups(
            group_codes) if group_codes else []
        transfer = util.to_bool_or_none(c.get('transfer'))
        underrepresented = util.to_bool_or_none(c.get('underrepresented'))
        unit_ranges = c.get('unitRanges')
        cohort_json.update({
            'criteria': {
                'coeAdvisorLdapUids': coe_advisor_ldap_uids,
                'coeEthnicities': coe_ethnicities,
                'coeGenders': coe_genders,
                'coePrepStatuses': coe_prep_statuses,
                'coeProbation': coe_probation,
                'coeUnderrepresented': coe_underrepresented,
                'cohortOwnerAcademicPlans': cohort_owner_academic_plans,
                'enteringTerms': entering_terms,
                'ethnicities': ethnicities,
                'expectedGradTerms': expected_grad_terms,
                'genders': genders,
                'gpaRanges': gpa_ranges,
                'groupCodes': group_codes,
                'inIntensiveCohort': in_intensive_cohort,
                'isInactiveAsc': is_inactive_asc,
                'isInactiveCoe': is_inactive_coe,
                'lastNameRanges': last_name_ranges,
                'lastTermGpaRanges': last_term_gpa_ranges,
                'levels': levels,
                'majors': majors,
                'midpointDeficient': midpoint_deficient_grade,
                'transfer': transfer,
                'unitRanges': unit_ranges,
                'underrepresented': underrepresented,
            },
            'teamGroups': team_groups,
        })
        if not include_students and not include_alerts_for_user_id and self.student_count is not None:
            # No need for a students query; return the database-stashed student count.
            cohort_json.update({
                'totalStudentCount': self.student_count,
            })
            benchmark('end')
            return cohort_json

        benchmark('begin students query')
        sids_only = not include_students

        # Translate the "My Students" filter, if present, into queryable criteria. Although our database relationships allow
        # for multiple cohort owners, we assume a single owner here since the "My Students" filter makes no sense
        # in any other scenario.
        if cohort_owner_academic_plans:
            if self.owners:
                owner_sid = get_csid_for_uid(app, self.owners[0].uid)
            else:
                owner_sid = current_user.get_csid()
            advisor_plan_mappings = [{
                'advisor_sid': owner_sid,
                'academic_plan_code': plan
            } for plan in cohort_owner_academic_plans]
        else:
            advisor_plan_mappings = None

        results = query_students(
            advisor_plan_mappings=advisor_plan_mappings,
            coe_advisor_ldap_uids=coe_advisor_ldap_uids,
            coe_ethnicities=coe_ethnicities,
            coe_genders=coe_genders,
            coe_prep_statuses=coe_prep_statuses,
            coe_probation=coe_probation,
            coe_underrepresented=coe_underrepresented,
            entering_terms=entering_terms,
            ethnicities=ethnicities,
            expected_grad_terms=expected_grad_terms,
            genders=genders,
            gpa_ranges=gpa_ranges,
            group_codes=group_codes,
            in_intensive_cohort=in_intensive_cohort,
            include_profiles=(include_students and include_profiles),
            is_active_asc=None
            if is_inactive_asc is None else not is_inactive_asc,
            is_active_coe=None
            if is_inactive_coe is None else not is_inactive_coe,
            last_name_ranges=last_name_ranges,
            last_term_gpa_ranges=last_term_gpa_ranges,
            levels=levels,
            limit=limit,
            majors=majors,
            midpoint_deficient_grade=midpoint_deficient_grade,
            offset=offset,
            order_by=order_by,
            sids_only=sids_only,
            transfer=transfer,
            underrepresented=underrepresented,
            unit_ranges=unit_ranges,
        )
        benchmark('end students query')

        if results:
            # Cohort might have tens of thousands of SIDs.
            if include_sids:
                cohort_json['sids'] = results['sids']
            cohort_json.update({
                'totalStudentCount':
                results['totalStudentCount'],
            })
            # If the cohort is new or cache refresh is underway then store student_count and sids in the db.
            if self.student_count is None:
                self.update_sids_and_student_count(
                    results['sids'], results['totalStudentCount'])
            if include_students:
                cohort_json.update({
                    'students': results['students'],
                })
            if include_alerts_for_user_id:
                benchmark('begin alerts query')
                alert_count_per_sid = Alert.include_alert_counts_for_students(
                    viewer_user_id=include_alerts_for_user_id,
                    group=results,
                    offset=alert_offset,
                    limit=alert_limit,
                )
                benchmark('end alerts query')
                cohort_json.update({
                    'alerts': alert_count_per_sid,
                })
                if self.alert_count is None:
                    alert_count = sum(student['alertCount']
                                      for student in alert_count_per_sid)
                    self.update_alert_count(alert_count)
                    cohort_json.update({
                        'alertCount': alert_count,
                    })
        benchmark('end')
        return cohort_json
Esempio n. 8
0
def _query_students(
    benchmark,
    criteria,
    include_profiles,
    limit,
    offset,
    order_by,
    owner,
    sids_only,
    term_id,
):
    benchmark('begin students query')
    # Translate the "My Students" filter, if present, into queryable criteria.
    plans = criteria.get('cohortOwnerAcademicPlans')
    if plans:
        if owner:
            owner_sid = get_csid_for_uid(app, owner.uid)
        else:
            owner_sid = current_user.get_csid()
        advisor_plan_mappings = [{
            'advisor_sid': owner_sid,
            'academic_plan_code': plan
        } for plan in plans]
    else:
        advisor_plan_mappings = None
    coe_advisor_ldap_uids = util.get(criteria, 'coeAdvisorLdapUids')
    if not isinstance(coe_advisor_ldap_uids, list):
        coe_advisor_ldap_uids = [coe_advisor_ldap_uids
                                 ] if coe_advisor_ldap_uids else None
    results = query_students(
        academic_standings=criteria.get('academicStandings'),
        advisor_plan_mappings=advisor_plan_mappings,
        coe_advisor_ldap_uids=coe_advisor_ldap_uids,
        coe_ethnicities=criteria.get('coeEthnicities'),
        coe_genders=criteria.get('coeGenders'),
        coe_prep_statuses=criteria.get('coePrepStatuses'),
        coe_probation=criteria.get('coeProbation'),
        coe_underrepresented=criteria.get('coeUnderrepresented'),
        colleges=criteria.get('colleges'),
        curated_group_ids=criteria.get('curatedGroupIds'),
        entering_terms=criteria.get('enteringTerms'),
        epn_cpn_grading_terms=criteria.get('epnCpnGradingTerms'),
        ethnicities=criteria.get('ethnicities'),
        expected_grad_terms=criteria.get('expectedGradTerms'),
        genders=criteria.get('genders'),
        gpa_ranges=criteria.get('gpaRanges'),
        group_codes=criteria.get('groupCodes'),
        in_intensive_cohort=criteria.get('inIntensiveCohort'),
        include_profiles=include_profiles,
        intended_majors=criteria.get('intendedMajors'),
        is_active_asc=None if criteria.get('isInactiveAsc') is None else
        not criteria.get('isInactiveAsc'),
        is_active_coe=None if criteria.get('isInactiveCoe') is None else
        not criteria.get('isInactiveCoe'),
        last_name_ranges=criteria.get('lastNameRanges'),
        last_term_gpa_ranges=criteria.get('lastTermGpaRanges'),
        levels=criteria.get('levels'),
        limit=limit,
        majors=criteria.get('majors'),
        midpoint_deficient_grade=criteria.get('midpointDeficient'),
        minors=criteria.get('minors'),
        offset=offset,
        order_by=order_by,
        sids_only=sids_only,
        term_id=term_id,
        transfer=criteria.get('transfer'),
        underrepresented=criteria.get('underrepresented'),
        unit_ranges=criteria.get('unitRanges'),
        visa_types=criteria.get('visaTypes'),
        student_holds=criteria.get('studentHolds'),
    )
    benchmark('end students query')
    return results
Esempio n. 9
0
    def to_api_json(
        self,
        order_by=None,
        offset=0,
        limit=50,
        include_students=True,
        include_profiles=False,
        include_alerts_for_uid=None,
    ):
        c = self.filter_criteria
        c = c if isinstance(c, dict) else json.loads(c)
        advisor_ldap_uids = util.get(c, 'advisorLdapUids')
        if not isinstance(advisor_ldap_uids, list):
            advisor_ldap_uids = [advisor_ldap_uids
                                 ] if advisor_ldap_uids else None
        cohort_name = self.label
        cohort_json = {
            'id': self.id,
            'code': self.id,
            'label': cohort_name,
            'name': cohort_name,
            'owners': [user.uid for user in self.owners],
        }
        coe_prep_statuses = c.get('coePrepStatuses')
        ethnicities = c.get('ethnicities')
        genders = c.get('genders')
        gpa_ranges = c.get('gpaRanges')
        group_codes = c.get('groupCodes')
        in_intensive_cohort = util.to_bool_or_none(c.get('inIntensiveCohort'))
        is_inactive_asc = util.to_bool_or_none(c.get('isInactiveAsc'))
        last_name_range = c.get('lastNameRange')
        levels = c.get('levels')
        majors = c.get('majors')
        team_groups = athletics.get_team_groups(
            group_codes) if group_codes else []
        underrepresented = util.to_bool_or_none(c.get('underrepresented'))
        unit_ranges = c.get('unitRanges')
        cohort_json.update({
            'filterCriteria': {
                'advisorLdapUids': advisor_ldap_uids,
                'coePrepStatuses': coe_prep_statuses,
                'ethnicities': ethnicities,
                'genders': genders,
                'gpaRanges': gpa_ranges,
                'groupCodes': group_codes,
                'inIntensiveCohort': in_intensive_cohort,
                'isInactiveAsc': is_inactive_asc,
                'lastNameRange': last_name_range,
                'levels': levels,
                'majors': majors,
                'unitRanges': unit_ranges,
                'underrepresented': underrepresented,
            },
            'teamGroups': team_groups,
        })

        if not include_students and not include_alerts_for_uid and self.student_count is not None:
            # No need for a students query; return the database-stashed student count.
            cohort_json.update({
                'totalStudentCount': self.student_count,
            })
            return cohort_json
        owner = self.owners[0] if len(self.owners) else None
        if owner and 'UWASC' in get_dept_codes(owner):
            is_active_asc = not is_inactive_asc
        else:
            is_active_asc = None if is_inactive_asc is None else not is_inactive_asc
        sids_only = not include_students
        results = query_students(
            advisor_ldap_uids=advisor_ldap_uids,
            coe_prep_statuses=coe_prep_statuses,
            ethnicities=ethnicities,
            genders=genders,
            gpa_ranges=gpa_ranges,
            group_codes=group_codes,
            in_intensive_cohort=in_intensive_cohort,
            include_profiles=(include_students and include_profiles),
            is_active_asc=is_active_asc,
            last_name_range=last_name_range,
            levels=levels,
            limit=limit,
            majors=majors,
            offset=offset,
            order_by=order_by,
            sids_only=sids_only,
            underrepresented=underrepresented,
            unit_ranges=unit_ranges,
        )
        if results:
            # If the cohort is newly created or a cache refresh is underway, store the student count in the database
            # to save future queries.
            if self.student_count is None:
                self.update_student_count(results['totalStudentCount'])
            cohort_json.update({
                'totalStudentCount':
                results['totalStudentCount'],
            })
            if include_students:
                cohort_json.update({
                    'students': results['students'],
                })
            if include_alerts_for_uid:
                alert_counts = Alert.include_alert_counts_for_students(
                    viewer_uid=include_alerts_for_uid, cohort=results)
                cohort_json.update({
                    'alerts': alert_counts,
                })
        return cohort_json