def add_appointment_scheduler_to_dept(dept_code):
    _verify_membership_and_appointments_enabled(current_user, dept_code)
    params = request.get_json() or {}
    scheduler_uid = params.get('uid', None)
    if not scheduler_uid:
        raise errors.BadRequestError('Scheduler UID missing')
    calnet_user = calnet.get_calnet_user_for_uid(app,
                                                 scheduler_uid,
                                                 skip_expired_users=True)
    if not calnet_user or not calnet_user.get('csid'):
        raise errors.BadRequestError('Invalid scheduler UID')
    user = AuthorizedUser.create_or_restore(
        scheduler_uid,
        created_by=current_user.get_uid(),
        is_admin=False,
        is_blocked=False,
        can_access_canvas_data=False,
    )
    Scheduler.create_or_update_membership(
        dept_code,
        user.id,
        drop_in=True,
        same_day=True,
    )
    _create_department_memberships(user, [{
        'code': dept_code,
        'role': 'scheduler',
        'automateMembership': False
    }])
    UserSession.flush_cache_for_id(user.id)
    return tolerant_jsonify(
        _get_appointment_scheduler_list(current_user, dept_code))
def _update_drop_in_availability(uid, dept_code, new_availability):
    dept_code = dept_code.upper()
    if uid != current_user.get_uid():
        authorized_to_toggle = current_user.is_admin or dept_code in [
            d['code']
            for d in current_user.departments if d.get('role') == 'scheduler'
        ]
        if not authorized_to_toggle:
            raise errors.ForbiddenRequestError(
                f'Unauthorized to toggle drop-in availability for department {dept_code}'
            )
    drop_in_membership = None
    user = AuthorizedUser.find_by_uid(uid)
    if user:
        drop_in_membership = next(
            (d for d in user.drop_in_departments if d.dept_code == dept_code),
            None)
    if drop_in_membership:
        if drop_in_membership.is_available is True and new_availability is False:
            Appointment.unreserve_all_for_advisor(uid, current_user.get_id())
        drop_in_membership.update_availability(new_availability)
        UserSession.flush_cache_for_id(user.id)
        return tolerant_jsonify(drop_in_membership.to_api_json())
    else:
        raise errors.ResourceNotFoundError(
            f'No drop-in advisor membership found: (uid={uid}, dept_code={dept_code})'
        )
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])
Exemple #4
0
def _update_drop_in_status(uid, dept_code, active):
    dept_code = dept_code.upper()
    if uid == 'me':
        uid = current_user.get_uid()
    else:
        authorized_to_toggle = current_user.is_admin or dept_code in [
            d['code'] for d in current_user.departments if d.get('isScheduler')
        ]
        if not authorized_to_toggle:
            raise errors.ForbiddenRequestError(
                f'Unauthorized to toggle drop-in status for department {dept_code}'
            )
    drop_in_status = None
    user = AuthorizedUser.find_by_uid(uid)
    if user:
        drop_in_status = next(
            (d for d in user.drop_in_departments if d.dept_code == dept_code),
            None)
    if drop_in_status:
        drop_in_status.update_availability(active)
        UserSession.flush_cache_for_id(user.id)
        return tolerant_jsonify(drop_in_status.to_api_json())
    else:
        raise errors.ResourceNotFoundError(
            f'No drop-in advisor status found: (uid={uid}, dept_code={dept_code})'
        )
def enable_same_day_advising(dept_code):
    same_day_membership = SameDayAdvisor.create_or_update_membership(
        dept_code,
        current_user.user_id,
        is_available=True,
    )
    UserSession.flush_cache_for_id(current_user.user_id)
    return tolerant_jsonify(same_day_membership.to_api_json())
def enable_drop_in_advising(dept_code):
    drop_in_membership = DropInAdvisor.create_or_update_membership(
        dept_code,
        current_user.user_id,
        is_available=False,
    )
    UserSession.flush_cache_for_id(current_user.user_id)
    return tolerant_jsonify(drop_in_membership.to_api_json())
Exemple #7
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')
def set_drop_in_advising_status(dept_code):
    user = AuthorizedUser.find_by_id(current_user.get_id())
    drop_in_membership = next((d for d in user.drop_in_departments
                               if d.dept_code == dept_code.upper()), None)
    if not drop_in_membership:
        raise errors.ResourceNotFoundError(
            f'No drop-in advisor membership found: (uid={current_user.get_uid()}, dept_code={dept_code})'
        )
    params = request.get_json()
    if 'status' not in params:
        raise errors.BadRequestError('Missing status')
    if params['status'] and len(params['status']) > 255:
        raise errors.BadRequestError('Invalid status')
    drop_in_membership.update_status(params['status'])
    UserSession.flush_cache_for_id(user.id)
    return tolerant_jsonify(drop_in_membership.to_api_json())
Exemple #9
0
def _dev_auth_login(uid, password):
    if app.config['DEVELOPER_AUTH_ENABLED']:
        logger = app.logger
        if password != app.config['DEVELOPER_AUTH_PASSWORD']:
            logger.error('Dev-auth: Wrong password')
            return tolerant_jsonify({'message': 'Invalid credentials'}, 401)
        user_id = AuthorizedUser.get_id_per_uid(uid)
        if user_id is None:
            logger.error(
                f'Dev-auth: User with UID {uid} is not registered in BOA.')
            return tolerant_jsonify(
                {
                    'message':
                    f'Sorry, user with UID {uid} is not registered to use BOA.'
                }, 403)

        user = UserSession(user_id=user_id, flush_cached=True)
        if not user.is_active:
            logger.error(
                f'Dev-auth: UID {uid} is registered with BOA but not active.')
            return tolerant_jsonify(
                {
                    'message':
                    f'Sorry, user with UID {uid} is not authorized to use BOA.'
                }, 403)
        logger.info(f'Dev-auth used to log in as UID {uid}')

        login_user(user, force=True, remember=True)
        UserLogin.record_user_login(uid)
        return tolerant_jsonify(current_user.to_api_json())
    else:
        raise ResourceNotFoundError('Unknown path')
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)
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()
        login_user(UserSession(user_id=user.id, flush_cached=True),
                   force=True,
                   remember=True)
        return tolerant_jsonify(current_user.to_api_json())
    else:
        raise errors.ResourceNotFoundError('Unknown path')
Exemple #12
0
def cas_login():
    logger = app.logger
    ticket = request.args['ticket']
    target_url = request.args.get('url')
    uid, attributes, proxy_granting_ticket = _cas_client(
        target_url).verify_ticket(ticket)
    logger.info(f'Logged into CAS as user {uid}')
    user_id = AuthorizedUser.get_id_per_uid(uid)

    if user_id is None:
        logger.error(f'UID {uid} is not an authorized user.')
        param = ('error', f"""
            Sorry, you are not registered to use BOA.
            Please <a href="mailto:{app.config['BOAC_SUPPORT_EMAIL']}">email us</a> for assistance.
        """)
        redirect_url = add_param_to_url('/', param)

    else:
        user = UserSession(user_id=user_id, flush_cached=True)
        if not user.is_active:
            logger.error(
                f'UID {uid} is in the BOA db but is not authorized to use the tool.'
            )
            param = ('error', f"""
                Sorry, you are not registered to use BOA.
                Please <a href="mailto:{app.config['BOAC_SUPPORT_EMAIL']}">email us</a> for assistance.
            """)
            redirect_url = add_param_to_url('/', param)
        else:
            login_user(user)
            flash('Logged in successfully.')
            UserLogin.record_user_login(uid)

            # Check if url is safe for redirects per https://flask-login.readthedocs.io/en/latest/
            if not _is_safe_url(request.args.get('next')):
                return abort(400)
            if not target_url:
                target_url = '/'
            # Our googleAnalyticsService uses 'casLogin' marker to track CAS login events
            redirect_url = add_param_to_url(target_url, ('casLogin', 'true'))

    return redirect(redirect_url)
Exemple #13
0
 def _user_loader(user_id=None, flush_cached=False):
     return UserSession(user_id, flush_cached)
def disable_same_day_advising(dept_code):
    user = AuthorizedUser.find_by_id(current_user.get_id())
    SameDayAdvisor.delete(authorized_user_id=user.id, dept_code=dept_code)
    UserSession.flush_cache_for_id(user.id)
    return tolerant_jsonify(
        {'message': 'Same-day advisor status has been disabled'}, status=200)
def disable_drop_in_advising(dept_code):
    user = AuthorizedUser.find_by_id(current_user.get_id())
    _delete_drop_in_advisor_status(user, dept_code)
    UserSession.flush_cache_for_id(user.id)
    return tolerant_jsonify(
        {'message': 'Drop-in advisor status has been disabled'}, status=200)