Beispiel #1
0
def create_cohort():
    params = request.get_json()
    if is_unauthorized_search(params):
        raise ForbiddenRequestError(
            'You are unauthorized to access student data managed by other departments'
        )
    label = util.get(params, 'label', None)
    if not label:
        raise BadRequestError('Cohort creation requires \'label\'')
    cohort = CohortFilter.create(
        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'),
        in_intensive_cohort=util.to_bool_or_none(
            params.get('inIntensiveCohort')),
        is_inactive_asc=util.to_bool_or_none(params.get('isInactiveAsc')),
        label=label,
        last_name_range=util.get(params, 'lastNameRange'),
        levels=util.get(params, 'levels'),
        majors=util.get(params, 'majors'),
        uid=current_user.get_id(),
        underrepresented=util.get(params, 'underrepresented'),
        unit_ranges=util.get(params, 'unitRanges'),
    )
    return tolerant_jsonify(decorate_cohort(cohort))
Beispiel #2
0
 def test_to_bool_or_none(self):
     """If None is not False in your use case then use this util."""
     assert util.to_bool_or_none(None) is None
     assert util.to_bool_or_none('true') is True
     assert util.to_bool_or_none('false') is False
     assert util.to_bool_or_none('FALSE') is False
     assert util.to_bool_or_none('blargh') is None
Beispiel #3
0
def _update_or_create_authorized_user(memberships,
                                      profile,
                                      include_deleted=False):
    user_id = profile.get('id')
    automate_degree_progress_permission = profile.get(
        'automateDegreeProgressPermission')
    can_access_canvas_data = to_bool_or_none(
        profile.get('canAccessCanvasData'))
    can_access_advising_data = to_bool_or_none(
        profile.get('canAccessAdvisingData'))
    degree_progress_permission = profile.get('degreeProgressPermission')

    if (automate_degree_progress_permission or degree_progress_permission
        ) and 'COENG' not in dept_codes_where_advising(
            {'departments': memberships}):
        raise errors.BadRequestError(
            'Degree Progress feature is only available to the College of Engineering.'
        )

    is_admin = to_bool_or_none(profile.get('isAdmin'))
    is_blocked = to_bool_or_none(profile.get('isBlocked'))
    if user_id:
        user = AuthorizedUser.update_user(
            automate_degree_progress_permission=
            automate_degree_progress_permission,
            can_access_advising_data=can_access_advising_data,
            can_access_canvas_data=can_access_canvas_data,
            degree_progress_permission=degree_progress_permission,
            include_deleted=include_deleted,
            is_admin=is_admin,
            is_blocked=is_blocked,
            user_id=user_id,
        )
        UserSession.flush_cache_for_id(user_id=user_id)
        return user
    else:
        uid = profile.get('uid')
        if AuthorizedUser.get_id_per_uid(uid, include_deleted=True):
            raise errors.BadRequestError(
                f'User with UID {uid} is already in the BOA database.')

        calnet_user = calnet.get_calnet_user_for_uid(app,
                                                     uid,
                                                     skip_expired_users=True)
        if calnet_user and calnet_user.get('csid', None):
            return AuthorizedUser.create_or_restore(
                automate_degree_progress_permission=
                automate_degree_progress_permission,
                can_access_advising_data=can_access_advising_data,
                can_access_canvas_data=can_access_canvas_data,
                created_by=current_user.get_uid(),
                degree_progress_permission=degree_progress_permission,
                is_admin=is_admin,
                is_blocked=is_blocked,
                uid=uid,
            )
        else:
            raise errors.BadRequestError('Invalid UID')
Beispiel #4
0
def create_topic():
    params = request.json
    topic = params.get('topic', '').strip()
    available_in_notes = to_bool_or_none(
        params.get('availableInNotes')) or False
    available_in_appointments = to_bool_or_none(
        params.get('availableInAppointments')) or False
    if not topic or not (available_in_notes or available_in_appointments):
        raise BadRequestError('Required parameters are missing.')
    topic = Topic.create_topic(
        topic,
        available_in_notes=available_in_notes,
        available_in_appointments=available_in_appointments,
    )
    return tolerant_jsonify(topic.to_api_json())
def get_admin_users():
    params = request.get_json()
    ignore_deleted = to_bool_or_none(util.get(params, 'ignoreDeleted'))
    users = AuthorizedUser.get_admin_users(
        ignore_deleted=True if ignore_deleted is None else ignore_deleted)
    return tolerant_jsonify({
        'users':
        authorized_users_api_feed(
            users,
            sort_by=util.get(params, 'sortBy'),
            sort_descending=to_bool_or_none(util.get(params,
                                                     'sortDescending')),
        ),
        'totalUserCount':
        len(users),
    })
Beispiel #6
0
def update_note():
    params = request.form
    body = params.get('body', None)
    is_private = to_bool_or_none(params.get('isPrivate', False))
    note_id = params.get('id', None)
    subject = params.get('subject', None)
    topics = get_note_topics_from_http_post()

    note = Note.find_by_id(note_id=note_id) if note_id else None
    if not note:
        raise ResourceNotFoundError('Note not found')
    if not subject:
        raise BadRequestError('Note subject is required')
    if note.author_uid != current_user.get_uid():
        raise ForbiddenRequestError(
            'Sorry, you are not the author of this note.')
    if (is_private is not note.is_private
        ) and not current_user.can_access_private_notes:
        raise ForbiddenRequestError(
            'Sorry, you are not authorized to manage note privacy')

    note = Note.update(
        body=process_input_from_rich_text_editor(body),
        is_private=is_private,
        note_id=note_id,
        subject=subject,
        topics=topics,
    )
    note_read = NoteRead.find_or_create(current_user.get_id(), note_id)
    return tolerant_jsonify(
        _boa_note_to_compatible_json(note=note, note_read=note_read))
Beispiel #7
0
def get_cohort(cohort_id):
    if is_unauthorized_search(request.args):
        raise ForbiddenRequestError(
            'You are unauthorized to access student data managed by other departments'
        )
    include_students = util.to_bool_or_none(
        util.get(request.args, 'includeStudents'))
    include_students = True if include_students is None else include_students
    order_by = util.get(request.args, 'orderBy', None)
    offset = util.get(request.args, 'offset', 0)
    limit = util.get(request.args, 'limit', 50)
    cohort = CohortFilter.find_by_id(int(cohort_id))
    if cohort and can_view_cohort(current_user, cohort):
        cohort = decorate_cohort(
            cohort,
            order_by=order_by,
            offset=int(offset),
            limit=int(limit),
            include_alerts_for_uid=current_user.uid,
            include_profiles=True,
            include_students=include_students,
        )
        return tolerant_jsonify(cohort)
    else:
        raise ResourceNotFoundError(
            f'No cohort found with identifier: {cohort_id}')
def update_note_template():
    params = request.form
    note_template_id = params.get('id', None)
    subject = params.get('subject', None)
    if not subject:
        raise BadRequestError('Requires \'subject\'')
    body = params.get('body', None)
    topics = get_note_topics_from_http_post()
    delete_ids_ = params.get('deleteAttachmentIds') or []
    delete_ids_ = delete_ids_ if isinstance(
        delete_ids_, list) else str(delete_ids_).split(',')
    delete_attachment_ids = [int(id_) for id_ in delete_ids_]
    note_template = NoteTemplate.find_by_id(note_template_id=note_template_id)
    if not note_template:
        raise ResourceNotFoundError('Template not found')
    if note_template.creator_id != current_user.get_id():
        raise ForbiddenRequestError('Template not available.')
    note_template = NoteTemplate.update(
        attachments=get_note_attachments_from_http_post(tolerate_none=True),
        body=process_input_from_rich_text_editor(body),
        delete_attachment_ids=delete_attachment_ids,
        is_private=to_bool_or_none(params.get('isPrivate', False)),
        note_template_id=note_template_id,
        subject=subject,
        topics=topics,
    )
    return tolerant_jsonify(note_template.to_api_json())
def create_or_update_user_profile():
    params = request.get_json()
    profile = params.get('profile', None)
    memberships = params.get('memberships', None)
    delete_action = to_bool_or_none(util.get(params, 'deleteAction'))

    if not profile or not profile.get('uid') or memberships is None:
        raise errors.BadRequestError('Required parameters are missing')

    authorized_user = _update_or_create_authorized_user(memberships,
                                                        profile,
                                                        include_deleted=True)
    _delete_existing_memberships(authorized_user)
    _create_department_memberships(authorized_user, memberships)

    if delete_action is True and not authorized_user.deleted_at:
        AuthorizedUser.delete(authorized_user.uid)
    elif delete_action is False and authorized_user.deleted_at:
        AuthorizedUser.un_delete(authorized_user.uid)

    user_id = authorized_user.id
    UserSession.flush_cache_for_id(user_id)

    updated_user = AuthorizedUser.find_by_id(user_id, include_deleted=True)
    users_json = authorized_users_api_feed([updated_user])
    return tolerant_jsonify(users_json and users_json[0])
def create_note_template():
    params = request.form
    title = params.get('title', None)
    subject = params.get('subject', None)
    body = params.get('body', None)
    topics = get_note_topics_from_http_post()
    if not title or not subject:
        raise BadRequestError(
            'Note creation requires \'subject\' and \'title\'')
    user_dept_codes = dept_codes_where_advising(current_user)
    if current_user.is_admin or not len(user_dept_codes):
        raise ForbiddenRequestError(
            'Sorry, only advisors can create advising note templates')

    attachments = get_note_attachments_from_http_post(tolerate_none=True)

    note_template = NoteTemplate.create(
        attachments=attachments,
        body=process_input_from_rich_text_editor(body),
        creator_id=current_user.get_id(),
        is_private=to_bool_or_none(params.get('isPrivate', False)),
        subject=subject,
        title=title,
        topics=topics,
    )
    return tolerant_jsonify(note_template.to_api_json())
def user_by_uid(uid):
    ignore_deleted = to_bool_or_none(util.get(request.args, 'ignoreDeleted'))
    user = _find_user_by_uid(uid, ignore_deleted)
    if user:
        users_feed = authorized_users_api_feed([user])
        return tolerant_jsonify(users_feed[0])
    else:
        raise errors.ResourceNotFoundError('User not found')
Beispiel #12
0
def create_notes():
    benchmark = get_benchmarker('create_notes')
    params = request.form
    sids = _get_sids_for_note_creation()
    benchmark(f'SID count: {len(sids)}')
    body = params.get('body', None)
    is_private = to_bool_or_none(params.get('isPrivate', False))
    subject = params.get('subject', None)
    topics = get_note_topics_from_http_post()
    if not sids or not subject:
        benchmark('end (BadRequest)')
        raise BadRequestError(
            'Note creation requires \'subject\' and \'sids\'')

    dept_codes = dept_codes_where_advising(current_user)
    if current_user.is_admin or not len(dept_codes):
        benchmark('end (Forbidden)')
        raise ForbiddenRequestError(
            'Sorry, only advisors can create advising notes')
    if is_private and not current_user.can_access_private_notes:
        benchmark('end (Forbidden)')
        raise ForbiddenRequestError(
            'Sorry, you are not authorized to manage note privacy.')

    attachments = get_note_attachments_from_http_post(tolerate_none=True)
    benchmark(f'Attachment count: {len(attachments)}')
    body = process_input_from_rich_text_editor(body)
    template_attachment_ids = get_template_attachment_ids_from_http_post()

    if len(sids) == 1:
        note = Note.create(
            **_get_author_profile(),
            attachments=attachments,
            body=body,
            is_private=is_private,
            sid=sids[0],
            subject=subject,
            template_attachment_ids=template_attachment_ids,
            topics=topics,
        )
        response = tolerant_jsonify(
            _boa_note_to_compatible_json(note, note_read=True))
    else:
        response = tolerant_jsonify(
            Note.create_batch(
                **_get_author_profile(),
                attachments=attachments,
                author_id=current_user.to_api_json()['id'],
                body=body,
                is_private=is_private,
                sids=sids,
                subject=subject,
                template_attachment_ids=template_attachment_ids,
                topics=topics,
            ), )
    benchmark('end')
    return response
Beispiel #13
0
def assign_course(course_id):
    params = request.get_json()
    course = DegreeProgressCourse.find_by_id(course_id)
    if course:
        # Get existing category assignment. If it's a placeholder then delete it at end of transaction.
        previous_category = DegreeProgressCategory.find_by_id(
            course.category_id) if course.category_id else None
        category_id = get_param(params, 'categoryId')
        category = DegreeProgressCategory.find_by_id(
            category_id) if category_id else None
        if category:
            if category.template_id != course.degree_check_id:
                raise BadRequestError(
                    'The category and course do not belong to the same degree_check instance.'
                )
            children = DegreeProgressCategory.find_by_parent_category_id(
                parent_category_id=category_id)
            if next((c for c in children if c.category_type == 'Subcategory'),
                    None):
                raise BadRequestError(
                    'A course cannot be assigned to a category with a subcategory.'
                )
            course = DegreeProgressCourse.assign(category_id=category_id,
                                                 course_id=course.id)

        else:
            # When user un-assigns a course we delete all copies of that course,.
            for copy_of_course in DegreeProgressCourse.get_courses(
                    degree_check_id=course.degree_check_id,
                    manually_created_at=course.manually_created_at,
                    manually_created_by=course.manually_created_by,
                    section_id=course.section_id,
                    sid=course.sid,
                    term_id=course.term_id,
            ):
                if copy_of_course.id != course.id:
                    DegreeProgressCourseUnitRequirement.delete(
                        copy_of_course.id)
                    category = DegreeProgressCategory.find_by_id(
                        copy_of_course.category_id)
                    if category and 'Placeholder' in category.category_type:
                        DegreeProgressCategory.delete(category.id)
                    DegreeProgressCourse.delete(copy_of_course)
            ignore = to_bool_or_none(get_param(params, 'ignore'))
            course = DegreeProgressCourse.unassign(course_id=course.id,
                                                   ignore=ignore)

        # If previous assignment was a "placeholder" category then delete it.
        if previous_category and 'Placeholder' in previous_category.category_type:
            DegreeProgressCategory.delete(previous_category.id)

        # Update updated_at date of top-level record
        DegreeProgressTemplate.refresh_updated_at(course.degree_check_id,
                                                  current_user.get_id())
        return tolerant_jsonify(course.to_api_json())
    else:
        raise ResourceNotFoundError('Course not found.')
Beispiel #14
0
def get_student_by_uid(uid):
    profile_only = to_bool_or_none(request.args.get('profileOnly'))
    student = get_student_and_terms_by_uid(uid)
    if not student:
        raise ResourceNotFoundError('Unknown student')
    if not profile_only:
        put_notifications(student)
        _put_degree_checks_json(student)
    return tolerant_jsonify(student)
def all_users():
    params = request.get_json()
    users, total_user_count = AuthorizedUser.get_users(
        blocked=to_bool_or_none(util.get(params, 'blocked')),
        deleted=to_bool_or_none(util.get(params, 'deleted')),
        dept_code=util.get(params, 'deptCode', None),
        role=util.get(params, 'role', None) or None,
    )
    return tolerant_jsonify({
        'users':
        authorized_users_api_feed(
            users,
            sort_by=util.get(params, 'sortBy', 'lastName'),
            sort_descending=to_bool_or_none(
                util.get(params, 'sortDescending', False)),
        ),
        'totalUserCount':
        total_user_count,
    })
def get_departments():
    exclude_empty = to_bool_or_none(
        util.get(request.args, 'excludeEmpty', None))
    api_json = []
    for d in UniversityDept.get_all(exclude_empty=exclude_empty):
        api_json.append({
            'id': d.id,
            'code': d.dept_code,
            'name': d.dept_name,
        })
    return tolerant_jsonify(api_json)
Beispiel #17
0
def get_all_topics():
    include_appointments = app.config['FEATURE_FLAG_ADVISOR_APPOINTMENTS']
    include_deleted = to_bool_or_none(request.args.get('includeDeleted'))
    if include_appointments:
        topics = Topic.get_all(include_deleted=include_deleted)
    else:
        topics = Topic.get_all(available_in_notes=True,
                               include_deleted=include_deleted)
    if not app.config['FEATURE_FLAG_ADVISOR_APPOINTMENTS']:
        for index, topic in enumerate(topics):
            if not topic.available_in_notes:
                topics.pop(index)
    return tolerant_jsonify(_to_api_json(topics))
Beispiel #18
0
    def to_base_json(self):
        c = self.filter_criteria
        c = c if isinstance(c, dict) else json.loads(c)
        user_uid = self.owner.uid if self.owner else None
        option_groups = CohortFilterOptions(
            user_uid, scope_for_criteria()).get_filter_option_groups()
        for label, option_group in option_groups.items():
            for option in option_group:
                key = option['key']
                if key in c:
                    value = c.get(key)
                    if option['type']['db'] == 'boolean':
                        c[key] = util.to_bool_or_none(value)
                    else:
                        c[key] = value

        def _owner_to_json(owner):
            if not owner:
                return None
            return {
                'uid':
                owner.uid,
                'deptCodes': [
                    m.university_dept.dept_code
                    for m in owner.department_memberships
                ],
            }

        return {
            'id':
            self.id,
            'domain':
            self.domain,
            'name':
            self.name,
            'code':
            self.id,
            'criteria':
            c,
            'owner':
            _owner_to_json(self.owner),
            'teamGroups':
            athletics.get_team_groups(c.get('groupCodes'))
            if c.get('groupCodes') else [],
            'alertCount':
            self.alert_count,
        }
def _create_department_memberships(authorized_user, memberships):
    for membership in [
            m for m in memberships
            if m['role'] in ('advisor', 'director', 'scheduler')
    ]:
        university_dept = UniversityDept.find_by_dept_code(membership['code'])
        role = membership['role']
        UniversityDeptMember.create_or_update_membership(
            university_dept_id=university_dept.id,
            authorized_user_id=authorized_user.id,
            role=role,
            automate_membership=to_bool_or_none(
                membership['automateMembership']),
        )
        if role == 'scheduler':
            _delete_drop_in_advisor_status(authorized_user,
                                           university_dept.dept_code)
        UserSession.flush_cache_for_id(authorized_user.id)
Beispiel #20
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,
    })
Beispiel #21
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
Beispiel #22
0
def get_topics_for_notes():
    include_deleted = to_bool_or_none(request.args.get('includeDeleted'))
    topics = Topic.get_all(available_in_notes=True,
                           include_deleted=include_deleted)
    return tolerant_jsonify(_to_sorted_json(topics))
Beispiel #23
0
def get_all_topics():
    include_deleted = to_bool_or_none(request.args.get('includeDeleted'))
    topics = Topic.get_all(include_deleted=include_deleted)
    return tolerant_jsonify(_to_sorted_json(topics))
Beispiel #24
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
Beispiel #25
0
def _is_service_announcement_published():
    is_published = ToolSetting.get_tool_setting(
        'SERVICE_ANNOUNCEMENT_IS_PUBLISHED')
    return False if is_published is None else to_bool_or_none(is_published)
Beispiel #26
0
def publish_service_announcement():
    publish = to_bool_or_none(request.get_json().get('publish'))
    if publish is None:
        raise BadRequestError('API requires \'publish\' arg')
    ToolSetting.upsert('SERVICE_ANNOUNCEMENT_IS_PUBLISHED', publish)
    return tolerant_jsonify(_get_service_announcement())
Beispiel #27
0
def get_topics():
    include_deleted = to_bool_or_none(request.args.get('includeDeleted'))
    topics = Topic.get_all(include_deleted=include_deleted)
    return tolerant_jsonify([topic.to_api_json() for topic in topics])