diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 0054f93..1c2ed26 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -710,9 +710,7 @@ paths: type: object properties: status: - description: | - Text content of the post. - Allowed HTML tags: a, br, pre, code, strong, em, p. + description: Text content of the post. type: string content_type: description: Media type of the post content. @@ -751,6 +749,42 @@ paths: $ref: '#/components/schemas/Status' 400: description: Invalid post data + /api/v1/statuses/preview: + post: + summary: Preview new post. + security: + - tokenAuth: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + status: + description: Text content of the post. + type: string + content_type: + description: Media type of the post content. + type: string + default: text/html + enum: + - text/html + - text/markdown + required: + - status + responses: + 200: + description: Preview generated. + content: + application/json: + schema: + type: object + properties: + content: + description: HTML-encoded post content. + type: string + 400: + description: Invalid post data. /api/v1/statuses/{status_id}: delete: summary: Delete post diff --git a/src/mastodon_api/statuses/types.rs b/src/mastodon_api/statuses/types.rs index 83e8357..c744775 100644 --- a/src/mastodon_api/statuses/types.rs +++ b/src/mastodon_api/statuses/types.rs @@ -149,6 +149,19 @@ pub struct StatusData { pub content_type: String, } +#[derive(Deserialize)] +pub struct StatusPreviewData { + pub status: String, + + #[serde(default = "default_post_content_type")] + pub content_type: String, +} + +#[derive(Serialize)] +pub struct StatusPreview { + pub content: String, +} + #[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 2d804ef..86d7ce1 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -47,7 +47,13 @@ use super::helpers::{ parse_microsyntaxes, PostContent, }; -use super::types::{Status, StatusData, TransactionData}; +use super::types::{ + Status, + StatusData, + StatusPreview, + StatusPreviewData, + TransactionData, +}; #[post("")] async fn create_status( @@ -161,6 +167,36 @@ async fn create_status( Ok(HttpResponse::Created().json(status)) } +#[post("/preview")] +async fn preview_status( + auth: BearerAuth, + config: web::Data, + db_pool: web::Data, + status_data: web::Json, +) -> Result { + let db_client = &**get_database_client(&db_pool).await?; + get_current_user(db_client, auth.token()).await?; + let status_data = status_data.into_inner(); + let content = match status_data.content_type.as_str() { + "text/html" => status_data.status, + "text/markdown" => { + markdown_lite_to_html(&status_data.status) + .map_err(|_| ValidationError("invalid markdown"))? + }, + _ => return Err(ValidationError("unsupported content type").into()), + }; + let PostContent { mut content, .. } = parse_microsyntaxes( + db_client, + &config.instance(), + content, + ).await?; + // Clean content + content = clean_content(&content)?; + // Return preview + let preview = StatusPreview { content }; + Ok(HttpResponse::Ok().json(preview)) +} + #[get("/{status_id}")] async fn get_status( auth: Option, @@ -524,6 +560,7 @@ pub fn status_api_scope() -> Scope { web::scope("/api/v1/statuses") // Routes without status ID .service(create_status) + .service(preview_status) // Routes with status ID .service(get_status) .service(delete_status)