Organizations (#712)

* untested, unformatted, un-refactored

* minor simplification

* simplification fix

* refactoring, changes

* some fixes

* fixes, refactoring

* missed cache

* revs

* revs - more!

* removed donation links; added all org members to route

* renamed slug to title

---------

Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Wyatt Verchere
2023-10-02 10:56:57 -07:00
committed by GitHub
parent 58a61051b9
commit a1b59d4545
24 changed files with 3658 additions and 979 deletions

View File

@@ -12,7 +12,7 @@ use crate::models::pats::Scopes;
use crate::models::projects::{
DonationLink, MonetizationStatus, Project, ProjectId, ProjectStatus, SearchRequest, SideType,
};
use crate::models::teams::Permissions;
use crate::models::teams::ProjectPermissions;
use crate::models::threads::MessageBody;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
@@ -404,20 +404,25 @@ pub async fn project_edit(
if let Some(project_item) = result {
let id = project_item.inner.id;
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
let permissions = Permissions::get_permissions_by_role(&user.role, &team_member);
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
);
if let Some(perms) = permissions {
let mut transaction = pool.begin().await?;
if let Some(title) = &new_project.title {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the title of this project!"
.to_string(),
@@ -438,7 +443,7 @@ pub async fn project_edit(
}
if let Some(description) = &new_project.description {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the description of this project!"
.to_string(),
@@ -459,7 +464,7 @@ pub async fn project_edit(
}
if let Some(status) = &new_project.status {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the status of this project!"
.to_string(),
@@ -624,7 +629,7 @@ pub async fn project_edit(
}
if let Some(requested_status) = &new_project.requested_status {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the requested status of this project!"
.to_string(),
@@ -653,7 +658,7 @@ pub async fn project_edit(
.await?;
}
if perms.contains(Permissions::EDIT_DETAILS) {
if perms.contains(ProjectPermissions::EDIT_DETAILS) {
if new_project.categories.is_some() {
sqlx::query!(
"
@@ -680,7 +685,7 @@ pub async fn project_edit(
}
if let Some(categories) = &new_project.categories {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the categories of this project!"
.to_string(),
@@ -712,7 +717,7 @@ pub async fn project_edit(
}
if let Some(categories) = &new_project.additional_categories {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the additional categories of this project!"
.to_string(),
@@ -744,7 +749,7 @@ pub async fn project_edit(
}
if let Some(issues_url) = &new_project.issues_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the issues URL of this project!"
.to_string(),
@@ -765,7 +770,7 @@ pub async fn project_edit(
}
if let Some(source_url) = &new_project.source_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the source URL of this project!"
.to_string(),
@@ -786,7 +791,7 @@ pub async fn project_edit(
}
if let Some(wiki_url) = &new_project.wiki_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the wiki URL of this project!"
.to_string(),
@@ -807,7 +812,7 @@ pub async fn project_edit(
}
if let Some(license_url) = &new_project.license_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the license URL of this project!"
.to_string(),
@@ -828,7 +833,7 @@ pub async fn project_edit(
}
if let Some(discord_url) = &new_project.discord_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the discord URL of this project!"
.to_string(),
@@ -849,7 +854,7 @@ pub async fn project_edit(
}
if let Some(slug) = &new_project.slug {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the slug of this project!"
.to_string(),
@@ -907,7 +912,7 @@ pub async fn project_edit(
}
if let Some(new_side) = &new_project.client_side {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the side type of this mod!"
.to_string(),
@@ -935,7 +940,7 @@ pub async fn project_edit(
}
if let Some(new_side) = &new_project.server_side {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the side type of this project!"
.to_string(),
@@ -963,7 +968,7 @@ pub async fn project_edit(
}
if let Some(license) = &new_project.license_id {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the license of this project!"
.to_string(),
@@ -994,7 +999,7 @@ pub async fn project_edit(
}
if let Some(donations) = &new_project.donation_urls {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the donation links of this project!"
.to_string(),
@@ -1086,7 +1091,7 @@ pub async fn project_edit(
}
if let Some(body) = &new_project.body {
if !perms.contains(Permissions::EDIT_BODY) {
if !perms.contains(ProjectPermissions::EDIT_BODY) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the body of this project!"
.to_string(),
@@ -1107,7 +1112,7 @@ pub async fn project_edit(
}
if let Some(monetization_status) = &new_project.monetization_status {
if !perms.contains(Permissions::EDIT_DETAILS) {
if !perms.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the monetization status of this project!"
.to_string(),
@@ -1282,6 +1287,24 @@ pub async fn projects_edit(
let team_members =
database::models::TeamMember::get_from_team_full_many(&team_ids, &**pool, &redis).await?;
let organization_ids = projects_data
.iter()
.filter_map(|x| x.inner.organization_id)
.collect::<Vec<database::models::OrganizationId>>();
let organizations =
database::models::Organization::get_many_ids(&organization_ids, &**pool, &redis).await?;
let organization_team_ids = organizations
.iter()
.map(|x| x.team_id)
.collect::<Vec<database::models::TeamId>>();
let organization_team_members = database::models::TeamMember::get_from_team_full_many(
&organization_team_ids,
&**pool,
&redis,
)
.await?;
let categories = database::models::categories::Category::list(&**pool, &redis).await?;
let donation_platforms =
database::models::categories::DonationPlatform::list(&**pool, &redis).await?;
@@ -1290,11 +1313,32 @@ pub async fn projects_edit(
for project in projects_data {
if !user.role.is_mod() {
if let Some(member) = team_members
let team_member = team_members
.iter()
.find(|x| x.team_id == project.inner.team_id && x.user_id == user.id.into())
{
if !member.permissions.contains(Permissions::EDIT_DETAILS) {
.find(|x| x.team_id == project.inner.team_id && x.user_id == user.id.into());
let organization = project
.inner
.organization_id
.and_then(|oid| organizations.iter().find(|x| x.id == oid));
let organization_team_member = if let Some(organization) = organization {
organization_team_members
.iter()
.find(|x| x.team_id == organization.team_id && x.user_id == user.id.into())
} else {
None
};
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member.cloned(),
&organization_team_member.cloned(),
)
.unwrap_or_default();
if team_member.is_some() {
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(format!(
"You do not have the permissions to bulk edit project {}!",
project.inner.title
@@ -1608,18 +1652,22 @@ pub async fn project_schedule(
let result = database::models::Project::get(&string, &**pool, &redis).await?;
if let Some(project_item) = result {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !user.role.is_mod()
&& !team_member
.map(|x| x.permissions.contains(Permissions::EDIT_DETAILS))
.unwrap_or(false)
{
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member.clone(),
&organization_team_member.clone(),
)
.unwrap_or_default();
if !user.role.is_mod() && !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have permission to edit this project's scheduling data!".to_string(),
));
@@ -1701,18 +1749,29 @@ pub async fn project_icon_edit(
})?;
if !user.role.is_mod() {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's icon.".to_string(),
));
@@ -1803,18 +1862,28 @@ pub async fn delete_project_icon(
})?;
if !user.role.is_mod() {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's icon.".to_string(),
));
@@ -1908,18 +1977,29 @@ pub async fn add_gallery_item(
}
if !user.role.is_admin() {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery.".to_string(),
));
@@ -2050,18 +2130,28 @@ pub async fn edit_gallery_item(
})?;
if !user.role.is_mod() {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery.".to_string(),
));
@@ -2201,18 +2291,29 @@ pub async fn delete_gallery_item(
})?;
if !user.role.is_mod() {
let team_member = database::models::TeamMember::get_from_user_id(
project_item.inner.team_id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project_item.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery.".to_string(),
));
@@ -2296,21 +2397,29 @@ pub async fn project_delete(
})?;
if !user.role.is_admin() {
let team_member = database::models::TeamMember::get_from_user_id_project(
project.inner.id,
user.id.into(),
&**pool,
)
.await
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInput("The specified project does not exist!".to_string())
})?;
let (team_member, organization_team_member) =
database::models::TeamMember::get_for_project_permissions(
&project.inner,
user.id.into(),
&**pool,
)
.await?;
if !team_member
.permissions
.contains(Permissions::DELETE_PROJECT)
{
// Hide the project
if team_member.is_none() && organization_team_member.is_none() {
return Err(ApiError::CustomAuthentication(
"The specified project does not exist!".to_string(),
));
}
let permissions = ProjectPermissions::get_permissions_by_role(
&user.role,
&team_member,
&organization_team_member,
)
.unwrap_or_default();
if !permissions.contains(ProjectPermissions::DELETE_PROJECT) {
return Err(ApiError::CustomAuthentication(
"You don't have permission to delete this project!".to_string(),
));