mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 13:16:38 +00:00
feat(labrinth): edit project disclosures endpoint
This commit is contained in:
Generated
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tSELECT 1 FROM project_disclosures\n\t\t\tWHERE project_id = $1 AND type = ANY($2) AND set_by_moderator\n\t\t\tLIMIT 1\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "763762b9995a6d7b00b6cf71c7661a8dff02ed316fc0b98754605a6e16e8e846"
|
||||
}
|
||||
@@ -86,6 +86,26 @@ impl DBProjectDisclosure {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn any_set_by_moderator(
|
||||
project_id: DBProjectId,
|
||||
types: &[String],
|
||||
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<bool, DatabaseError> {
|
||||
let existing = sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT 1 FROM project_disclosures
|
||||
WHERE project_id = $1 AND type = ANY($2) AND set_by_moderator
|
||||
LIMIT 1
|
||||
"#,
|
||||
project_id as DBProjectId,
|
||||
types,
|
||||
)
|
||||
.fetch_optional(exec)
|
||||
.await?;
|
||||
|
||||
Ok(existing.is_some())
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
project_id: DBProjectId,
|
||||
disclosure_type: &str,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use actix_web::{HttpRequest, get, web};
|
||||
use serde::Serialize;
|
||||
use actix_web::{HttpRequest, get, patch, web};
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
use xredis::RedisPool;
|
||||
|
||||
@@ -7,14 +8,16 @@ use crate::auth::checks::is_visible_project;
|
||||
use crate::auth::get_user_from_headers;
|
||||
use crate::database::models as db_models;
|
||||
use crate::database::{PgPool, ReadOnlyPgPool};
|
||||
use crate::models::disclosures::ProjectDisclosureData;
|
||||
use crate::models::disclosures::{ProjectDisclosure, ProjectDisclosureData};
|
||||
use crate::models::pats::Scopes;
|
||||
use crate::models::teams::ProjectPermissions;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::error::Context;
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(get_project_disclosures);
|
||||
cfg.service(get_project_disclosures)
|
||||
.service(modify_project_disclosures);
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
@@ -77,6 +80,123 @@ pub async fn get_project_disclosures(
|
||||
.map(|disclosure| {
|
||||
ProjectDisclosureData::from_db(disclosure, viewer_is_moderator)
|
||||
})
|
||||
.collect()
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ModifyProjectDisclosures {
|
||||
pub set: Vec<ProjectDisclosure>,
|
||||
pub remove: Vec<String>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
context_path = "/project",
|
||||
tag = "project_disclosures",
|
||||
request_body = ModifyProjectDisclosures,
|
||||
responses((status = NO_CONTENT))
|
||||
)]
|
||||
#[patch("/{project_id}/disclosures")]
|
||||
pub async fn modify_project_disclosures(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
body: web::Json<ModifyProjectDisclosures>,
|
||||
) -> Result<(), ApiError> {
|
||||
let (string,) = info.into_inner();
|
||||
let body = body.into_inner();
|
||||
|
||||
let user = get_user_from_headers(
|
||||
&req,
|
||||
&**pool,
|
||||
&redis,
|
||||
&session_queue,
|
||||
Scopes::PROJECT_WRITE,
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
|
||||
let project = db_models::DBProject::get(&string, &**pool, &redis)
|
||||
.await
|
||||
.wrap_internal_err("failed to fetch project")?
|
||||
.ok_or(ApiError::NotFound)?;
|
||||
|
||||
let (team_member, organization_team_member) =
|
||||
db_models::DBTeamMember::get_for_project_permissions(
|
||||
&project.inner,
|
||||
user.id.into(),
|
||||
&**pool,
|
||||
)
|
||||
.await
|
||||
.wrap_internal_err("failed to fetch project permissions")?;
|
||||
|
||||
let can_edit_details = ProjectPermissions::get_permissions_by_role(
|
||||
&user.role,
|
||||
&team_member,
|
||||
&organization_team_member,
|
||||
)
|
||||
.is_some_and(|perms| perms.contains(ProjectPermissions::EDIT_DETAILS));
|
||||
|
||||
if !can_edit_details {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"you do not have permission to edit this project's disclosures"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !user.role.is_mod() {
|
||||
let modified_types = body
|
||||
.set
|
||||
.iter()
|
||||
.map(|disclosure| <&'static str>::from(disclosure).to_owned())
|
||||
.chain(body.remove.iter().cloned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if db_models::DBProjectDisclosure::any_set_by_moderator(
|
||||
project.inner.id,
|
||||
&modified_types,
|
||||
&**pool,
|
||||
)
|
||||
.await
|
||||
.wrap_internal_err("failed to check moderator disclosures")?
|
||||
{
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"you cannot modify a disclosure set by a moderator".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
for disclosure in body.set {
|
||||
db_models::DBProjectDisclosure {
|
||||
project_id: project.inner.id,
|
||||
disclosure,
|
||||
updated_at: Utc::now(),
|
||||
updated_by: user.id.into(),
|
||||
set_by_moderator: user.role.is_mod(),
|
||||
}
|
||||
.upsert(&mut transaction)
|
||||
.await
|
||||
.wrap_internal_err("failed to upsert project disclosure")?;
|
||||
}
|
||||
|
||||
for disclosure_type in &body.remove {
|
||||
db_models::DBProjectDisclosure::remove(
|
||||
project.inner.id,
|
||||
disclosure_type,
|
||||
&mut transaction,
|
||||
)
|
||||
.await
|
||||
.wrap_internal_err("failed to remove project disclosure")?;
|
||||
}
|
||||
|
||||
transaction
|
||||
.commit()
|
||||
.await
|
||||
.wrap_internal_err("failed to commit project disclosure changes")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
projects::project_get_organization,
|
||||
projects::dependency_list,
|
||||
disclosures::get_project_disclosures,
|
||||
disclosures::modify_project_disclosures,
|
||||
project_creation::project_create,
|
||||
project_creation::project_create_with_id,
|
||||
project_creation::new::create,
|
||||
|
||||
Reference in New Issue
Block a user