You've already forked AstralRinth
forked from didirus/AstralRinth
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:
@@ -1,3 +1,5 @@
|
||||
// Legacy models from V2, where its useful to keep the struct for rerouting/conversion
|
||||
pub mod notifications;
|
||||
pub mod projects;
|
||||
pub mod search;
|
||||
pub mod teams;
|
||||
|
||||
183
src/models/v2/notifications.rs
Normal file
183
src/models/v2/notifications.rs
Normal file
@@ -0,0 +1,183 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{
|
||||
ids::{
|
||||
NotificationId, OrganizationId, ProjectId, ReportId, TeamId, ThreadId, ThreadMessageId,
|
||||
UserId, VersionId,
|
||||
},
|
||||
notifications::{Notification, NotificationAction, NotificationBody},
|
||||
projects::ProjectStatus,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct LegacyNotification {
|
||||
pub id: NotificationId,
|
||||
pub user_id: UserId,
|
||||
pub read: bool,
|
||||
pub created: DateTime<Utc>,
|
||||
pub body: LegacyNotificationBody,
|
||||
|
||||
// DEPRECATED: use body field instead
|
||||
#[serde(rename = "type")]
|
||||
pub type_: Option<String>,
|
||||
pub title: String,
|
||||
pub text: String,
|
||||
pub link: String,
|
||||
pub actions: Vec<LegacyNotificationAction>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct LegacyNotificationAction {
|
||||
pub title: String,
|
||||
/// The route to call when this notification action is called. Formatted HTTP Method, route
|
||||
pub action_route: (String, String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum LegacyNotificationBody {
|
||||
ProjectUpdate {
|
||||
project_id: ProjectId,
|
||||
version_id: VersionId,
|
||||
},
|
||||
TeamInvite {
|
||||
project_id: ProjectId,
|
||||
team_id: TeamId,
|
||||
invited_by: UserId,
|
||||
role: String,
|
||||
},
|
||||
OrganizationInvite {
|
||||
organization_id: OrganizationId,
|
||||
invited_by: UserId,
|
||||
team_id: TeamId,
|
||||
role: String,
|
||||
},
|
||||
StatusChange {
|
||||
project_id: ProjectId,
|
||||
old_status: ProjectStatus,
|
||||
new_status: ProjectStatus,
|
||||
},
|
||||
ModeratorMessage {
|
||||
thread_id: ThreadId,
|
||||
message_id: ThreadMessageId,
|
||||
|
||||
project_id: Option<ProjectId>,
|
||||
report_id: Option<ReportId>,
|
||||
},
|
||||
LegacyMarkdown {
|
||||
notification_type: Option<String>,
|
||||
title: String,
|
||||
text: String,
|
||||
link: String,
|
||||
actions: Vec<NotificationAction>,
|
||||
},
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl LegacyNotification {
|
||||
pub fn from(notification: Notification) -> Self {
|
||||
let type_ = match ¬ification.body {
|
||||
NotificationBody::ProjectUpdate { .. } => Some("project_update".to_string()),
|
||||
NotificationBody::TeamInvite { .. } => Some("team_invite".to_string()),
|
||||
NotificationBody::OrganizationInvite { .. } => Some("organization_invite".to_string()),
|
||||
NotificationBody::StatusChange { .. } => Some("status_change".to_string()),
|
||||
NotificationBody::ModeratorMessage { .. } => Some("moderator_message".to_string()),
|
||||
NotificationBody::LegacyMarkdown {
|
||||
notification_type, ..
|
||||
} => notification_type.clone(),
|
||||
NotificationBody::Unknown => None,
|
||||
};
|
||||
|
||||
let legacy_body = match notification.body {
|
||||
NotificationBody::ProjectUpdate {
|
||||
project_id,
|
||||
version_id,
|
||||
} => LegacyNotificationBody::ProjectUpdate {
|
||||
project_id,
|
||||
version_id,
|
||||
},
|
||||
NotificationBody::TeamInvite {
|
||||
project_id,
|
||||
team_id,
|
||||
invited_by,
|
||||
role,
|
||||
} => LegacyNotificationBody::TeamInvite {
|
||||
project_id,
|
||||
team_id,
|
||||
invited_by,
|
||||
role,
|
||||
},
|
||||
NotificationBody::OrganizationInvite {
|
||||
organization_id,
|
||||
invited_by,
|
||||
team_id,
|
||||
role,
|
||||
} => LegacyNotificationBody::OrganizationInvite {
|
||||
organization_id,
|
||||
invited_by,
|
||||
team_id,
|
||||
role,
|
||||
},
|
||||
NotificationBody::StatusChange {
|
||||
project_id,
|
||||
old_status,
|
||||
new_status,
|
||||
} => LegacyNotificationBody::StatusChange {
|
||||
project_id,
|
||||
old_status,
|
||||
new_status,
|
||||
},
|
||||
NotificationBody::ModeratorMessage {
|
||||
thread_id,
|
||||
message_id,
|
||||
project_id,
|
||||
report_id,
|
||||
} => LegacyNotificationBody::ModeratorMessage {
|
||||
thread_id,
|
||||
message_id,
|
||||
project_id,
|
||||
report_id,
|
||||
},
|
||||
NotificationBody::LegacyMarkdown {
|
||||
notification_type,
|
||||
name,
|
||||
text,
|
||||
link,
|
||||
actions,
|
||||
} => LegacyNotificationBody::LegacyMarkdown {
|
||||
notification_type,
|
||||
title: name,
|
||||
text,
|
||||
link,
|
||||
actions,
|
||||
},
|
||||
NotificationBody::Unknown => LegacyNotificationBody::Unknown,
|
||||
};
|
||||
|
||||
Self {
|
||||
id: notification.id,
|
||||
user_id: notification.user_id,
|
||||
read: notification.read,
|
||||
created: notification.created,
|
||||
body: legacy_body,
|
||||
type_,
|
||||
title: notification.name,
|
||||
text: notification.text,
|
||||
link: notification.link,
|
||||
actions: notification
|
||||
.actions
|
||||
.into_iter()
|
||||
.map(LegacyNotificationAction::from)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LegacyNotificationAction {
|
||||
pub fn from(notification_action: NotificationAction) -> Self {
|
||||
Self {
|
||||
title: notification_action.name,
|
||||
action_route: notification_action.action_route,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ use crate::database::models::{version_item, DatabaseError};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::models::ids::{ProjectId, VersionId};
|
||||
use crate::models::projects::{
|
||||
Dependency, GalleryItem, License, Link, Loader, ModeratorMessage, MonetizationStatus, Project,
|
||||
Dependency, License, Link, Loader, ModeratorMessage, MonetizationStatus, Project,
|
||||
ProjectStatus, Version, VersionFile, VersionStatus, VersionType,
|
||||
};
|
||||
use crate::models::threads::ThreadId;
|
||||
@@ -63,7 +63,7 @@ pub struct LegacyProject {
|
||||
pub wiki_url: Option<String>,
|
||||
pub discord_url: Option<String>,
|
||||
pub donation_urls: Option<Vec<DonationLink>>,
|
||||
pub gallery: Vec<GalleryItem>,
|
||||
pub gallery: Vec<LegacyGalleryItem>,
|
||||
pub color: Option<u32>,
|
||||
pub thread_id: ThreadId,
|
||||
pub monetization_status: MonetizationStatus,
|
||||
@@ -151,12 +151,12 @@ impl LegacyProject {
|
||||
id: data.id,
|
||||
slug: data.slug,
|
||||
project_type,
|
||||
team: data.team,
|
||||
team: data.team_id,
|
||||
organization: data.organization,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
body: data.body,
|
||||
body_url: data.body_url,
|
||||
title: data.name,
|
||||
description: data.summary, // V2 description is V3 summary
|
||||
body: data.description, // V2 body is V3 description
|
||||
body_url: None, // Always None even in V2
|
||||
published: data.published,
|
||||
updated: data.updated,
|
||||
approved: data.approved,
|
||||
@@ -177,7 +177,11 @@ impl LegacyProject {
|
||||
wiki_url,
|
||||
discord_url,
|
||||
donation_urls,
|
||||
gallery: data.gallery,
|
||||
gallery: data
|
||||
.gallery
|
||||
.into_iter()
|
||||
.map(LegacyGalleryItem::from)
|
||||
.collect(),
|
||||
color: data.color,
|
||||
thread_id: data.thread_id,
|
||||
monetization_status: data.monetization_status,
|
||||
@@ -317,7 +321,7 @@ impl From<Version> for LegacyVersion {
|
||||
name: data.name,
|
||||
version_number: data.version_number,
|
||||
changelog: data.changelog,
|
||||
changelog_url: data.changelog_url,
|
||||
changelog_url: None, // Always None even in V2
|
||||
date_published: data.date_published,
|
||||
downloads: data.downloads,
|
||||
version_type: data.version_type,
|
||||
@@ -332,6 +336,29 @@ impl From<Version> for LegacyVersion {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct LegacyGalleryItem {
|
||||
pub url: String,
|
||||
pub featured: bool,
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub ordering: i64,
|
||||
}
|
||||
|
||||
impl LegacyGalleryItem {
|
||||
fn from(data: crate::models::projects::GalleryItem) -> Self {
|
||||
Self {
|
||||
url: data.url,
|
||||
featured: data.featured,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
created: data.created,
|
||||
ordering: data.ordering,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate, Clone, Eq, PartialEq)]
|
||||
pub struct DonationLink {
|
||||
pub id: String,
|
||||
|
||||
@@ -109,7 +109,7 @@ impl LegacyResultSearchProject {
|
||||
project_id: result_search_project.project_id,
|
||||
slug: result_search_project.slug,
|
||||
author: result_search_project.author,
|
||||
title: result_search_project.title,
|
||||
title: result_search_project.name,
|
||||
description: result_search_project.description,
|
||||
display_categories,
|
||||
downloads: result_search_project.downloads,
|
||||
|
||||
41
src/models/v2/teams.rs
Normal file
41
src/models/v2/teams.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{
|
||||
ids::TeamId,
|
||||
teams::{ProjectPermissions, TeamMember},
|
||||
users::User,
|
||||
};
|
||||
|
||||
/// A member of a team
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct LegacyTeamMember {
|
||||
pub role: String,
|
||||
// is_owner removed, and role hardcoded to Owner if true,
|
||||
pub team_id: TeamId,
|
||||
pub user: User,
|
||||
pub permissions: Option<ProjectPermissions>,
|
||||
pub accepted: bool,
|
||||
|
||||
#[serde(with = "rust_decimal::serde::float_option")]
|
||||
pub payouts_split: Option<Decimal>,
|
||||
pub ordering: i64,
|
||||
}
|
||||
|
||||
impl LegacyTeamMember {
|
||||
pub fn from(team_member: TeamMember) -> Self {
|
||||
LegacyTeamMember {
|
||||
role: match (team_member.is_owner, team_member.role.as_str()) {
|
||||
(true, _) => "Owner".to_string(),
|
||||
(false, "Owner") => "Member".to_string(), // The odd case of a non-owner with the owner role should show as 'Member'
|
||||
(false, role) => role.to_string(),
|
||||
},
|
||||
team_id: team_member.team_id,
|
||||
user: team_member.user,
|
||||
permissions: team_member.permissions,
|
||||
accepted: team_member.accepted,
|
||||
payouts_split: team_member.payouts_split,
|
||||
ordering: team_member.ordering,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ pub struct Collection {
|
||||
/// The person that has ownership of this collection.
|
||||
pub user: UserId,
|
||||
/// The title or name of the collection.
|
||||
pub title: String,
|
||||
pub name: String,
|
||||
/// A short description of the collection.
|
||||
pub description: String,
|
||||
|
||||
@@ -48,7 +48,7 @@ impl From<database::models::Collection> for Collection {
|
||||
id: c.id.into(),
|
||||
user: c.user_id.into(),
|
||||
created: c.created,
|
||||
title: c.title,
|
||||
name: c.name,
|
||||
description: c.description,
|
||||
updated: c.updated,
|
||||
projects: c.projects.into_iter().map(|x| x.into()).collect(),
|
||||
|
||||
@@ -21,10 +21,7 @@ pub struct Notification {
|
||||
pub created: DateTime<Utc>,
|
||||
pub body: NotificationBody,
|
||||
|
||||
// DEPRECATED: use body field instead
|
||||
#[serde(rename = "type")]
|
||||
pub type_: Option<String>,
|
||||
pub title: String,
|
||||
pub name: String,
|
||||
pub text: String,
|
||||
pub link: String,
|
||||
pub actions: Vec<NotificationAction>,
|
||||
@@ -63,7 +60,7 @@ pub enum NotificationBody {
|
||||
},
|
||||
LegacyMarkdown {
|
||||
notification_type: Option<String>,
|
||||
title: String,
|
||||
name: String,
|
||||
text: String,
|
||||
link: String,
|
||||
actions: Vec<NotificationAction>,
|
||||
@@ -73,13 +70,12 @@ pub enum NotificationBody {
|
||||
|
||||
impl From<DBNotification> for Notification {
|
||||
fn from(notif: DBNotification) -> Self {
|
||||
let (type_, title, text, link, actions) = {
|
||||
let (name, text, link, actions) = {
|
||||
match ¬if.body {
|
||||
NotificationBody::ProjectUpdate {
|
||||
project_id,
|
||||
version_id,
|
||||
} => (
|
||||
Some("project_update".to_string()),
|
||||
"A project you follow has been updated!".to_string(),
|
||||
format!(
|
||||
"The project {} has released a new version: {}",
|
||||
@@ -94,17 +90,16 @@ impl From<DBNotification> for Notification {
|
||||
team_id,
|
||||
..
|
||||
} => (
|
||||
Some("team_invite".to_string()),
|
||||
"You have been invited to join a team!".to_string(),
|
||||
format!("An invite has been sent for you to be {} of a team", role),
|
||||
format!("/project/{}", project_id),
|
||||
vec![
|
||||
NotificationAction {
|
||||
title: "Accept".to_string(),
|
||||
name: "Accept".to_string(),
|
||||
action_route: ("POST".to_string(), format!("team/{team_id}/join")),
|
||||
},
|
||||
NotificationAction {
|
||||
title: "Deny".to_string(),
|
||||
name: "Deny".to_string(),
|
||||
action_route: (
|
||||
"DELETE".to_string(),
|
||||
format!("team/{team_id}/members/{}", UserId::from(notif.user_id)),
|
||||
@@ -118,7 +113,6 @@ impl From<DBNotification> for Notification {
|
||||
team_id,
|
||||
..
|
||||
} => (
|
||||
Some("organization_invite".to_string()),
|
||||
"You have been invited to join an organization!".to_string(),
|
||||
format!(
|
||||
"An invite has been sent for you to be {} of an organization",
|
||||
@@ -127,11 +121,11 @@ impl From<DBNotification> for Notification {
|
||||
format!("/organization/{}", organization_id),
|
||||
vec![
|
||||
NotificationAction {
|
||||
title: "Accept".to_string(),
|
||||
name: "Accept".to_string(),
|
||||
action_route: ("POST".to_string(), format!("team/{team_id}/join")),
|
||||
},
|
||||
NotificationAction {
|
||||
title: "Deny".to_string(),
|
||||
name: "Deny".to_string(),
|
||||
action_route: (
|
||||
"DELETE".to_string(),
|
||||
format!(
|
||||
@@ -147,7 +141,6 @@ impl From<DBNotification> for Notification {
|
||||
new_status,
|
||||
project_id,
|
||||
} => (
|
||||
Some("status_change".to_string()),
|
||||
"Project status has changed".to_string(),
|
||||
format!(
|
||||
"Status has changed from {} to {}",
|
||||
@@ -162,7 +155,6 @@ impl From<DBNotification> for Notification {
|
||||
report_id,
|
||||
..
|
||||
} => (
|
||||
Some("moderator_message".to_string()),
|
||||
"A moderator has sent you a message!".to_string(),
|
||||
"Click on the link to read more.".to_string(),
|
||||
if let Some(project_id) = project_id {
|
||||
@@ -175,25 +167,20 @@ impl From<DBNotification> for Notification {
|
||||
vec![],
|
||||
),
|
||||
NotificationBody::LegacyMarkdown {
|
||||
notification_type,
|
||||
title,
|
||||
name,
|
||||
text,
|
||||
link,
|
||||
actions,
|
||||
..
|
||||
} => (
|
||||
notification_type.clone(),
|
||||
title.clone(),
|
||||
name.clone(),
|
||||
text.clone(),
|
||||
link.clone(),
|
||||
actions.clone().into_iter().map(Into::into).collect(),
|
||||
),
|
||||
NotificationBody::Unknown => (
|
||||
None,
|
||||
"".to_string(),
|
||||
"".to_string(),
|
||||
"#".to_string(),
|
||||
vec![],
|
||||
),
|
||||
NotificationBody::Unknown => {
|
||||
("".to_string(), "".to_string(), "#".to_string(), vec![])
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -204,9 +191,7 @@ impl From<DBNotification> for Notification {
|
||||
read: notif.read,
|
||||
created: notif.created,
|
||||
|
||||
// DEPRECATED
|
||||
type_,
|
||||
title,
|
||||
name,
|
||||
text,
|
||||
link,
|
||||
actions,
|
||||
@@ -216,7 +201,7 @@ impl From<DBNotification> for Notification {
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct NotificationAction {
|
||||
pub title: String,
|
||||
pub name: String,
|
||||
/// The route to call when this notification action is called. Formatted HTTP Method, route
|
||||
pub action_route: (String, String),
|
||||
}
|
||||
@@ -224,7 +209,7 @@ pub struct NotificationAction {
|
||||
impl From<DBNotificationAction> for NotificationAction {
|
||||
fn from(act: DBNotificationAction) -> Self {
|
||||
Self {
|
||||
title: act.title,
|
||||
name: act.name,
|
||||
action_route: (act.action_route_method, act.action_route),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct Organization {
|
||||
/// The id of the 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,
|
||||
/// The description of the organization
|
||||
@@ -38,7 +38,7 @@ impl Organization {
|
||||
) -> Self {
|
||||
Self {
|
||||
id: data.id.into(),
|
||||
title: data.title,
|
||||
name: data.name,
|
||||
team_id: data.team_id.into(),
|
||||
description: data.description,
|
||||
members: team_members,
|
||||
|
||||
@@ -34,17 +34,15 @@ pub struct Project {
|
||||
/// The aggregated games of the versions of this project
|
||||
pub games: Vec<String>,
|
||||
/// The team of people that has ownership of this project.
|
||||
pub team: TeamId,
|
||||
pub team_id: TeamId,
|
||||
/// The optional organization of people that have ownership of this project.
|
||||
pub organization: Option<OrganizationId>,
|
||||
/// The title or name of the project.
|
||||
pub title: String,
|
||||
pub name: String,
|
||||
/// A short description of the project.
|
||||
pub description: String,
|
||||
pub summary: String,
|
||||
/// A long form description of the project.
|
||||
pub body: String,
|
||||
/// The link to the long description of the project. Deprecated, always None
|
||||
pub body_url: Option<String>,
|
||||
pub description: String,
|
||||
|
||||
/// The date at which the project was first published.
|
||||
pub published: DateTime<Utc>,
|
||||
@@ -151,12 +149,11 @@ impl From<QueryProject> for Project {
|
||||
slug: m.slug,
|
||||
project_types: data.project_types,
|
||||
games: data.games,
|
||||
team: m.team_id.into(),
|
||||
team_id: m.team_id.into(),
|
||||
organization: m.organization_id.map(|i| i.into()),
|
||||
title: m.title,
|
||||
name: m.name,
|
||||
summary: m.summary,
|
||||
description: m.description,
|
||||
body: m.body,
|
||||
body_url: None,
|
||||
published: m.published,
|
||||
updated: m.updated,
|
||||
approved: m.approved,
|
||||
@@ -210,7 +207,7 @@ impl From<QueryProject> for Project {
|
||||
.map(|x| GalleryItem {
|
||||
url: x.image_url,
|
||||
featured: x.featured,
|
||||
title: x.title,
|
||||
name: x.name,
|
||||
description: x.description,
|
||||
created: x.created,
|
||||
ordering: x.ordering,
|
||||
@@ -228,7 +225,7 @@ impl From<QueryProject> for Project {
|
||||
pub struct GalleryItem {
|
||||
pub url: String,
|
||||
pub featured: bool,
|
||||
pub title: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub created: DateTime<Utc>,
|
||||
pub ordering: i64,
|
||||
@@ -464,8 +461,6 @@ pub struct Version {
|
||||
pub games: Vec<String>,
|
||||
/// The changelog for this version of the project.
|
||||
pub changelog: String,
|
||||
/// A link to the changelog for this version of the project. Deprecated, always None
|
||||
pub changelog_url: Option<String>,
|
||||
|
||||
/// The date that this version was published.
|
||||
pub date_published: DateTime<Utc>,
|
||||
@@ -517,7 +512,6 @@ impl From<QueryVersion> for Version {
|
||||
project_types: data.project_types,
|
||||
games: data.games,
|
||||
changelog: v.changelog,
|
||||
changelog_url: None,
|
||||
date_published: v.date_published,
|
||||
downloads: v.downloads as u32,
|
||||
version_type: match v.version_type.as_str() {
|
||||
|
||||
@@ -135,6 +135,8 @@ pub struct TeamMember {
|
||||
pub user: User,
|
||||
/// The role of the user in the team
|
||||
pub role: String,
|
||||
/// Is the user the owner of the team?
|
||||
pub is_owner: bool,
|
||||
/// A bitset containing the user's permissions in this team.
|
||||
/// In an organization-controlled project, these are the unique overriding permissions for the user's role for any project in the organization, if they exist.
|
||||
/// In an organization, these are the default project permissions for any project in the organization.
|
||||
@@ -178,6 +180,7 @@ impl TeamMember {
|
||||
team_id: data.team_id.into(),
|
||||
user,
|
||||
role: data.role,
|
||||
is_owner: data.is_owner,
|
||||
permissions: if override_permissions {
|
||||
None
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user