mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 13:16:38 +00:00
feat(labrinth): project disclosures database model
This commit is contained in:
Generated
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tINSERT INTO project_disclosures (project_id, type, metadata, updated_by, support)\n\t\t\tVALUES ($1, $2, $3, $4, $5)\n\t\t\tON CONFLICT (project_id, type) DO UPDATE SET\n\t\t\t\tmetadata = $3,\n\t\t\t\tupdated_at = now(),\n\t\t\t\tupdated_by = $4,\n\t\t\t\tsupport = $5\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Int8",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "02ef27605b8d19c35cebe27d618b690a420f7529a6b319893bd219760a258926"
|
||||
}
|
||||
Generated
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tINSERT INTO project_disclosures (project_id, type, metadata, updated_by, moderator)\n\t\t\tVALUES ($1, $2, $3, $4, $5)\n\t\t\tON CONFLICT (project_id, type) DO UPDATE SET\n\t\t\t\tmetadata = $3,\n\t\t\t\tupdated_at = now(),\n\t\t\t\tupdated_by = $4,\n\t\t\t\tmoderator = $5\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Int8",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "67443fdd9d8daaecc26e198cb439d5e5ec33d41b9ae3be81330facedd50c7564"
|
||||
}
|
||||
Generated
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tDELETE FROM project_disclosures\n\t\t\tWHERE project_id = $1 AND type = $2\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9eea063cb153da407548f957cef7da1a33a059b0a1d00b51e27b4a5399492b13"
|
||||
}
|
||||
Generated
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tINSERT INTO project_disclosures (project_id, type, metadata, updated_by, set_by_moderator)\n\t\t\tVALUES ($1, $2, $3, $4, $5)\n\t\t\tON CONFLICT (project_id, type) DO UPDATE SET\n\t\t\t\tmetadata = $3,\n\t\t\t\tupdated_at = now(),\n\t\t\t\tupdated_by = $4,\n\t\t\t\tset_by_moderator = $5\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text",
|
||||
"Jsonb",
|
||||
"Int8",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b6b9b0cd345eddb4c4a9daf701dd0d2e5a708e59b897961f00164a28ab6294a4"
|
||||
}
|
||||
Generated
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tSELECT project_id, type AS \"disclosure_type!\", metadata, updated_at, updated_by, moderator\n\t\t\tFROM project_disclosures\n\t\t\tWHERE project_id = $1\n\t\t\tORDER BY updated_at DESC\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "project_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "disclosure_type!",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "metadata",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "updated_by",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "moderator",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e6db9cff0b164399dba86a54ac512813c1374a86daf5737f14fe49944de5d73f"
|
||||
}
|
||||
Generated
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tSELECT project_id, type AS \"disclosure_type!\", metadata, updated_at, updated_by, set_by_moderator\n\t\t\tFROM project_disclosures\n\t\t\tWHERE project_id = $1\n\t\t\tORDER BY updated_at DESC\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "project_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "disclosure_type!",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "metadata",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "updated_by",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "set_by_moderator",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ef602037ceb20dbce5313e4a90c16fb59fbbe0adf002d21fc40ca0ddd9d6ab10"
|
||||
}
|
||||
Generated
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n\t\t\tSELECT project_id, type AS \"disclosure_type!\", metadata, updated_at, updated_by, support\n\t\t\tFROM project_disclosures\n\t\t\tWHERE project_id = $1\n\t\t\tORDER BY updated_at DESC\n\t\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "project_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "disclosure_type!",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "metadata",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "updated_by",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "support",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "fd137835f703a2e4041554b36c94e4499ecb9ec4ee80308bfe7fa3082be08f0c"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE project_disclosures (
|
||||
project_id BIGINT NOT NULL REFERENCES mods(id) ON DELETE CASCADE,
|
||||
type TEXT NOT NULL,
|
||||
metadata JSONB NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_by BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
set_by_moderator BOOLEAN NOT NULL,
|
||||
PRIMARY KEY (project_id, type)
|
||||
);
|
||||
@@ -30,6 +30,7 @@ pub mod payout_item;
|
||||
pub mod payouts_values_notifications;
|
||||
pub mod product_item;
|
||||
pub mod products_tax_identifier_item;
|
||||
pub mod project_disclosure_item;
|
||||
pub mod project_item;
|
||||
pub mod report_item;
|
||||
pub mod session_item;
|
||||
@@ -53,6 +54,7 @@ pub use image_item::DBImage;
|
||||
pub use oauth_client_item::DBOAuthClient;
|
||||
pub use organization_item::DBOrganization;
|
||||
pub use passkey_item::DBPasskey;
|
||||
pub use project_disclosure_item::DBProjectDisclosure;
|
||||
pub use project_item::DBProject;
|
||||
pub use team_item::DBTeam;
|
||||
pub use team_item::DBTeamMember;
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
database::models::{DBProjectId, DBUserId, DatabaseError},
|
||||
models::v3::disclosures::ProjectDisclosure,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DBProjectDisclosure {
|
||||
pub project_id: DBProjectId,
|
||||
pub disclosure: ProjectDisclosure,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub updated_by: DBUserId,
|
||||
pub set_by_moderator: bool,
|
||||
}
|
||||
|
||||
impl DBProjectDisclosure {
|
||||
pub async fn upsert(
|
||||
&self,
|
||||
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let (disclosure_type, metadata) =
|
||||
self.disclosure.to_parts().map_err(|e| {
|
||||
DatabaseError::Internal(eyre::Report::new(e).wrap_err(
|
||||
"failed to serialize project disclosure metadata",
|
||||
))
|
||||
})?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO project_disclosures (project_id, type, metadata, updated_by, set_by_moderator)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (project_id, type) DO UPDATE SET
|
||||
metadata = $3,
|
||||
updated_at = now(),
|
||||
updated_by = $4,
|
||||
set_by_moderator = $5
|
||||
"#,
|
||||
self.project_id as DBProjectId,
|
||||
disclosure_type,
|
||||
metadata,
|
||||
self.updated_by as DBUserId,
|
||||
self.set_by_moderator,
|
||||
)
|
||||
.execute(exec)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_many_for_project(
|
||||
project_id: DBProjectId,
|
||||
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<Vec<DBProjectDisclosure>, DatabaseError> {
|
||||
let rows = sqlx::query!(
|
||||
r#"
|
||||
SELECT project_id, type AS "disclosure_type!", metadata, updated_at, updated_by, set_by_moderator
|
||||
FROM project_disclosures
|
||||
WHERE project_id = $1
|
||||
ORDER BY updated_at DESC
|
||||
"#,
|
||||
project_id as DBProjectId,
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
rows.into_iter()
|
||||
.map(|row| {
|
||||
Ok(DBProjectDisclosure {
|
||||
project_id: DBProjectId(row.project_id),
|
||||
disclosure: ProjectDisclosure::from_parts(
|
||||
&row.disclosure_type,
|
||||
row.metadata,
|
||||
)
|
||||
.map_err(|e| {
|
||||
DatabaseError::Internal(eyre::Report::new(e).wrap_err(
|
||||
"failed to deserialize project disclosure metadata",
|
||||
))
|
||||
})?,
|
||||
updated_at: row.updated_at,
|
||||
updated_by: DBUserId(row.updated_by),
|
||||
set_by_moderator: row.set_by_moderator,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
project_id: DBProjectId,
|
||||
disclosure_type: &str,
|
||||
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<bool, DatabaseError> {
|
||||
let result = sqlx::query!(
|
||||
r#"
|
||||
DELETE FROM project_disclosures
|
||||
WHERE project_id = $1 AND type = $2
|
||||
"#,
|
||||
project_id as DBProjectId,
|
||||
disclosure_type,
|
||||
)
|
||||
.execute(exec)
|
||||
.await?;
|
||||
|
||||
Ok(result.rows_affected() > 0)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
use ariadne::ids::UserId;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoStaticStr;
|
||||
use utoipa::ToSchema;
|
||||
use crate::database::models::DBProjectDisclosure;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoStaticStr)]
|
||||
#[serde(rename_all = "snake_case", tag = "type")]
|
||||
@@ -30,6 +33,57 @@ pub enum ProjectDisclosure {
|
||||
},
|
||||
}
|
||||
|
||||
impl ProjectDisclosure {
|
||||
pub fn to_parts(
|
||||
&self,
|
||||
) -> Result<(&'static str, serde_json::Value), serde_json::Error> {
|
||||
let serde_json::Value::Object(mut object) = serde_json::to_value(self)?
|
||||
else {
|
||||
return Err(serde::ser::Error::custom(
|
||||
"project disclosure must serialize to a JSON object",
|
||||
));
|
||||
};
|
||||
object.remove("type");
|
||||
Ok((self.into(), serde_json::Value::Object(object)))
|
||||
}
|
||||
|
||||
pub fn from_parts(
|
||||
kind: &str,
|
||||
metadata: serde_json::Value,
|
||||
) -> Result<Self, serde_json::Error> {
|
||||
let serde_json::Value::Object(mut object) = metadata else {
|
||||
return Err(serde::ser::Error::custom(
|
||||
"project disclosure metadata must be a JSON object, this should never be reachable",
|
||||
));
|
||||
};
|
||||
object.insert(
|
||||
"type".to_owned(),
|
||||
serde_json::Value::String(kind.to_owned()),
|
||||
);
|
||||
serde_json::from_value(serde_json::Value::Object(object))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ProjectDisclosureData {
|
||||
#[serde(flatten)]
|
||||
pub disclosure: ProjectDisclosure,
|
||||
pub set_by_moderator: bool,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub updated_by: UserId,
|
||||
}
|
||||
|
||||
impl From<DBProjectDisclosure> for ProjectDisclosureData {
|
||||
fn from(db: DBProjectDisclosure) -> Self {
|
||||
Self {
|
||||
disclosure: db.disclosure,
|
||||
set_by_moderator: db.set_by_moderator,
|
||||
updated_at: db.updated_at,
|
||||
updated_by: db.updated_by.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TelementryConsent {
|
||||
|
||||
Reference in New Issue
Block a user