diff --git a/README.md b/README.md index 9e12ca9..3fd3fe1 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ Additional methods: ``` POST /api/v1/statuses/{status_id}/make_permanent GET /api/v1/statuses/{status_id}/signature +POST /api/v1/statuses/{status_id}/token_minted ``` [OpenAPI spec](./docs/openapi.yaml) diff --git a/docs/openapi.yaml b/docs/openapi.yaml index c1e8a5c..66c13b6 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -56,6 +56,32 @@ paths: description: Ethereum integration is not enabled 422: description: Post is not saved to IPFS + /api/v1/{status_id}/token_minted: + post: + summary: Register transaction that mints a token + parameters: + - $ref: '#/components/parameters/status_id' + requestBody: + content: + application/json: + schema: + properties: + transaction_id: + type: string + description: Transaction ID + responses: + 200: + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + 403: + description: Post does not belong to user or is not public + 404: + description: Post not found + 422: + description: Transaction already registered components: parameters: @@ -78,3 +104,7 @@ components: type: string nullable: true example: 'bafkr...' + token_tx_id: + type: string + nullable: true + example: '0x5fe80cdea7f...' diff --git a/src/mastodon_api/statuses/types.rs b/src/mastodon_api/statuses/types.rs index ec185b6..57bdae7 100644 --- a/src/mastodon_api/statuses/types.rs +++ b/src/mastodon_api/statuses/types.rs @@ -123,3 +123,8 @@ impl From for PostCreateData { } } } + +#[derive(Deserialize)] +pub struct TransactionData { + pub transaction_id: String, +} diff --git a/src/mastodon_api/statuses/views.rs b/src/mastodon_api/statuses/views.rs index 9b75ce3..02d38c1 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -40,7 +40,7 @@ use crate::models::reactions::queries::{ create_reaction, delete_reaction, }; -use super::types::{Status, StatusData}; +use super::types::{Status, StatusData, TransactionData}; #[post("")] async fn create_status( @@ -395,6 +395,31 @@ async fn get_signature( Ok(HttpResponse::Ok().json(signature)) } +#[post("/{status_id}/token_minted")] +async fn token_minted( + auth: BearerAuth, + config: web::Data, + db_pool: web::Data, + web::Path(status_id): web::Path, + data: web::Json, +) -> Result { + let db_client = &**get_database_client(&db_pool).await?; + let current_user = get_current_user(db_client, auth.token()).await?; + let mut post = get_post_by_id(db_client, &status_id).await?; + if post.token_tx_id.is_some() { + return Err(HttpError::OperationError("transaction is already registered")); + }; + if post.author.id != current_user.id || !post.is_public() { + return Err(HttpError::PermissionError); + }; + post.token_tx_id = Some(data.into_inner().transaction_id); + update_post(db_client, &post).await?; + get_reposted_posts(db_client, vec![&mut post]).await?; + get_actions_for_posts(db_client, ¤t_user.id, vec![&mut post]).await?; + let status = Status::from_post(post, &config.instance_url()); + Ok(HttpResponse::Ok().json(status)) +} + pub fn status_api_scope() -> Scope { web::scope("/api/v1/statuses") // Routes without status ID @@ -408,4 +433,5 @@ pub fn status_api_scope() -> Scope { .service(unreblog) .service(make_permanent) .service(get_signature) + .service(token_minted) } diff --git a/src/models/posts/queries.rs b/src/models/posts/queries.rs index 8f97cf2..6f0f605 100644 --- a/src/models/posts/queries.rs +++ b/src/models/posts/queries.rs @@ -450,7 +450,6 @@ pub async fn update_post( db_client: &impl GenericClient, post: &Post, ) -> Result<(), DatabaseError> { - // TODO: create PostUpdateData type let updated_count = db_client.execute( " UPDATE post