Misc v3 linear tasks (#767)

* v3_reroute 404 error

* hash change

* fixed issue with error conversion

* added new model confirmation tests
+ title name change

* renaming, fields

* owner; test changes

* clippy prepare

* fmt

* merge fixes

* clippy

* working merge

* revs

* merge fixes
This commit is contained in:
Wyatt Verchere
2023-12-01 19:15:00 -08:00
committed by GitHub
parent 2d92b08404
commit a70df067bc
119 changed files with 2897 additions and 1334 deletions

View File

@@ -12,7 +12,7 @@ const COLLECTIONS_NAMESPACE: &str = "collections";
pub struct CollectionBuilder {
pub collection_id: CollectionId,
pub user_id: UserId,
pub title: String,
pub name: String,
pub description: String,
pub status: CollectionStatus,
pub projects: Vec<ProjectId>,
@@ -25,7 +25,7 @@ impl CollectionBuilder {
) -> Result<CollectionId, DatabaseError> {
let collection_struct = Collection {
id: self.collection_id,
title: self.title,
name: self.name,
user_id: self.user_id,
description: self.description,
created: Utc::now(),
@@ -44,7 +44,7 @@ impl CollectionBuilder {
pub struct Collection {
pub id: CollectionId,
pub user_id: UserId,
pub title: String,
pub name: String,
pub description: String,
pub created: DateTime<Utc>,
pub updated: DateTime<Utc>,
@@ -62,7 +62,7 @@ impl Collection {
sqlx::query!(
"
INSERT INTO collections (
id, user_id, title, description,
id, user_id, name, description,
created, icon_url, status
)
VALUES (
@@ -72,7 +72,7 @@ impl Collection {
",
self.id as CollectionId,
self.user_id as UserId,
&self.title,
&self.name,
&self.description,
self.created,
self.icon_url.as_ref(),
@@ -190,7 +190,7 @@ impl Collection {
remaining_collections.iter().map(|x| x.0).collect();
let db_collections: Vec<Collection> = sqlx::query!(
"
SELECT c.id id, c.title title, c.description description,
SELECT c.id id, c.name name, c.description description,
c.icon_url icon_url, c.color color, c.created created, c.user_id user_id,
c.updated updated, c.status status,
ARRAY_AGG(DISTINCT cm.mod_id) filter (where cm.mod_id is not null) mods
@@ -209,7 +209,7 @@ impl Collection {
Collection {
id: CollectionId(id),
user_id: UserId(m.user_id),
title: m.title.clone(),
name: m.name.clone(),
description: m.description.clone(),
icon_url: m.icon_url.clone(),
color: m.color.map(|x| x as u32),

View File

@@ -25,7 +25,7 @@ pub struct Notification {
pub struct NotificationAction {
pub id: NotificationActionId,
pub notification_id: NotificationId,
pub title: String,
pub name: String,
pub action_route_method: String,
pub action_route: String,
}
@@ -122,8 +122,8 @@ impl Notification {
let notification_ids_parsed: Vec<i64> = notification_ids.iter().map(|x| x.0).collect();
sqlx::query!(
"
SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, n.body,
JSONB_AGG(DISTINCT jsonb_build_object('id', na.id, 'notification_id', na.notification_id, 'title', na.title, 'action_route_method', na.action_route_method, 'action_route', na.action_route)) filter (where na.id is not null) actions
SELECT n.id, n.user_id, n.name, n.text, n.link, n.created, n.read, n.type notification_type, n.body,
JSONB_AGG(DISTINCT jsonb_build_object('id', na.id, 'notification_id', na.notification_id, 'name', na.name, 'action_route_method', na.action_route_method, 'action_route', na.action_route)) filter (where na.id is not null) actions
FROM notifications n
LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id
WHERE n.id = ANY($1)
@@ -143,10 +143,10 @@ impl Notification {
read: row.read,
created: row.created,
body: row.body.clone().and_then(|x| serde_json::from_value(x).ok()).unwrap_or_else(|| {
if let Some(title) = row.title {
if let Some(name) = row.name {
NotificationBody::LegacyMarkdown {
notification_type: row.notification_type,
title,
name,
text: row.text.unwrap_or_default(),
link: row.link.unwrap_or_default(),
actions: serde_json::from_value(
@@ -186,8 +186,8 @@ impl Notification {
let db_notifications = sqlx::query!(
"
SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, n.body,
JSONB_AGG(DISTINCT jsonb_build_object('id', na.id, 'notification_id', na.notification_id, 'title', na.title, 'action_route_method', na.action_route_method, 'action_route', na.action_route)) filter (where na.id is not null) actions
SELECT n.id, n.user_id, n.name, n.text, n.link, n.created, n.read, n.type notification_type, n.body,
JSONB_AGG(DISTINCT jsonb_build_object('id', na.id, 'notification_id', na.notification_id, 'name', na.name, 'action_route_method', na.action_route_method, 'action_route', na.action_route)) filter (where na.id is not null) actions
FROM notifications n
LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id
WHERE n.user_id = $1
@@ -206,10 +206,10 @@ impl Notification {
read: row.read,
created: row.created,
body: row.body.clone().and_then(|x| serde_json::from_value(x).ok()).unwrap_or_else(|| {
if let Some(title) = row.title {
if let Some(name) = row.name {
NotificationBody::LegacyMarkdown {
notification_type: row.notification_type,
title,
name,
text: row.text.unwrap_or_default(),
link: row.link.unwrap_or_default(),
actions: serde_json::from_value(

View File

@@ -16,7 +16,7 @@ pub struct Organization {
pub id: OrganizationId,
/// The title (and slug) of the organization
pub title: String,
pub name: String,
/// The associated team of the organization
pub team_id: TeamId,
@@ -36,11 +36,11 @@ impl Organization {
) -> Result<(), super::DatabaseError> {
sqlx::query!(
"
INSERT INTO organizations (id, title, team_id, description, icon_url, color)
INSERT INTO organizations (id, name, team_id, description, icon_url, color)
VALUES ($1, $2, $3, $4, $5, $6)
",
self.id.0,
self.title,
self.name,
self.team_id as TeamId,
self.description,
self.icon_url,
@@ -149,7 +149,7 @@ impl Organization {
{
remaining_strings.retain(|x| {
&to_base62(organization.id.0 as u64) != x
&& organization.title.to_lowercase() != x.to_lowercase()
&& organization.name.to_lowercase() != x.to_lowercase()
});
found_organizations.push(organization);
continue;
@@ -166,9 +166,9 @@ impl Organization {
let organizations: Vec<Organization> = sqlx::query!(
"
SELECT o.id, o.title, o.team_id, o.description, o.icon_url, o.color
SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color
FROM organizations o
WHERE o.id = ANY($1) OR LOWER(o.title) = ANY($2)
WHERE o.id = ANY($1) OR LOWER(o.name) = ANY($2)
GROUP BY o.id;
",
&organization_ids_parsed,
@@ -181,7 +181,7 @@ impl Organization {
.try_filter_map(|e| async {
Ok(e.right().map(|m| Organization {
id: OrganizationId(m.id),
title: m.title,
name: m.name,
team_id: TeamId(m.team_id),
description: m.description,
icon_url: m.icon_url,
@@ -203,7 +203,7 @@ impl Organization {
redis
.set(
ORGANIZATIONS_TITLES_NAMESPACE,
&organization.title.to_lowercase(),
&organization.name.to_lowercase(),
&organization.id.0.to_string(),
None,
)
@@ -226,7 +226,7 @@ impl Organization {
{
let result = sqlx::query!(
"
SELECT o.id, o.title, o.team_id, o.description, o.icon_url, o.color
SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color
FROM organizations o
LEFT JOIN mods m ON m.organization_id = o.id
WHERE m.id = $1
@@ -240,7 +240,7 @@ impl Organization {
if let Some(result) = result {
Ok(Some(Organization {
id: OrganizationId(result.id),
title: result.title,
name: result.name,
team_id: TeamId(result.team_id),
description: result.description,
icon_url: result.icon_url,
@@ -279,7 +279,7 @@ impl Organization {
super::project_item::Project::remove(project_id, transaction, redis).await?;
}
Organization::clear_cache(id, Some(organization.title), redis).await?;
Organization::clear_cache(id, Some(organization.name), redis).await?;
sqlx::query!(
"

View File

@@ -54,7 +54,7 @@ impl LinkUrl {
pub struct GalleryItem {
pub image_url: String,
pub featured: bool,
pub title: Option<String>,
pub name: Option<String>,
pub description: Option<String>,
pub created: DateTime<Utc>,
pub ordering: i64,
@@ -66,7 +66,7 @@ impl GalleryItem {
project_id: ProjectId,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<(), sqlx::error::Error> {
let (project_ids, image_urls, featureds, titles, descriptions, orderings): (
let (project_ids, image_urls, featureds, names, descriptions, orderings): (
Vec<_>,
Vec<_>,
Vec<_>,
@@ -80,7 +80,7 @@ impl GalleryItem {
project_id.0,
gi.image_url,
gi.featured,
gi.title,
gi.name,
gi.description,
gi.ordering,
)
@@ -89,14 +89,14 @@ impl GalleryItem {
sqlx::query!(
"
INSERT INTO mods_gallery (
mod_id, image_url, featured, title, description, ordering
mod_id, image_url, featured, name, description, ordering
)
SELECT * FROM UNNEST ($1::bigint[], $2::varchar[], $3::bool[], $4::varchar[], $5::varchar[], $6::bigint[])
",
&project_ids[..],
&image_urls[..],
&featureds[..],
&titles[..] as &[Option<String>],
&names[..] as &[Option<String>],
&descriptions[..] as &[Option<String>],
&orderings[..]
)
@@ -144,9 +144,9 @@ pub struct ProjectBuilder {
pub project_id: ProjectId,
pub team_id: TeamId,
pub organization_id: Option<OrganizationId>,
pub title: String,
pub name: String,
pub summary: String,
pub description: String,
pub body: String,
pub icon_url: Option<String>,
pub license_url: Option<String>,
pub categories: Vec<CategoryId>,
@@ -171,10 +171,9 @@ impl ProjectBuilder {
id: self.project_id,
team_id: self.team_id,
organization_id: self.organization_id,
title: self.title,
name: self.name,
summary: self.summary,
description: self.description,
body: self.body,
body_url: None,
published: Utc::now(),
updated: Utc::now(),
approved: None,
@@ -237,10 +236,9 @@ pub struct Project {
pub id: ProjectId,
pub team_id: TeamId,
pub organization_id: Option<OrganizationId>,
pub title: String,
pub name: String,
pub summary: String,
pub description: String,
pub body: String,
pub body_url: Option<String>,
pub published: DateTime<Utc>,
pub updated: DateTime<Utc>,
pub approved: Option<DateTime<Utc>>,
@@ -269,7 +267,7 @@ impl Project {
sqlx::query!(
"
INSERT INTO mods (
id, team_id, title, description, body,
id, team_id, name, summary, description,
published, downloads, icon_url, status, requested_status,
license_url, license,
slug, color, monetization_status
@@ -283,9 +281,9 @@ impl Project {
",
self.id as ProjectId,
self.team_id as TeamId,
&self.title,
&self.name,
&self.summary,
&self.description,
&self.body,
self.published,
self.downloads,
self.icon_url.as_ref(),
@@ -623,7 +621,7 @@ impl Project {
SELECT DISTINCT mod_id,
JSONB_AGG(
DISTINCT jsonb_build_object(
'image_url', mg.image_url, 'featured', mg.featured, 'title', mg.title, 'description', mg.description, 'created', mg.created, 'ordering', mg.ordering
'image_url', mg.image_url, 'featured', mg.featured, 'name', mg.name, 'description', mg.description, 'created', mg.created, 'ordering', mg.ordering
)
) filter (where image_url is not null) mods_gallery_json
FROM mods_gallery mg
@@ -644,8 +642,8 @@ impl Project {
GROUP BY mod_id
)
SELECT m.id id, m.title title, m.description description, m.downloads downloads, m.follows follows,
m.icon_url icon_url, m.body body, m.published published,
SELECT m.id id, m.name name, m.summary summary, m.downloads downloads, m.follows follows,
m.icon_url icon_url, m.description description, m.published published,
m.updated updated, m.approved approved, m.queued, m.status status, m.requested_status requested_status,
m.license_url license_url,
m.team_id team_id, m.organization_id organization_id, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,
@@ -693,10 +691,9 @@ impl Project {
id: ProjectId(id),
team_id: TeamId(m.team_id),
organization_id: m.organization_id.map(OrganizationId),
title: m.title.clone(),
description: m.description.clone(),
name: m.name.clone(),
summary: m.summary.clone(),
downloads: m.downloads,
body_url: None,
icon_url: m.icon_url.clone(),
published: m.published,
updated: m.updated,
@@ -709,7 +706,7 @@ impl Project {
)),
license: m.license.clone(),
slug: m.slug.clone(),
body: m.body.clone(),
description: m.description.clone(),
follows: m.follows,
moderation_message: m.moderation_message,
moderation_message_body: m.moderation_message_body,

View File

@@ -15,6 +15,7 @@ pub struct TeamBuilder {
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,
@@ -50,6 +51,7 @@ impl TeamBuilder {
team_ids,
user_ids,
roles,
is_owners,
permissions,
organization_permissions,
accepteds,
@@ -64,6 +66,7 @@ impl TeamBuilder {
Vec<_>,
Vec<_>,
Vec<_>,
Vec<_>,
) = members
.into_iter()
.map(|m| {
@@ -71,6 +74,7 @@ impl TeamBuilder {
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,
@@ -81,13 +85,14 @@ impl TeamBuilder {
.multiunzip();
sqlx::query!(
"
INSERT INTO team_members (id, team_id, user_id, role, permissions, organization_permissions, accepted, payouts_split, ordering)
SELECT * FROM UNNEST ($1::int8[], $2::int8[], $3::int8[], $4::varchar[], $5::int8[], $6::int8[], $7::bool[], $8::numeric[], $9::int8[])
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[..],
@@ -162,6 +167,7 @@ pub struct TeamMember {
/// 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
@@ -233,7 +239,7 @@ impl TeamMember {
if !team_ids_parsed.is_empty() {
let teams: Vec<TeamMember> = sqlx::query!(
"
SELECT id, team_id, role AS member_role, permissions, organization_permissions,
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
accepted, payouts_split,
ordering, user_id
FROM team_members
@@ -248,6 +254,7 @@ impl 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
@@ -310,7 +317,7 @@ impl TeamMember {
let team_members = sqlx::query!(
"
SELECT id, team_id, role AS member_role, permissions, organization_permissions,
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
accepted, payouts_split, role,
ordering, user_id
FROM team_members
@@ -328,6 +335,7 @@ impl TeamMember {
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
@@ -362,7 +370,7 @@ impl TeamMember {
{
let result = sqlx::query!(
"
SELECT id, team_id, role AS member_role, permissions, organization_permissions,
SELECT id, team_id, role AS member_role, is_owner, permissions, organization_permissions,
accepted, payouts_split, role,
ordering, user_id
@@ -382,6 +390,7 @@ impl TeamMember {
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
@@ -431,11 +440,10 @@ impl TeamMember {
sqlx::query!(
"
DELETE FROM team_members
WHERE (team_id = $1 AND user_id = $2 AND NOT role = $3)
WHERE (team_id = $1 AND user_id = $2 AND NOT is_owner = TRUE)
",
id as TeamId,
user_id as UserId,
crate::models::teams::OWNER_ROLE,
)
.execute(&mut **transaction)
.await?;
@@ -453,6 +461,7 @@ impl TeamMember {
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 {
@@ -546,6 +555,21 @@ impl TeamMember {
.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(())
}
@@ -559,7 +583,7 @@ impl TeamMember {
{
let result = sqlx::query!(
"
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering
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 = TRUE
WHERE m.id = $1
@@ -576,6 +600,7 @@ impl TeamMember {
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
@@ -600,7 +625,7 @@ impl TeamMember {
{
let result = sqlx::query!(
"
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering
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 = TRUE
WHERE o.id = $1
@@ -617,6 +642,7 @@ impl TeamMember {
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
@@ -641,7 +667,7 @@ impl TeamMember {
{
let result = sqlx::query!(
"
SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.organization_permissions, tm.accepted, tm.payouts_split, tm.ordering, v.mod_id
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
@@ -659,6 +685,7 @@ impl TeamMember {
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

View File

@@ -450,10 +450,9 @@ impl User {
"
SELECT m.id FROM mods m
INNER JOIN team_members tm ON tm.team_id = m.team_id
WHERE tm.user_id = $1 AND tm.role = $2
WHERE tm.user_id = $1 AND tm.is_owner = TRUE
",
id as UserId,
crate::models::teams::OWNER_ROLE
)
.fetch_many(&mut **transaction)
.try_filter_map(|e| async { Ok(e.right().map(|m| ProjectId(m.id))) })
@@ -470,11 +469,10 @@ impl User {
"
UPDATE team_members
SET user_id = $1
WHERE (user_id = $2 AND role = $3)
WHERE (user_id = $2 AND is_owner = TRUE)
",
deleted_user as UserId,
id as UserId,
crate::models::teams::OWNER_ROLE
)
.execute(&mut **transaction)
.await?;

View File

@@ -209,7 +209,6 @@ impl VersionBuilder {
name: self.name,
version_number: self.version_number,
changelog: self.changelog,
changelog_url: None,
date_published: Utc::now(),
downloads: 0,
featured: self.featured,
@@ -293,7 +292,6 @@ pub struct Version {
pub name: String,
pub version_number: String,
pub changelog: String,
pub changelog_url: Option<String>,
pub date_published: DateTime<Utc>,
pub downloads: i32,
pub version_type: String,
@@ -644,7 +642,6 @@ impl Version {
name: v.version_name,
version_number: v.version_number,
changelog: v.changelog,
changelog_url: None,
date_published: v.date_published,
downloads: v.downloads,
version_type: v.version_type,
@@ -1015,7 +1012,6 @@ mod tests {
name: Default::default(),
version_number: Default::default(),
changelog: Default::default(),
changelog_url: Default::default(),
downloads: Default::default(),
version_type: Default::default(),
featured: Default::default(),