use crate::{
crates::Crate, permissions::UserPermission, users::User, BitwiseExpressionMethods, Error,
};
use super::{
schema::{organisations, user_organisation_permissions, users},
uuid::SqlUuid,
ConnectionPool, Result,
};
use diesel::{prelude::*, Associations, Identifiable, Queryable};
use std::sync::Arc;
#[derive(Identifiable, Queryable, Associations, PartialEq, Eq, Hash, Debug)]
pub struct Organisation {
pub id: i32,
pub uuid: SqlUuid,
pub name: String,
pub description: String,
}
impl Organisation {
pub async fn list(conn: ConnectionPool, requesting_user_id: i32) -> Result<Vec<Organisation>> {
use user_organisation_permissions::dsl::permissions;
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
organisations::table
.inner_join(
user_organisation_permissions::table.on(user_organisation_permissions::user_id
.eq(requesting_user_id)
.and(
user_organisation_permissions::organisation_id
.eq(organisations::dsl::id),
)),
)
.filter(
permissions
.bitwise_and(UserPermission::VISIBLE.bits())
.eq(UserPermission::VISIBLE.bits()),
)
.select(organisations::all_columns)
.load(&conn)
.map_err(Into::into)
})
.await?
}
pub async fn find_by_name(
conn: ConnectionPool,
requesting_user_id: i32,
given_name: String,
) -> Result<OrganisationWithPermissions> {
use organisations::dsl::name as organisation_name;
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
let (permissions, organisation) = organisations::table
.left_join(
user_organisation_permissions::table.on(user_organisation_permissions::user_id
.eq(requesting_user_id)
.and(
user_organisation_permissions::organisation_id
.eq(organisations::dsl::id),
)),
)
.filter(organisation_name.eq(given_name))
.select((
user_organisation_permissions::dsl::permissions.nullable(),
organisations::all_columns,
))
.get_result::<(Option<UserPermission>, _)>(&conn)
.optional()?
.ok_or(Error::MissingOrganisation)?;
let permissions = permissions.ok_or(Error::MissingOrganisationPermission(
UserPermission::VISIBLE,
))?;
Ok(OrganisationWithPermissions {
organisation,
permissions,
})
})
.await?
}
}
pub struct OrganisationWithPermissions {
organisation: Organisation,
permissions: UserPermission,
}
impl OrganisationWithPermissions {
#[must_use]
pub fn permissions(&self) -> UserPermission {
self.permissions
}
#[must_use]
pub fn organisation(&self) -> &Organisation {
&self.organisation
}
pub async fn crates(self: Arc<Self>, conn: ConnectionPool) -> Result<Vec<Crate>> {
if !self.permissions.contains(UserPermission::VISIBLE) {
return Err(Error::MissingOrganisationPermission(
UserPermission::VISIBLE,
));
}
tokio::task::spawn_blocking(move || {
let conn = conn.get()?;
Crate::belonging_to(&self.organisation)
.load(&conn)
.map_err(Into::into)
})
.await?
}
pub async fn members(
self: Arc<Self>,
conn: ConnectionPool,
) -> Result<Vec<(User, UserPermission)>> {
if !self.permissions.contains(UserPermission::VISIBLE) {
return Err(Error::MissingOrganisationPermission(
UserPermission::VISIBLE,
));
}
tokio::task::spawn_blocking(move || {
use crate::schema::user_organisation_permissions::dsl::organisation_id;
let conn = conn.get()?;
user_organisation_permissions::table
.filter(organisation_id.eq(self.organisation.id))
.inner_join(users::table)
.select((
users::all_columns,
user_organisation_permissions::columns::permissions,
))
.load(&conn)
.map_err(Into::into)
})
.await?
}
pub async fn update_permissions(
self: Arc<Self>,
conn: ConnectionPool,
given_user_id: i32,
given_permissions: UserPermission,
) -> Result<usize> {
if !self.permissions.contains(UserPermission::MANAGE_USERS) {
return Err(Error::MissingCratePermission(UserPermission::MANAGE_USERS));
}
tokio::task::spawn_blocking(move || {
use crate::schema::user_organisation_permissions::dsl::{
organisation_id, permissions, user_id, user_organisation_permissions,
};
let conn = conn.get()?;
Ok(diesel::update(
user_organisation_permissions
.filter(user_id.eq(given_user_id))
.filter(organisation_id.eq(self.organisation.id)),
)
.set(permissions.eq(given_permissions.bits()))
.execute(&conn)?)
})
.await?
}
pub async fn insert_permissions(
self: Arc<Self>,
conn: ConnectionPool,
given_user_id: i32,
given_permissions: UserPermission,
) -> Result<usize> {
if !self.permissions.contains(UserPermission::MANAGE_USERS) {
return Err(Error::MissingCratePermission(UserPermission::MANAGE_USERS));
}
tokio::task::spawn_blocking(move || {
use crate::schema::user_organisation_permissions::dsl::{
organisation_id, permissions, user_id, user_organisation_permissions,
};
let conn = conn.get()?;
Ok(diesel::insert_into(user_organisation_permissions)
.values((
user_id.eq(given_user_id),
organisation_id.eq(self.organisation.id),
permissions.eq(given_permissions.bits()),
))
.execute(&conn)?)
})
.await?
}
pub async fn delete_member(
self: Arc<Self>,
conn: ConnectionPool,
given_user_id: i32,
) -> Result<()> {
if !self.permissions.contains(UserPermission::MANAGE_USERS) {
return Err(Error::MissingCratePermission(UserPermission::MANAGE_USERS));
}
tokio::task::spawn_blocking(move || {
use crate::schema::user_organisation_permissions::dsl::{
organisation_id, user_id, user_organisation_permissions,
};
let conn = conn.get()?;
diesel::delete(
user_organisation_permissions
.filter(user_id.eq(given_user_id))
.filter(organisation_id.eq(self.organisation.id)),
)
.execute(&conn)?;
Ok(())
})
.await?
}
}