You've already forked AstralRinth
forked from didirus/AstralRinth
move to monorepo dir
This commit is contained in:
708
apps/labrinth/src/database/models/team_item.rs
Normal file
708
apps/labrinth/src/database/models/team_item.rs
Normal file
@@ -0,0 +1,708 @@
|
||||
use super::{ids::*, Organization, Project};
|
||||
use crate::{
|
||||
database::redis::RedisPool,
|
||||
models::teams::{OrganizationPermissions, ProjectPermissions},
|
||||
};
|
||||
use dashmap::DashMap;
|
||||
use futures::TryStreamExt;
|
||||
use itertools::Itertools;
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const TEAMS_NAMESPACE: &str = "teams";
|
||||
|
||||
pub struct TeamBuilder {
|
||||
pub members: Vec<TeamMemberBuilder>,
|
||||
}
|
||||
pub struct TeamMemberBuilder {
|
||||
pub user_id: UserId,
|
||||
pub role: String,
|
||||
pub is_owner: bool,
|
||||
pub permissions: ProjectPermissions,
|
||||
pub organization_permissions: Option<OrganizationPermissions>,
|
||||
pub accepted: bool,
|
||||
pub payouts_split: Decimal,
|
||||
pub ordering: i64,
|
||||
}
|
||||
|
||||
impl TeamBuilder {
|
||||
pub async fn insert(
|
||||
self,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<TeamId, super::DatabaseError> {
|
||||
let team_id = generate_team_id(transaction).await?;
|
||||
|
||||
let team = Team { id: team_id };
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
INSERT INTO teams (id)
|
||||
VALUES ($1)
|
||||
",
|
||||
team.id as TeamId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
let mut team_member_ids = Vec::new();
|
||||
for _ in self.members.iter() {
|
||||
team_member_ids.push(generate_team_member_id(transaction).await?.0);
|
||||
}
|
||||
let TeamBuilder { members } = self;
|
||||
let (
|
||||
team_ids,
|
||||
user_ids,
|
||||
roles,
|
||||
is_owners,
|
||||
permissions,
|
||||
organization_permissions,
|
||||
accepteds,
|
||||
payouts_splits,
|
||||
orderings,
|
||||
): (
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
) = members
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
(
|
||||
team.id.0,
|
||||
m.user_id.0,
|
||||
m.role,
|
||||
m.is_owner,
|
||||
m.permissions.bits() as i64,
|
||||
m.organization_permissions.map(|p| p.bits() as i64),
|
||||
m.accepted,
|
||||
m.payouts_split,
|
||||
m.ordering,
|
||||
)
|
||||
})
|
||||
.multiunzip();
|
||||
sqlx::query!(
|
||||
"
|
||||
INSERT INTO team_members (id, team_id, user_id, role, is_owner, permissions, organization_permissions, accepted, payouts_split, ordering)
|
||||
SELECT * FROM UNNEST ($1::int8[], $2::int8[], $3::int8[], $4::varchar[], $5::bool[], $6::int8[], $7::int8[], $8::bool[], $9::numeric[], $10::int8[])
|
||||
",
|
||||
&team_member_ids[..],
|
||||
&team_ids[..],
|
||||
&user_ids[..],
|
||||
&roles[..],
|
||||
&is_owners[..],
|
||||
&permissions[..],
|
||||
&organization_permissions[..] as &[Option<i64>],
|
||||
&accepteds[..],
|
||||
&payouts_splits[..],
|
||||
&orderings[..],
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(team_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// A team of users who control a project
|
||||
pub struct Team {
|
||||
/// The id of the team
|
||||
pub id: TeamId,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug, Copy)]
|
||||
pub enum TeamAssociationId {
|
||||
Project(ProjectId),
|
||||
Organization(OrganizationId),
|
||||
}
|
||||
|
||||
impl Team {
|
||||
pub async fn get_association<'a, 'b, E>(
|
||||
id: TeamId,
|
||||
executor: E,
|
||||
) -> Result<Option<TeamAssociationId>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT m.id AS pid, NULL AS oid
|
||||
FROM mods m
|
||||
WHERE m.team_id = $1
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT NULL AS pid, o.id AS oid
|
||||
FROM organizations o
|
||||
WHERE o.team_id = $1
|
||||
",
|
||||
id as TeamId
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(t) = result {
|
||||
// Only one of project_id or organization_id will be set
|
||||
let mut team_association_id = None;
|
||||
if let Some(pid) = t.pid {
|
||||
team_association_id = Some(TeamAssociationId::Project(ProjectId(pid)));
|
||||
}
|
||||
if let Some(oid) = t.oid {
|
||||
team_association_id = Some(TeamAssociationId::Organization(OrganizationId(oid)));
|
||||
}
|
||||
return Ok(team_association_id);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// A member of a team
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct TeamMember {
|
||||
pub id: TeamMemberId,
|
||||
pub team_id: TeamId,
|
||||
|
||||
/// The ID of the user associated with the member
|
||||
pub user_id: UserId,
|
||||
pub role: String,
|
||||
pub is_owner: bool,
|
||||
|
||||
// The permissions of the user in this project team
|
||||
// For an organization team, these are the fallback permissions for any project in the organization
|
||||
pub permissions: ProjectPermissions,
|
||||
|
||||
// The permissions of the user in this organization team
|
||||
// For a project team, this is None
|
||||
pub organization_permissions: Option<OrganizationPermissions>,
|
||||
|
||||
pub accepted: bool,
|
||||
pub payouts_split: Decimal,
|
||||
pub ordering: i64,
|
||||
}
|
||||
|
||||
impl TeamMember {
|
||||
// Lists the full members of a team
|
||||
pub async fn get_from_team_full<'a, 'b, E>(
|
||||
id: TeamId,
|
||||
executor: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<TeamMember>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
Self::get_from_team_full_many(&[id], executor, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_from_team_full_many<'a, E>(
|
||||
team_ids: &[TeamId],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<TeamMember>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
if team_ids.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let val = redis.get_cached_keys(
|
||||
TEAMS_NAMESPACE,
|
||||
&team_ids.iter().map(|x| x.0).collect::<Vec<_>>(),
|
||||
|team_ids| async move {
|
||||
let teams = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
|
||||
accepted, payouts_split,
|
||||
ordering, user_id
|
||||
FROM team_members
|
||||
WHERE team_id = ANY($1)
|
||||
ORDER BY team_id, ordering;
|
||||
",
|
||||
&team_ids
|
||||
)
|
||||
.fetch(exec)
|
||||
.try_fold(DashMap::new(), |acc: DashMap<i64, Vec<TeamMember>>, m| {
|
||||
let member = TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
role: m.member_role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
user_id: UserId(m.user_id),
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
};
|
||||
|
||||
acc.entry(m.team_id)
|
||||
.or_default()
|
||||
.push(member);
|
||||
|
||||
async move { Ok(acc) }
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(teams)
|
||||
},
|
||||
).await?;
|
||||
|
||||
Ok(val.into_iter().flatten().collect())
|
||||
}
|
||||
|
||||
pub async fn clear_cache(id: TeamId, redis: &RedisPool) -> Result<(), super::DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
redis.delete(TEAMS_NAMESPACE, id.0).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets a team member from a user id and team id. Does not return pending members.
|
||||
pub async fn get_from_user_id<'a, 'b, E>(
|
||||
id: TeamId,
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
Self::get_from_user_id_many(&[id], user_id, executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
/// Gets team members from user ids and team ids. Does not return pending members.
|
||||
pub async fn get_from_user_id_many<'a, 'b, E>(
|
||||
team_ids: &[TeamId],
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<Vec<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let team_ids_parsed: Vec<i64> = team_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
|
||||
accepted, payouts_split, role,
|
||||
ordering, user_id
|
||||
FROM team_members
|
||||
WHERE (team_id = ANY($1) AND user_id = $2 AND accepted = TRUE)
|
||||
ORDER BY ordering
|
||||
",
|
||||
&team_ids_parsed,
|
||||
user_id as UserId
|
||||
)
|
||||
.fetch(executor)
|
||||
.map_ok(|m| TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
})
|
||||
.try_collect::<Vec<TeamMember>>()
|
||||
.await?;
|
||||
|
||||
Ok(team_members)
|
||||
}
|
||||
|
||||
/// Gets a team member from a user id and team id, including pending members.
|
||||
pub async fn get_from_user_id_pending<'a, 'b, E>(
|
||||
id: TeamId,
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
|
||||
accepted, payouts_split, role,
|
||||
ordering, user_id
|
||||
|
||||
FROM team_members
|
||||
WHERE (team_id = $1 AND user_id = $2)
|
||||
ORDER BY ordering
|
||||
",
|
||||
id as TeamId,
|
||||
user_id as UserId
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insert(
|
||||
&self,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), sqlx::error::Error> {
|
||||
sqlx::query!(
|
||||
"
|
||||
INSERT INTO team_members (
|
||||
id, team_id, user_id, role, permissions, organization_permissions, is_owner, accepted, payouts_split
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9
|
||||
)
|
||||
",
|
||||
self.id as TeamMemberId,
|
||||
self.team_id as TeamId,
|
||||
self.user_id as UserId,
|
||||
self.role,
|
||||
self.permissions.bits() as i64,
|
||||
self.organization_permissions.map(|p| p.bits() as i64),
|
||||
self.is_owner,
|
||||
self.accepted,
|
||||
self.payouts_split
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete<'a, 'b>(
|
||||
id: TeamId,
|
||||
user_id: UserId,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), super::DatabaseError> {
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM team_members
|
||||
WHERE (team_id = $1 AND user_id = $2 AND NOT is_owner = TRUE)
|
||||
",
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn edit_team_member(
|
||||
id: TeamId,
|
||||
user_id: UserId,
|
||||
new_permissions: Option<ProjectPermissions>,
|
||||
new_organization_permissions: Option<OrganizationPermissions>,
|
||||
new_role: Option<String>,
|
||||
new_accepted: Option<bool>,
|
||||
new_payouts_split: Option<Decimal>,
|
||||
new_ordering: Option<i64>,
|
||||
new_is_owner: Option<bool>,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), super::DatabaseError> {
|
||||
if let Some(permissions) = new_permissions {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET permissions = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
permissions.bits() as i64,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(organization_permissions) = new_organization_permissions {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET organization_permissions = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
organization_permissions.bits() as i64,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(role) = new_role {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET role = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
role,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(accepted) = new_accepted {
|
||||
if accepted {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET accepted = TRUE
|
||||
WHERE (team_id = $1 AND user_id = $2)
|
||||
",
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(payouts_split) = new_payouts_split {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET payouts_split = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
payouts_split,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(ordering) = new_ordering {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET ordering = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
ordering,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(is_owner) = new_is_owner {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE team_members
|
||||
SET is_owner = $1
|
||||
WHERE (team_id = $2 AND user_id = $3)
|
||||
",
|
||||
is_owner,
|
||||
id as TeamId,
|
||||
user_id as UserId,
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_from_user_id_project<'a, 'b, E>(
|
||||
id: ProjectId,
|
||||
user_id: UserId,
|
||||
allow_pending: bool,
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let accepted = if allow_pending {
|
||||
vec![true, false]
|
||||
} else {
|
||||
vec![true]
|
||||
};
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.is_owner, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering
|
||||
FROM mods m
|
||||
INNER JOIN team_members tm ON tm.team_id = m.team_id AND user_id = $2 AND accepted = ANY($3)
|
||||
WHERE m.id = $1
|
||||
",
|
||||
id as ProjectId,
|
||||
user_id as UserId,
|
||||
&accepted
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_from_user_id_organization<'a, 'b, E>(
|
||||
id: OrganizationId,
|
||||
user_id: UserId,
|
||||
allow_pending: bool,
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let accepted = if allow_pending {
|
||||
vec![true, false]
|
||||
} else {
|
||||
vec![true]
|
||||
};
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.is_owner, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering
|
||||
FROM organizations o
|
||||
INNER JOIN team_members tm ON tm.team_id = o.team_id AND user_id = $2 AND accepted = ANY($3)
|
||||
WHERE o.id = $1
|
||||
",
|
||||
id as OrganizationId,
|
||||
user_id as UserId,
|
||||
&accepted
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_from_user_id_version<'a, 'b, E>(
|
||||
id: VersionId,
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.is_owner, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering, v.mod_id
|
||||
FROM versions v
|
||||
INNER JOIN mods m ON m.id = v.mod_id
|
||||
INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.user_id = $2 AND tm.accepted = TRUE
|
||||
WHERE v.id = $1
|
||||
",
|
||||
id as VersionId,
|
||||
user_id as UserId
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: TeamId(m.team_id),
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets both required members for checking permissions of an action on a project
|
||||
// - project team member (a user's membership to a given project)
|
||||
// - organization team member (a user's membership to a given organization that owns a given project)
|
||||
pub async fn get_for_project_permissions<'a, 'b, E>(
|
||||
project: &Project,
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<(Option<Self>, Option<Self>), super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let project_team_member =
|
||||
Self::get_from_user_id(project.team_id, user_id, executor).await?;
|
||||
|
||||
let organization =
|
||||
Organization::get_associated_organization_project_id(project.id, executor).await?;
|
||||
|
||||
let organization_team_member = if let Some(organization) = &organization {
|
||||
Self::get_from_user_id(organization.team_id, user_id, executor).await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((project_team_member, organization_team_member))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user