Skip to content

Commit

Permalink
add index authz for coaching session resources
Browse files Browse the repository at this point in the history
There is a lot of duplicated code here. The plan is to defer refactoring for now and
take a look at a better error handling system.
  • Loading branch information
calebbourg committed Dec 12, 2024
1 parent e39e506 commit 06c401f
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 0 deletions.
51 changes: 51 additions & 0 deletions web/src/protect/actions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::{extractors::authenticated_user::AuthenticatedUser, AppState};
use axum::{
extract::{Query, Request, State},
http::StatusCode,
middleware::Next,
response::IntoResponse,
};
use entity::Id;
use entity_api::coaching_session;
use log::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub(crate) struct QueryParams {
coaching_session_id: Id,
}

/// Checks that coaching relationship record associated with the coaching session
/// referenced by `coaching_session_id exists and that the authenticated user is associated with it.
/// Intended to be given to axum::middleware::from_fn_with_state in the router
pub(crate) async fn index(
State(app_state): State<AppState>,
AuthenticatedUser(user): AuthenticatedUser,
Query(params): Query<QueryParams>,
request: Request,
next: Next,
) -> impl IntoResponse {
match coaching_session::find_by_id_with_coaching_relationship(
app_state.db_conn_ref(),
params.coaching_session_id,
)
.await
{
Ok((_coaching_session, coaching_relationship)) => {
if coaching_relationship.coach_id == user.id
|| coaching_relationship.coachee_id == user.id
{
// User has access to coaching relationship
next.run(request).await
} else {
// User does not have access to coaching relationship
(StatusCode::UNAUTHORIZED, "UNAUTHORIZED").into_response()
}
}
Err(e) => {
error!("Error authorizing overarching goals index{:?}", e);

(StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR").into_response()
}
}
}
51 changes: 51 additions & 0 deletions web/src/protect/agreements.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::{extractors::authenticated_user::AuthenticatedUser, AppState};
use axum::{
extract::{Query, Request, State},
http::StatusCode,
middleware::Next,
response::IntoResponse,
};
use entity::Id;
use entity_api::coaching_session;
use log::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub(crate) struct QueryParams {
coaching_session_id: Id,
}

/// Checks that coaching relationship record associated with the coaching session
/// referenced by `coaching_session_id exists and that the authenticated user is associated with it.
/// Intended to be given to axum::middleware::from_fn_with_state in the router
pub(crate) async fn index(
State(app_state): State<AppState>,
AuthenticatedUser(user): AuthenticatedUser,
Query(params): Query<QueryParams>,
request: Request,
next: Next,
) -> impl IntoResponse {
match coaching_session::find_by_id_with_coaching_relationship(
app_state.db_conn_ref(),
params.coaching_session_id,
)
.await
{
Ok((_coaching_session, coaching_relationship)) => {
if coaching_relationship.coach_id == user.id
|| coaching_relationship.coachee_id == user.id
{
// User has access to coaching relationship
next.run(request).await
} else {
// User does not have access to coaching relationship
(StatusCode::UNAUTHORIZED, "UNAUTHORIZED").into_response()
}
}
Err(e) => {
error!("Error authorizing overarching goals index{:?}", e);

(StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR").into_response()
}
}
}
3 changes: 3 additions & 0 deletions web/src/protect/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub(crate) mod actions;
pub(crate) mod agreements;
pub(crate) mod coaching_relationships;
pub(crate) mod coaching_sessions;
pub(crate) mod notes;
pub(crate) mod overarching_goals;
51 changes: 51 additions & 0 deletions web/src/protect/notes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::{extractors::authenticated_user::AuthenticatedUser, AppState};
use axum::{
extract::{Query, Request, State},
http::StatusCode,
middleware::Next,
response::IntoResponse,
};
use entity::Id;
use entity_api::coaching_session;
use log::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub(crate) struct QueryParams {
coaching_session_id: Id,
}

/// Checks that coaching relationship record associated with the coaching session
/// referenced by `coaching_session_id exists and that the authenticated user is associated with it.
/// Intended to be given to axum::middleware::from_fn_with_state in the router
pub(crate) async fn index(
State(app_state): State<AppState>,
AuthenticatedUser(user): AuthenticatedUser,
Query(params): Query<QueryParams>,
request: Request,
next: Next,
) -> impl IntoResponse {
match coaching_session::find_by_id_with_coaching_relationship(
app_state.db_conn_ref(),
params.coaching_session_id,
)
.await
{
Ok((_coaching_session, coaching_relationship)) => {
if coaching_relationship.coach_id == user.id
|| coaching_relationship.coachee_id == user.id
{
// User has access to coaching relationship
next.run(request).await
} else {
// User does not have access to coaching relationship
(StatusCode::UNAUTHORIZED, "UNAUTHORIZED").into_response()
}
}
Err(e) => {
error!("Error authorizing overarching goals index{:?}", e);

(StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR").into_response()
}
}
}
9 changes: 9 additions & 0 deletions web/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ fn action_routes(app_state: AppState) -> Router {
.route("/actions", post(action_controller::create))
.route("/actions/:id", put(action_controller::update))
.route("/actions", get(action_controller::index))
.route_layer(from_fn_with_state(
app_state.clone(),
protect::actions::index,
))
.route("/actions/:id", get(action_controller::read))
.route("/actions/:id/status", put(action_controller::update_status))
.route("/actions/:id", delete(action_controller::delete))
Expand All @@ -136,6 +140,10 @@ fn agreement_routes(app_state: AppState) -> Router {
.route("/agreements", post(agreement_controller::create))
.route("/agreements/:id", put(agreement_controller::update))
.route("/agreements", get(agreement_controller::index))
.route_layer(from_fn_with_state(
app_state.clone(),
protect::agreements::index,
))
.route("/agreements/:id", get(agreement_controller::read))
.route("/agreements/:id", delete(agreement_controller::delete))
.route_layer(login_required!(Backend, login_url = "/login"))
Expand Down Expand Up @@ -165,6 +173,7 @@ fn note_routes(app_state: AppState) -> Router {
.route("/notes", post(note_controller::create))
.route("/notes/:id", put(note_controller::update))
.route("/notes", get(note_controller::index))
.route_layer(from_fn_with_state(app_state.clone(), protect::notes::index))
.route("/notes/:id", get(note_controller::read))
.route_layer(login_required!(Backend, login_url = "/login"))
.with_state(app_state)
Expand Down

0 comments on commit 06c401f

Please sign in to comment.