Skip to content

Commit bf6741b

Browse files
committed
allow admin to cancel appointments
1 parent 7c0a892 commit bf6741b

4 files changed

Lines changed: 80 additions & 1 deletion

File tree

src/docs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};
5252
specialists::add_specialty,
5353
specialists::list_specialties,
5454
specialists::upload_license,
55+
specialists::get_patient_profile,
5556
appointments::get_appointments,
5657
appointments::create_appointment,
5758
appointments::confirm_appointment,

src/handlers/specialists.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,49 @@ pub async fn upload_license(
354354
url,
355355
))
356356
}
357+
358+
/// Get patient profile for a specialist
359+
///
360+
/// Retrieves a patient's full profile including appointments and donation history.
361+
#[utoipa::path(
362+
get,
363+
path = "/api/specialists/patients/{id}",
364+
responses(
365+
(status = 200, body = ApiResponse<crate::admin::dtos::AdminPatientProfileResponse>),
366+
(status = 401, description = "Unauthorized"),
367+
(status = 403, description = "Forbidden"),
368+
(status = 404, description = "User not found"),
369+
(status = 500)
370+
),
371+
tag = "specialists",
372+
security(("bearer_auth" = []))
373+
)]
374+
pub async fn get_patient_profile(
375+
State(state): State<AppState>,
376+
Extension(user): Extension<User>,
377+
Path(patient_id): Path<Uuid>,
378+
) -> Result<ApiResponse<crate::admin::dtos::AdminPatientProfileResponse>, AppError> {
379+
use crate::schema::users;
380+
use crate::utils::enums::Role;
381+
382+
if user.role != Role::Specialist {
383+
return Err(AppError::Unauthorized("Only specialists can access this".into()));
384+
}
385+
386+
let mut conn = state.pool.get()?;
387+
388+
// Fetch user to check that they are actually a patient
389+
let target_user = users::table
390+
.find(patient_id)
391+
.select(User::as_select())
392+
.first::<User>(&mut conn)
393+
.map_err(|_| AppError::NotFound("Patient not found".into()))?;
394+
395+
match target_user.role {
396+
Role::Patient | Role::Donor | Role::PatientDonor => {
397+
let profile = crate::admin::dashboard::get_admin_patient_profile(&mut conn, patient_id)?;
398+
Ok(ApiResponse::success(profile))
399+
}
400+
_ => Err(AppError::BadRequest("User is not a patient".into()))
401+
}
402+
}

src/hospitals/appointments.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,17 @@ pub fn reschedule_appointment(
111111
Role::Donor | Role::Patient | Role::PatientDonor => {
112112
assert_user_owns_appointment(conn, appointment_id, user.id)?;
113113
}
114-
_ => return Err(AppError::Unauthorized("Invalid role".into())),
114+
Role::Specialist => {
115+
assert_specialist_owns_appointment(conn, appointment_id, user.id)?;
116+
}
117+
Role::Admin => {
118+
// user role is admin. if role is admin, allow it.
119+
appointments::table
120+
.filter(appointments::id.eq(appointment_id))
121+
.select(Appointment::as_select())
122+
.first(conn)
123+
.map_err(|_| AppError::NotFound("Appointment not found".into()))?;
124+
}
115125
}
116126

117127
diesel::update(appointments::table.find(appointment_id))
@@ -271,6 +281,14 @@ pub fn cancel_appointment(
271281
Role::Donor | Role::Patient | Role::PatientDonor => {
272282
assert_user_owns_appointment(conn, appointment_id, user.id)?
273283
}
284+
Role::Specialist => assert_specialist_owns_appointment(conn, appointment_id, user.id)?,
285+
Role::Admin => {
286+
appointments::table
287+
.filter(appointments::id.eq(appointment_id))
288+
.select(Appointment::as_select())
289+
.first(conn)
290+
.map_err(|_| AppError::NotFound("Appointment not found".into()))?
291+
}
274292
_ => return Err(AppError::Unauthorized("Invalid role".into())),
275293
};
276294

@@ -343,3 +361,16 @@ fn assert_user_owns_appointment(
343361
.first(conn)
344362
.map_err(|_| AppError::Unauthorized("Appointment not owned by user".into()))
345363
}
364+
365+
fn assert_specialist_owns_appointment(
366+
conn: &mut PgConnection,
367+
appointment_id: Uuid,
368+
specialist_id: Uuid,
369+
) -> Result<Appointment, AppError> {
370+
appointments::table
371+
.filter(appointments::id.eq(appointment_id))
372+
.filter(appointments::specialist_id.eq(specialist_id))
373+
.select(Appointment::as_select())
374+
.first(conn)
375+
.map_err(|_| AppError::Unauthorized("Appointment not owned by specialist".into()))
376+
}

src/routes/specialists.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ pub fn protected_router() -> Router<AppState> {
1717
.route("/{id}", put(specialists::update_specialist))
1818
.route("/specialties", post(specialists::add_specialty))
1919
.route("/license", post(specialists::upload_license))
20+
.route("/patients/{id}", get(specialists::get_patient_profile))
2021
}

0 commit comments

Comments
 (0)