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})'
        )
Exemple #2
0
 def test_search_by_appointment_cancel_reason(self, coe_advisor, client):
     """Appointments can be searched for by cancel reason and cancel reason explained."""
     appointment = Appointment.find_by_id(1)
     Appointment.cancel(
         appointment_id=appointment.id,
         canceled_by=AuthorizedUser.get_id_per_uid('6972201'),
         cancel_reason='Sick cat',
         cancel_reason_explained=
         'Student needed to attend to ailing feline.',
     )
     response = client.post(
         '/api/search',
         data=json.dumps({
             'appointments': True,
             'notes': True,
             'searchPhrase': 'cat'
         }),
         content_type='application/json',
     )
     self._assert(response, appointment_count=1)
     response = client.post(
         '/api/search',
         data=json.dumps({
             'appointments': True,
             'notes': True,
             'searchPhrase': 'feline'
         }),
         content_type='application/json',
     )
     self._assert(response, appointment_count=1)
Exemple #3
0
def appointment_check_in(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    if appointment.dept_code in _dept_codes_with_scheduler_privilege():
        params = request.get_json()
        advisor_uid = params.get('advisorUid', None)
        if not advisor_uid:
            raise BadRequestError(
                'Appointment check-in requires \'advisor_uid\'')
        appointment = Appointment.check_in(
            appointment_id=appointment_id,
            checked_in_by=current_user.get_id(),
            advisor_dept_codes=params.get('advisorDeptCodes', None),
            advisor_name=params.get('advisorName', None),
            advisor_role=params.get('advisorRole', None),
            advisor_uid=advisor_uid,
        )
        api_json = appointment.to_api_json(current_user.get_id())
        _put_student_profile_per_appointment([api_json])
        return tolerant_jsonify(api_json)
    else:
        raise ForbiddenRequestError(
            f'You are unauthorized to manage {appointment.dept_code} appointments.'
        )
Exemple #4
0
def _create_reserved_appointments():
    coe_advisor_user_id = AuthorizedUser.get_id_per_uid('90412')
    reserve_me = Appointment.create(
        appointment_type='Drop-in',
        created_by=coe_advisor_user_id,
        dept_code='COENG',
        details='I will reserve this appointment.',
        student_sid='7890123456',
        topics=['Whoops'],
    )
    Appointment.reserve(appointment_id=reserve_me.id,
                        reserved_by=coe_advisor_user_id)
 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 _create_reserved_appointments():
    coe_advisor_attrs = _advisor_attrs_for_uid('90412')
    reserve_me = Appointment.create(
        appointment_type='Drop-in',
        created_by=coe_advisor_attrs['id'],
        dept_code='COENG',
        details='I will reserve this appointment.',
        student_sid='7890123456',
        topics=['Whoops'],
    )
    Appointment.reserve(appointment_id=reserve_me.id,
                        reserved_by=coe_advisor_attrs['id'],
                        advisor_attrs=coe_advisor_attrs)
Exemple #7
0
def create_appointment():
    params = request.get_json()
    dept_code = params.get('deptCode', None)
    sid = params.get('sid', None)
    advisor_uid = params.get('advisorUid', None)
    appointment_type = params.get('appointmentType', None)
    topics = params.get('topics', None)
    if not dept_code or not sid or not appointment_type or not len(topics):
        raise BadRequestError(
            'Appointment creation: required parameters were not provided')
    dept_code = dept_code.upper()
    if dept_code not in BERKELEY_DEPT_CODE_TO_NAME:
        raise ResourceNotFoundError(
            f'Unrecognized department code: {dept_code}')
    if dept_code not in _dept_codes_with_scheduler_privilege():
        raise ForbiddenRequestError(
            f'You are unauthorized to manage {dept_code} appointments.')
    appointment = Appointment.create(
        advisor_uid=advisor_uid,
        appointment_type=appointment_type,
        created_by=current_user.get_id(),
        dept_code=dept_code,
        details=params.get('details', None),
        student_sid=sid,
        topics=topics,
    )
    AppointmentRead.find_or_create(current_user.get_id(), appointment.id)
    api_json = appointment.to_api_json(current_user.get_id())
    _put_student_profile_per_appointment([api_json])
    return tolerant_jsonify(api_json)
Exemple #8
0
 def test_search_with_no_input_and_date(self, coe_advisor, client):
     """Notes and appointments search needs no input when date options are set."""
     from boac import db, std_commit
     appointment = Appointment.find_by_id(2)
     appointment.created_at = util.localized_timestamp_to_utc(
         '2017-11-01T00:00:00')
     std_commit()
     db.session.refresh(appointment)
     response = client.post(
         '/api/search',
         data=json.dumps({
             'appointments': True,
             'notes': True,
             'searchPhrase': '',
             'appointmentOptions': {
                 'dateFrom': '2017-11-01',
                 'dateTo': '2017-11-02'
             },
             'noteOptions': {
                 'dateFrom': '2017-11-01',
                 'dateTo': '2017-11-02'
             },
         }),
         content_type='application/json',
     )
     self._assert(response, note_count=4, appointment_count=1)
Exemple #9
0
def get_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    api_json = appointment.to_api_json(current_user.get_id())
    _put_student_profile_per_appointment([api_json])
    return tolerant_jsonify(api_json)
 def test_appointment_cancel(self, app, client, fake_auth):
     """Drop-in advisor can cancel 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._cancel_appointment(client, waiting['id'],
                                            'Canceled by wolves')
     appointment_id = appointment['id']
     assert appointment_id == waiting['id']
     assert appointment['status'] == 'canceled'
     assert appointment['statusBy']['id'] == user.id
     assert appointment['statusBy']['uid'] == user.uid
     assert appointment['statusDate'] is not None
     Appointment.delete(appointment_id)
Exemple #11
0
    def test_search_by_appointment_cancel_reason(self, coe_advisor, client):
        """Appointments can be searched for by cancel reason and cancel reason explained."""
        appointment = Appointment.find_by_id(1)
        Appointment.cancel(
            appointment_id=appointment.id,
            cancelled_by=AuthorizedUser.get_id_per_uid('6972201'),
            cancel_reason='Sick cat',
            cancel_reason_explained=
            'Student needed to attend to ailing feline.',
        )

        api_json = _api_search(client, 'cat', appointments=True)
        self._assert(api_json, appointment_count=1)

        api_json = _api_search(client, 'feline', appointments=True)
        self._assert(api_json, appointment_count=1)
def get_waitlist(dept_code):
    def _is_current_user_authorized():
        return current_user.is_admin or dept_code in _dept_codes_with_scheduler_privilege()

    dept_code = dept_code.upper()
    if dept_code not in BERKELEY_DEPT_CODE_TO_NAME:
        raise ResourceNotFoundError(f'Unrecognized department code: {dept_code}')
    elif _is_current_user_authorized():
        show_all_statuses = current_user.is_drop_in_advisor or current_user.is_admin
        statuses = appointment_event_type.enums if show_all_statuses else ['reserved', 'waiting']
        unresolved = []
        resolved = []
        for appointment in Appointment.get_drop_in_waitlist(dept_code, statuses):
            a = appointment.to_api_json(current_user.get_id())
            if a['status'] in ['reserved', 'waiting']:
                unresolved.append(a)
            else:
                resolved.append(a)
        _put_student_profile_per_appointment(unresolved)
        _put_student_profile_per_appointment(resolved)
        return tolerant_jsonify({
            'advisors': drop_in_advisors_for_dept_code(dept_code),
            'waitlist': {
                'unresolved': unresolved,
                'resolved': resolved,
            },
        })
    else:
        raise ForbiddenRequestError(f'You are unauthorized to manage {dept_code} appointments.')
def update_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    has_privilege = current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege()
    if not has_privilege:
        raise ForbiddenRequestError(f'You are unauthorized to manage {appointment.dept_code} appointments.')
    params = request.get_json()
    details = params.get('details', None)
    scheduled_time = params.get('scheduledTime', None)
    if scheduled_time:
        scheduled_time = localized_timestamp_to_utc(scheduled_time)
    student_contact_info = params.get('studentContactInfo', None)
    student_contact_type = params.get('studentContactType', None)
    topics = params.get('topics', None)
    appointment.update(
        details=process_input_from_rich_text_editor(details),
        scheduled_time=scheduled_time,
        student_contact_info=student_contact_info,
        student_contact_type=student_contact_type,
        topics=topics,
        updated_by=current_user.get_id(),
    )
    api_json = appointment.to_api_json(current_user.get_id())
    _put_student_profile_per_appointment([api_json])
    return tolerant_jsonify(api_json)
def _create_cancelled_appointments():
    coe_advisor_user_id = AuthorizedUser.get_id_per_uid('90412')
    scheduler_user_id = AuthorizedUser.get_id_per_uid('6972201')
    cancel_me = Appointment.create(
        appointment_type='Drop-in',
        created_by=coe_advisor_user_id,
        dept_code='COENG',
        details='We will cancel this appointment.',
        student_sid='7890123456',
        topics=['Whoops'],
    )
    Appointment.cancel(
        appointment_id=cancel_me.id,
        cancelled_by=scheduler_user_id,
        cancel_reason='Just because',
        cancel_reason_explained='I felt like it.',
    )
def search_advising_appointments(
    search_phrase,
    advisor_csid=None,
    advisor_uid=None,
    student_csid=None,
    topic=None,
    datetime_from=None,
    datetime_to=None,
    offset=0,
    limit=20,
):
    benchmark = get_benchmarker('search_advising_appointments')
    benchmark('begin')

    if search_phrase:
        search_terms = list({t.group(0) for t in list(re.finditer(TEXT_SEARCH_PATTERN, search_phrase)) if t})
        search_phrase = ' & '.join(search_terms)
    else:
        search_terms = []

    advisor_uid = get_uid_for_csid(app, advisor_csid) if (not advisor_uid and advisor_csid) else advisor_uid

    benchmark('begin local appointments query')
    appointments_feed = Appointment.search(
        search_phrase=search_phrase,
        advisor_uid=advisor_uid,
        student_csid=student_csid,
        topic=topic,
        datetime_from=datetime_from,
        datetime_to=datetime_to,
        limit=limit,
        offset=offset,
    )
    benchmark('end local appointments query')

    local_appointments_count = len(appointments_feed)
    if local_appointments_count == limit:
        return appointments_feed

    benchmark('begin loch appointments query')
    loch_results = data_loch.search_advising_appointments(
        search_phrase=search_phrase,
        advisor_uid=advisor_uid,
        advisor_csid=advisor_csid,
        student_csid=student_csid,
        topic=topic,
        datetime_from=datetime_from,
        datetime_to=datetime_to,
        offset=max(0, offset - local_appointments_count),
        limit=(limit - local_appointments_count),
    )
    benchmark('end loch appointments query')

    benchmark('begin loch appointments parsing')
    appointments_feed += _get_loch_appointments_search_results(loch_results, search_terms)
    benchmark('end loch appointments parsing')

    return appointments_feed
Exemple #16
0
def reserve_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')

    has_privilege = current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege(
    )
    if has_privilege and appointment.status in ('reserved', 'waiting'):
        appointment = Appointment.reserve(
            appointment_id=appointment_id,
            reserved_by=current_user.get_id(),
        )
        api_json = appointment.to_api_json(current_user.get_id())
        _put_student_profile_per_appointment([api_json])
        return tolerant_jsonify(api_json)
    else:
        raise ForbiddenRequestError(
            f'You are unauthorized to manage appointment {appointment_id}.')
def appointment_check_in(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    if appointment.dept_code not in _dept_codes_with_scheduler_privilege():
        raise ForbiddenRequestError(f'You are unauthorized to manage {appointment.dept_code} appointments.')
    if not appointment.status_change_available():
        raise BadRequestError(appointment.to_api_json(current_user.get_id()))
    params = request.get_json()
    advisor_attrs = _advisor_attrs_for_uid(params.get('advisorUid'))
    if not advisor_attrs:
        raise BadRequestError('Appointment reservation requires valid "advisorUid"')
    Appointment.check_in(
        appointment_id=appointment_id,
        checked_in_by=current_user.get_id(),
        advisor_attrs=advisor_attrs,
    )
    return Response(status=200)
 def test_advisor_read_appointment(self, app, client, fake_auth):
     """L&S advisor reads an appointment."""
     fake_auth.login(l_s_college_scheduler_uid)
     # As scheduler, create appointment
     appointment = AppointmentTestUtil.create_appointment(client, 'QCADV')
     appointment_id = appointment['id']
     client.get('/api/auth/logout')
     # Verify unread by advisor
     uid = l_s_college_advisor_uid
     user_id = AuthorizedUser.get_id_per_uid(uid)
     assert AppointmentRead.was_read_by(user_id, appointment_id) is False
     # Next, log in as advisor and read the appointment
     fake_auth.login(uid)
     api_json = self._mark_appointment_read(client, appointment_id)
     assert api_json['appointmentId'] == appointment_id
     assert api_json['viewerId'] == user_id
     assert AppointmentRead.was_read_by(user_id, appointment_id) is True
     Appointment.delete(appointment_id)
def cancel_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    has_privilege = current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege()
    if not has_privilege:
        raise ForbiddenRequestError(f'You are unauthorized to manage {appointment.dept_code} appointments.')
    if not appointment.status_change_available():
        raise BadRequestError(appointment.to_api_json(current_user.get_id()))
    params = request.get_json()
    cancel_reason = params.get('cancelReason', None)
    cancel_reason_explained = params.get('cancelReasonExplained', None)
    Appointment.cancel(
        appointment_id=appointment_id,
        cancelled_by=current_user.get_id(),
        cancel_reason=cancel_reason,
        cancel_reason_explained=cancel_reason_explained,
    )
    return Response(status=200)
Exemple #20
0
def _appointments_search(search_phrase, params):
    appointment_options = util.get(params, 'appointmentOptions', {})
    advisor_uid = appointment_options.get('advisorUid')
    advisor_csid = appointment_options.get('advisorCsid')
    student_csid = appointment_options.get('studentCsid')
    topic = appointment_options.get('topic')
    limit = int(util.get(appointment_options, 'limit', 20))
    offset = int(util.get(appointment_options, 'offset', 0))

    date_from = appointment_options.get('dateFrom')
    date_to = appointment_options.get('dateTo')

    if not len(search_phrase) and not (advisor_uid or advisor_csid
                                       or student_csid or topic or date_from
                                       or date_to):
        raise BadRequestError('Invalid or empty search input')

    if advisor_csid and not advisor_uid:
        advisor_uid = get_uid_for_csid(app, advisor_csid)

    if date_from:
        try:
            datetime_from = util.localized_timestamp_to_utc(
                f'{date_from}T00:00:00')
        except ValueError:
            raise BadRequestError('Invalid dateFrom value')
    else:
        datetime_from = None

    if date_to:
        try:
            datetime_to = util.localized_timestamp_to_utc(
                f'{date_to}T00:00:00') + timedelta(days=1)
        except ValueError:
            raise BadRequestError('Invalid dateTo value')
    else:
        datetime_to = None

    if datetime_from and datetime_to and datetime_to <= datetime_from:
        raise BadRequestError('dateFrom must be less than dateTo')

    appointment_results = Appointment.search(
        search_phrase=search_phrase,
        advisor_uid=advisor_uid,
        student_csid=student_csid,
        topic=topic,
        datetime_from=datetime_from,
        datetime_to=datetime_to,
        offset=offset,
        limit=limit,
    )
    return {
        'appointments': appointment_results,
    }
def unreserve_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    has_privilege = current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege()
    if not has_privilege:
        raise ForbiddenRequestError(f'You are unauthorized to manage appointment {appointment_id}.')
    if appointment.status != 'reserved':
        raise BadRequestError(appointment.to_api_json(current_user.get_id()))
    _set_appointment_to_waiting(appointment)
    return Response(status=200)
def get_non_legacy_advising_appointments(sid):
    appointments_by_id = {}
    for row in Appointment.get_appointments_per_sid(sid):
        appointment = row.__dict__
        appointment_id = appointment['id']
        event = appointment_event_to_json(appointment_id, row.status)
        appointments_by_id[str(appointment_id)] = appointment_to_compatible_json(
            appointment=appointment,
            topics=[t.to_api_json() for t in row.topics if not t.deleted_at],
            event=event,
        )
    return appointments_by_id
Exemple #23
0
def cancel_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')
    if current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege(
    ):
        params = request.get_json()
        cancel_reason = params.get('cancelReason', None)
        cancel_reason_explained = params.get('cancelReasonExplained', None)
        appointment = Appointment.cancel(
            appointment_id=appointment_id,
            canceled_by=current_user.get_id(),
            cancel_reason=cancel_reason,
            cancel_reason_explained=cancel_reason_explained,
        )
        api_json = appointment.to_api_json(current_user.get_id())
        _put_student_profile_per_appointment([api_json])
        return tolerant_jsonify(api_json)
    else:
        raise ForbiddenRequestError(
            f'You are unauthorized to manage {appointment.dept_code} appointments.'
        )
    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_appointment_as_coe_scheduler(self, client, fake_auth):
     """Scheduler can create appointments."""
     fake_auth.login(coe_scheduler_uid)
     details = 'Aloysius has some questions.'
     appointment = AppointmentTestUtil.create_appointment(
         client, 'COENG', details)
     appointment_id = appointment['id']
     waitlist = self._get_waitlist(client, 'COENG')
     matching = next((a for a in waitlist if a['details'] == details), None)
     assert matching
     assert appointment_id == matching['id']
     assert appointment['read'] is True
     assert appointment['status'] == 'waiting'
     assert appointment['student']['sid'] == '3456789012'
     assert appointment['student']['name'] == 'Paul Kerschen'
     assert appointment['student']['photoUrl']
     assert appointment['appointmentType'] == 'Drop-in'
     assert len(appointment['topics']) == 2
     # Verify that a deleted appointment is off the waitlist
     Appointment.delete(appointment_id)
     waitlist = self._get_waitlist(client, 'COENG')
     assert next(
         (a for a in waitlist if a['details'] == details), None) is None
Exemple #26
0
def unreserve_appointment(appointment_id):
    appointment = Appointment.find_by_id(appointment_id)
    if not appointment:
        raise ResourceNotFoundError('Unknown path')

    has_privilege = current_user.is_admin or appointment.dept_code in _dept_codes_with_scheduler_privilege(
    )
    if has_privilege and appointment.status == 'reserved':
        event = AppointmentEvent.get_most_recent_per_type(
            appointment.id, 'reserved')
        if event.user_id == current_user.get_id():
            appointment = Appointment.unreserve(
                appointment_id=appointment_id,
                unreserved_by=current_user.get_id(),
            )
            api_json = appointment.to_api_json(current_user.get_id())
            _put_student_profile_per_appointment([api_json])
            return tolerant_jsonify(api_json)
        else:
            raise ForbiddenRequestError(
                f'You did not reserve appointment {appointment_id}.')
    else:
        raise ForbiddenRequestError(
            f'You are unauthorized to manage appointment {appointment_id}.')
Exemple #27
0
def find_appointment_advisors_by_name():
    query = request.args.get('q')
    if not query:
        raise BadRequestError('Search query must be supplied')
    limit = request.args.get('limit')
    query_fragments = filter(None, query.upper().split(' '))
    advisors = Appointment.find_advisors_by_name(query_fragments, limit=limit)

    def _advisor_feed(a):
        return {
            'label': a.advisor_name,
            'uid': a.advisor_uid,
        }

    return tolerant_jsonify([_advisor_feed(a) for a in advisors])
Exemple #28
0
    def test_search_respects_date_filters(self, app, coe_advisor, client):
        """Search results include appointments created within provided date range."""
        from boac import std_commit
        appointment = Appointment.find_by_id(2)
        appointment.created_at = util.localized_timestamp_to_utc(
            '2017-10-31T00:00:00')
        std_commit(allow_test_environment=True)

        api_json = _api_search(
            client,
            'pick me',
            appointments=True,
            appointment_options={
                'dateFrom': '2017-10-31',
                'dateTo': '2017-11-01',
            },
        )
        self._assert(api_json, appointment_count=1)
Exemple #29
0
    def test_appointment_search_with_no_input_and_date(self, coe_advisor,
                                                       client):
        """Appointments search needs no input when date options are set."""
        from boac import db, std_commit
        appointment = Appointment.find_by_id(2)
        appointment.created_at = util.localized_timestamp_to_utc(
            '2017-11-01T00:00:00')
        std_commit()
        db.session.refresh(appointment)

        api_json = _api_search(
            client,
            '',
            appointments=True,
            appointment_options={
                'dateFrom': '2017-11-01',
                'dateTo': '2017-11-02'
            },
        )
        self._assert(api_json, appointment_count=3)
def get_today_scheduled_appointments(dept_code):
    def _is_current_user_authorized():
        return current_user.is_admin or dept_code in _dept_codes_with_scheduler_privilege()

    dept_code = dept_code.upper()
    if dept_code not in BERKELEY_DEPT_CODE_TO_NAME:
        raise ResourceNotFoundError(f'Unrecognized department code: {dept_code}')
    elif _is_current_user_authorized():
        local_today = localize_datetime(utc_now())
        advisor_uid = request.args.get('advisorUid')
        scheduled_for_today = Appointment.get_scheduled(dept_code, local_today, advisor_uid)
        appointments = [a.to_api_json(current_user.get_id()) for a in scheduled_for_today]
        openings = AppointmentAvailability.get_openings(dept_code, local_today, appointments)
        _put_student_profile_per_appointment(appointments)
        return tolerant_jsonify({
            'appointments': appointments,
            'openings': openings,
        })
    else:
        raise ForbiddenRequestError(f'You are unauthorized to manage {dept_code} appointments.')