Initial Auth Impl + More Caching (#647)

* Port redis to staging

* redis cache on staging

* add back legacy auth callback

* Begin work on new auth flows

* Finish all auth flows

* Finish base session authentication

* run prep + fix clippy

* make compilation work
This commit is contained in:
Geometrically
2023-07-07 12:20:16 -07:00
committed by GitHub
parent b0057b130e
commit 239214ef92
53 changed files with 6250 additions and 6359 deletions

View File

@@ -1,3 +1,4 @@
use crate::auth::{get_user_from_headers, is_authorized};
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::TeamMember;
use crate::models::ids::ProjectId;
@@ -5,7 +6,6 @@ use crate::models::notifications::NotificationBody;
use crate::models::teams::{Permissions, TeamId};
use crate::models::users::UserId;
use crate::routes::ApiError;
use crate::util::auth::{get_user_from_headers, is_authorized};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
@@ -30,25 +30,27 @@ pub async fn team_members_get_project(
req: HttpRequest,
info: web::Path<(String,)>,
pool: web::Data<PgPool>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let string = info.into_inner().0;
let project_data =
crate::database::models::Project::get_from_slug_or_project_id(&string, &**pool).await?;
let project_data = crate::database::models::Project::get(&string, &**pool, &redis).await?;
if let Some(project) = project_data {
let current_user = get_user_from_headers(req.headers(), &**pool).await.ok();
let current_user = get_user_from_headers(req.headers(), &**pool, &redis)
.await
.ok();
if !is_authorized(&project, &current_user, &pool).await? {
let members_data =
TeamMember::get_from_team_full(project.inner.team_id, &**pool, &redis).await?;
if !is_authorized(&project.inner, &current_user, &pool).await? {
return Ok(HttpResponse::NotFound().body(""));
}
let members_data = TeamMember::get_from_team_full(project.team_id, &**pool).await?;
if let Some(user) = &current_user {
let team_member =
TeamMember::get_from_user_id(project.team_id, user.id.into(), &**pool)
.await
.map_err(ApiError::Database)?;
let team_member = members_data
.iter()
.find(|x| x.user.id == user.id.into() && x.accepted);
if team_member.is_some() {
let team_members: Vec<_> = members_data
@@ -83,16 +85,19 @@ pub async fn team_members_get(
req: HttpRequest,
info: web::Path<(TeamId,)>,
pool: web::Data<PgPool>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let id = info.into_inner().0;
let members_data = TeamMember::get_from_team_full(id.into(), &**pool).await?;
let members_data = TeamMember::get_from_team_full(id.into(), &**pool, &redis).await?;
let current_user = get_user_from_headers(req.headers(), &**pool).await.ok();
let current_user = get_user_from_headers(req.headers(), &**pool, &redis)
.await
.ok();
if let Some(user) = &current_user {
let team_member = TeamMember::get_from_user_id(id.into(), user.id.into(), &**pool)
.await
.map_err(ApiError::Database)?;
let team_member = members_data
.iter()
.find(|x| x.user.id == user.id.into() && x.accepted);
if team_member.is_some() {
let team_members: Vec<_> = members_data
@@ -129,6 +134,7 @@ pub async fn teams_get(
req: HttpRequest,
web::Query(ids): web::Query<TeamIds>,
pool: web::Data<PgPool>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
use itertools::Itertools;
@@ -137,34 +143,39 @@ pub async fn teams_get(
.map(|x| x.into())
.collect::<Vec<crate::database::models::ids::TeamId>>();
let teams_data = TeamMember::get_from_team_full_many(&team_ids, &**pool).await?;
let teams_data = TeamMember::get_from_team_full_many(&team_ids, &**pool, &redis).await?;
let current_user = get_user_from_headers(req.headers(), &**pool).await.ok();
let accepted = if let Some(user) = current_user {
TeamMember::get_from_user_id_many(&team_ids, user.id.into(), &**pool)
.await?
.into_iter()
.map(|m| m.team_id.0)
.collect()
} else {
std::collections::HashSet::new()
};
let current_user = get_user_from_headers(req.headers(), &**pool, &redis)
.await
.ok();
let teams_groups = teams_data.into_iter().group_by(|data| data.team_id.0);
let mut teams: Vec<Vec<crate::models::teams::TeamMember>> = vec![];
for (id, member_data) in &teams_groups {
if accepted.contains(&id) {
let team_members =
member_data.map(|data| crate::models::teams::TeamMember::from(data, false));
for (_, member_data) in &teams_groups {
let members = member_data.collect::<Vec<_>>();
let team_member = if let Some(user) = &current_user {
members
.iter()
.find(|x| x.user.id == user.id.into() && x.accepted)
} else {
None
};
if team_member.is_some() {
let team_members = members
.into_iter()
.map(|data| crate::models::teams::TeamMember::from(data, false));
teams.push(team_members.collect());
continue;
}
let team_members = member_data
let team_members = members
.into_iter()
.filter(|x| x.accepted)
.map(|data| crate::models::teams::TeamMember::from(data, true));
@@ -179,9 +190,10 @@ pub async fn join_team(
req: HttpRequest,
info: web::Path<(TeamId,)>,
pool: web::Data<PgPool>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let team_id = info.into_inner().0.into();
let current_user = get_user_from_headers(req.headers(), &**pool).await?;
let current_user = get_user_from_headers(req.headers(), &**pool, &redis).await?;
let member =
TeamMember::get_from_user_id_pending(team_id, current_user.id.into(), &**pool).await?;
@@ -207,6 +219,8 @@ pub async fn join_team(
)
.await?;
TeamMember::clear_cache(team_id, &redis).await?;
transaction.commit().await?;
} else {
return Err(ApiError::InvalidInput(
@@ -244,12 +258,13 @@ pub async fn add_team_member(
info: web::Path<(TeamId,)>,
pool: web::Data<PgPool>,
new_member: web::Json<NewTeamMember>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let team_id = info.into_inner().0.into();
let mut transaction = pool.begin().await?;
let current_user = get_user_from_headers(req.headers(), &**pool).await?;
let current_user = get_user_from_headers(req.headers(), &**pool, &redis).await?;
let member = TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
@@ -281,12 +296,8 @@ pub async fn add_team_member(
));
}
let request = crate::database::models::team_item::TeamMember::get_from_user_id_pending(
team_id,
new_member.user_id.into(),
&**pool,
)
.await?;
let request =
TeamMember::get_from_user_id_pending(team_id, new_member.user_id.into(), &**pool).await?;
if let Some(req) = request {
if req.accepted {
@@ -300,7 +311,7 @@ pub async fn add_team_member(
}
}
crate::database::models::User::get(member.user_id, &**pool)
crate::database::models::User::get_id(member.user_id, &**pool, &redis)
.await?
.ok_or_else(|| ApiError::InvalidInput("An invalid User ID specified".to_string()))?;
@@ -340,6 +351,8 @@ pub async fn add_team_member(
.insert(new_member.user_id.into(), &mut transaction)
.await?;
TeamMember::clear_cache(team_id, &redis).await?;
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
@@ -359,12 +372,13 @@ pub async fn edit_team_member(
info: web::Path<(TeamId, UserId)>,
pool: web::Data<PgPool>,
edit_member: web::Json<EditTeamMember>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let ids = info.into_inner();
let id = ids.0.into();
let user_id = ids.1.into();
let current_user = get_user_from_headers(req.headers(), &**pool).await?;
let current_user = get_user_from_headers(req.headers(), &**pool, &redis).await?;
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
@@ -430,6 +444,8 @@ pub async fn edit_team_member(
)
.await?;
TeamMember::clear_cache(id, &redis).await?;
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
@@ -446,10 +462,11 @@ pub async fn transfer_ownership(
info: web::Path<(TeamId,)>,
pool: web::Data<PgPool>,
new_owner: web::Json<TransferOwnership>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let id = info.into_inner().0;
let current_user = get_user_from_headers(req.headers(), &**pool).await?;
let current_user = get_user_from_headers(req.headers(), &**pool, &redis).await?;
if !current_user.role.is_admin() {
let member = TeamMember::get_from_user_id(id.into(), current_user.id.into(), &**pool)
@@ -505,6 +522,8 @@ pub async fn transfer_ownership(
)
.await?;
TeamMember::clear_cache(id.into(), &redis).await?;
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
@@ -515,12 +534,13 @@ pub async fn remove_team_member(
req: HttpRequest,
info: web::Path<(TeamId, UserId)>,
pool: web::Data<PgPool>,
redis: web::Data<deadpool_redis::Pool>,
) -> Result<HttpResponse, ApiError> {
let ids = info.into_inner();
let id = ids.0.into();
let user_id = ids.1.into();
let current_user = get_user_from_headers(req.headers(), &**pool).await?;
let current_user = get_user_from_headers(req.headers(), &**pool, &redis).await?;
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
@@ -566,6 +586,8 @@ pub async fn remove_team_member(
));
}
TeamMember::clear_cache(id, &redis).await?;
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
} else {