use anyhow::Result; use deadpool_diesel::postgres::Connection; use diesel::prelude::*; use uuid::Uuid; use crate::{ app_error::AppError, csrf::validate_csrf_token, team_memberships::TeamMembership, teams::Team, users::User, }; /// Returns a ForbiddenError if user is not a member of the indicated team. /// Intended to be used in HTTP handlers to check authorization. The team /// struct is often useful in such cases, so it is returned if the /// authorization check is successful. pub async fn require_team_membership( current_user: &User, team_id: &Uuid, db_conn: &Connection, ) -> Result { let maybe_team = { let current_user_id = current_user.id; let team_id = *team_id; db_conn .interact::<_, Result>>(move |conn| { TeamMembership::all() .filter(TeamMembership::with_user_id(¤t_user_id)) .filter(TeamMembership::with_team_id(&team_id)) .first(conn) .optional() .map_err(Into::into) }) .await .unwrap()? }; match maybe_team { Some((team, _)) => Ok(team), None => Err(AppError::ForbiddenError( "not a member of requested team".to_string(), )), } } /// Returns a ForbiddenError if the CSRF token parameters do not match an entry /// in the database. Do not expect this function to invalidate tokens after use. pub async fn require_valid_csrf_token( csrf_token: &str, current_user: &User, db_conn: &Connection, ) -> Result<(), AppError> { if validate_csrf_token(db_conn, csrf_token, Some(current_user.id)).await? { Ok(()) } else { Err(AppError::ForbiddenError("invalid CSRF token".to_string())) } }