Staging bug fixes (#819)

* Staging bug fixes

* Finish fixes

* fix tests

* Update migration

* Update migrations

* fix side types being added for ineligible loaders

* fix tests

* Fix tests

* Finish fixes

* Add slug display names
This commit is contained in:
Geometrically
2024-01-04 16:24:33 -05:00
committed by GitHub
parent cf9c8cbb4f
commit f5802fee31
36 changed files with 322 additions and 246 deletions

View File

@@ -72,7 +72,7 @@ pub async fn organization_projects_get(
"
SELECT m.id FROM organizations o
INNER JOIN mods m ON m.organization_id = o.id
WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.name = $2 AND $2 IS NOT NULL)
WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.slug = $2 AND $2 IS NOT NULL)
",
possible_organization_id.map(|x| x as i64),
info
@@ -95,7 +95,9 @@ pub struct NewOrganization {
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
)]
// Title of the organization, also used as slug
pub slug: String,
// Title of the organization
#[validate(length(min = 3, max = 64))]
pub name: String,
#[validate(length(min = 3, max = 256))]
pub description: String,
@@ -126,12 +128,12 @@ pub async fn organization_create(
// Try title
let name_organization_id_option: Option<OrganizationId> =
serde_json::from_str(&format!("\"{}\"", new_organization.name)).ok();
serde_json::from_str(&format!("\"{}\"", new_organization.slug)).ok();
let mut organization_strings = vec![];
if let Some(name_organization_id) = name_organization_id_option {
organization_strings.push(name_organization_id.to_string());
}
organization_strings.push(new_organization.name.clone());
organization_strings.push(new_organization.slug.clone());
let results = Organization::get_many(&organization_strings, &mut *transaction, &redis).await?;
if !results.is_empty() {
return Err(CreateError::SlugCollision);
@@ -157,6 +159,7 @@ pub async fn organization_create(
// Create organization
let organization = Organization {
id: organization_id,
slug: new_organization.slug.clone(),
name: new_organization.name.clone(),
description: new_organization.description.clone(),
team_id,
@@ -336,7 +339,8 @@ pub struct OrganizationEdit {
length(min = 3, max = 64),
regex = "crate::util::validate::RE_URL_SAFE"
)]
// Title of the organization, also used as slug
pub slug: Option<String>,
#[validate(length(min = 3, max = 64))]
pub name: Option<String>,
}
@@ -406,8 +410,28 @@ pub async fn organizations_edit(
.to_string(),
));
}
sqlx::query!(
"
UPDATE organizations
SET name = $1
WHERE (id = $2)
",
name,
id as database::models::ids::OrganizationId,
)
.execute(&mut *transaction)
.await?;
}
let name_organization_id_option: Option<u64> = parse_base62(name).ok();
if let Some(slug) = &new_organization.slug {
if !perms.contains(OrganizationPermissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the slug of this organization!"
.to_string(),
));
}
let name_organization_id_option: Option<u64> = parse_base62(slug).ok();
if let Some(name_organization_id) = name_organization_id_option {
let results = sqlx::query!(
"
@@ -420,26 +444,26 @@ pub async fn organizations_edit(
if results.exists.unwrap_or(true) {
return Err(ApiError::InvalidInput(
"name collides with other organization's id!".to_string(),
"slug collides with other organization's id!".to_string(),
));
}
}
// Make sure the new name is different from the old one
// We are able to unwrap here because the name is always set
if !name.eq(&organization_item.name.clone()) {
if !slug.eq(&organization_item.slug.clone()) {
let results = sqlx::query!(
"
SELECT EXISTS(SELECT 1 FROM organizations WHERE name = LOWER($1))
",
name
SELECT EXISTS(SELECT 1 FROM organizations WHERE LOWER(slug) = LOWER($1))
",
slug
)
.fetch_one(&mut *transaction)
.await?;
if results.exists.unwrap_or(true) {
return Err(ApiError::InvalidInput(
"Name collides with other organization's id!".to_string(),
"slug collides with other organization's id!".to_string(),
));
}
}
@@ -447,10 +471,10 @@ pub async fn organizations_edit(
sqlx::query!(
"
UPDATE organizations
SET name = LOWER($1)
SET slug = $1
WHERE (id = $2)
",
Some(name),
Some(slug),
id as database::models::ids::OrganizationId,
)
.execute(&mut *transaction)
@@ -460,7 +484,7 @@ pub async fn organizations_edit(
transaction.commit().await?;
database::models::Organization::clear_cache(
organization_item.id,
Some(organization_item.name),
Some(organization_item.slug),
&redis,
)
.await?;
@@ -578,7 +602,7 @@ pub async fn organization_delete(
transaction.commit().await?;
database::models::Organization::clear_cache(organization.id, Some(organization.name), &redis)
database::models::Organization::clear_cache(organization.id, Some(organization.slug), &redis)
.await?;
for team_id in organization_project_teams {
@@ -994,7 +1018,7 @@ pub async fn organization_icon_edit(
transaction.commit().await?;
database::models::Organization::clear_cache(
organization_item.id,
Some(organization_item.name),
Some(organization_item.slug),
&redis,
)
.await?;
@@ -1079,7 +1103,7 @@ pub async fn delete_organization_icon(
database::models::Organization::clear_cache(
organization_item.id,
Some(organization_item.name),
Some(organization_item.slug),
&redis,
)
.await?;

View File

@@ -73,7 +73,7 @@ pub enum CreateError {
InvalidCategory(String),
#[error("Invalid file type for version file: {0}")]
InvalidFileType(String),
#[error("Slug collides with other project's id!")]
#[error("Slug is already taken!")]
SlugCollision,
#[error("Authentication Error: {0}")]
Unauthorized(#[from] AuthenticationError),
@@ -612,22 +612,22 @@ async fn project_create_inner(
additional_categories.extend(ids.values());
}
// Should only be owner if not attached to an organization
let is_owner = project_create_data.organization_id.is_none();
let mut members = vec![];
let team = models::team_item::TeamBuilder {
members: vec![models::team_item::TeamMemberBuilder {
if project_create_data.organization_id.is_none() {
members.push(models::team_item::TeamMemberBuilder {
user_id: current_user.id.into(),
role: crate::models::teams::OWNER_ROLE.to_owned(),
is_owner,
// Allow all permissions for project creator, even if attached to a project
is_owner: true,
permissions: ProjectPermissions::all(),
organization_permissions: None,
accepted: true,
payouts_split: Decimal::ONE_HUNDRED,
ordering: 0,
}],
};
})
}
let team = models::team_item::TeamBuilder { members };
let team_id = team.insert(&mut *transaction).await?;

View File

@@ -65,7 +65,7 @@ pub async fn team_members_get_project(
}
let members_data =
TeamMember::get_from_team_full(project.inner.team_id, &**pool, &redis).await?;
let users = crate::database::models::User::get_many_ids(
let users = User::get_many_ids(
&members_data.iter().map(|x| x.user_id).collect::<Vec<_>>(),
&**pool,
&redis,
@@ -73,14 +73,14 @@ pub async fn team_members_get_project(
.await?;
let user_id = current_user.as_ref().map(|x| x.id.into());
let logged_in = if let Some(user_id) = user_id {
let (team_member, organization_team_member) =
TeamMember::get_for_project_permissions(&project.inner, user_id, &**pool).await?;
let logged_in = current_user
.and_then(|user| {
members_data
.iter()
.find(|x| x.user_id == user.id.into() && x.accepted)
})
.is_some();
team_member.is_some() || organization_team_member.is_some()
} else {
false
};
let team_members: Vec<_> = members_data
.into_iter()

View File

@@ -731,7 +731,9 @@ async fn upload_file_to_version_inner(
"At least one file must be specified".to_string(),
));
} else {
VersionFileBuilder::insert_many(file_builders, version_id, &mut *transaction).await?;
for file in file_builders {
file.insert(version_id, &mut *transaction).await?;
}
}
// Clear version cache