forked from Plume/Plume
Remove Canapi (#540)
* Remove Canapi It added more complexity than it helped. * Fail if there are many blog, but none was specified * cargo fmtfix-mobile-margin
parent
787eb7f399
commit
ec57f1e687
@ -1,12 +1,24 @@
|
||||
use canapi::Provider;
|
||||
use rocket_contrib::json::Json;
|
||||
use serde_json;
|
||||
|
||||
use plume_api::apps::AppEndpoint;
|
||||
use plume_models::{apps::App, db_conn::DbConn, Connection};
|
||||
use crate::api::Api;
|
||||
use plume_api::apps::NewAppData;
|
||||
use plume_common::utils::random_hex;
|
||||
use plume_models::{apps::*, db_conn::DbConn};
|
||||
|
||||
#[post("/apps", data = "<data>")]
|
||||
pub fn create(conn: DbConn, data: Json<AppEndpoint>) -> Json<serde_json::Value> {
|
||||
let post = <App as Provider<Connection>>::create(&*conn, (*data).clone()).ok();
|
||||
Json(json!(post))
|
||||
pub fn create(conn: DbConn, data: Json<NewAppData>) -> Api<App> {
|
||||
let client_id = random_hex();
|
||||
let client_secret = random_hex();
|
||||
let app = App::insert(
|
||||
&*conn,
|
||||
NewApp {
|
||||
name: data.name.clone(),
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uri: data.redirect_uri.clone(),
|
||||
website: data.website.clone(),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Json(app))
|
||||
}
|
||||
|
@ -1,54 +1,236 @@
|
||||
use canapi::{Error as ApiError, Provider};
|
||||
use rocket::http::uri::Origin;
|
||||
use chrono::NaiveDateTime;
|
||||
use heck::{CamelCase, KebabCase};
|
||||
use rocket_contrib::json::Json;
|
||||
use serde_json;
|
||||
use serde_qs;
|
||||
|
||||
use api::authorization::*;
|
||||
use plume_api::posts::PostEndpoint;
|
||||
use plume_models::{posts::Post, users::User, PlumeRocket};
|
||||
use crate::api::{authorization::*, Api};
|
||||
use plume_api::posts::*;
|
||||
use plume_common::{activity_pub::broadcast, utils::md_to_html};
|
||||
use plume_models::{
|
||||
blogs::Blog, db_conn::DbConn, instance::Instance, medias::Media, mentions::*, post_authors::*,
|
||||
posts::*, safe_string::SafeString, tags::*, users::User, Error, PlumeRocket,
|
||||
};
|
||||
|
||||
#[get("/posts/<id>")]
|
||||
pub fn get(
|
||||
id: i32,
|
||||
auth: Option<Authorization<Read, Post>>,
|
||||
mut rockets: PlumeRocket,
|
||||
) -> Json<serde_json::Value> {
|
||||
rockets.user = auth.and_then(|a| User::get(&*rockets.conn, a.0.user_id).ok());
|
||||
let post = <Post as Provider<PlumeRocket>>::get(&rockets, id).ok();
|
||||
Json(json!(post))
|
||||
pub fn get(id: i32, auth: Option<Authorization<Read, Post>>, conn: DbConn) -> Api<PostData> {
|
||||
let user = auth.and_then(|a| User::get(&conn, a.0.user_id).ok());
|
||||
let post = Post::get(&conn, id)?;
|
||||
|
||||
if !post.published
|
||||
&& !user
|
||||
.and_then(|u| post.is_author(&conn, u.id).ok())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Err(Error::Unauthorized.into());
|
||||
}
|
||||
|
||||
Ok(Json(PostData {
|
||||
authors: post
|
||||
.get_authors(&conn)?
|
||||
.into_iter()
|
||||
.map(|a| a.username)
|
||||
.collect(),
|
||||
creation_date: post.creation_date.format("%Y-%m-%d").to_string(),
|
||||
tags: Tag::for_post(&conn, post.id)?
|
||||
.into_iter()
|
||||
.map(|t| t.tag)
|
||||
.collect(),
|
||||
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
subtitle: post.subtitle,
|
||||
content: post.content.to_string(),
|
||||
source: Some(post.source),
|
||||
blog_id: post.blog_id,
|
||||
published: post.published,
|
||||
license: post.license,
|
||||
cover_id: post.cover_id,
|
||||
}))
|
||||
}
|
||||
|
||||
#[get("/posts")]
|
||||
#[get("/posts?<title>&<subtitle>&<content>")]
|
||||
pub fn list(
|
||||
uri: &Origin,
|
||||
title: Option<String>,
|
||||
subtitle: Option<String>,
|
||||
content: Option<String>,
|
||||
auth: Option<Authorization<Read, Post>>,
|
||||
mut rockets: PlumeRocket,
|
||||
) -> Json<serde_json::Value> {
|
||||
rockets.user = auth.and_then(|a| User::get(&*rockets.conn, a.0.user_id).ok());
|
||||
let query: PostEndpoint =
|
||||
serde_qs::from_str(uri.query().unwrap_or("")).expect("api::list: invalid query error");
|
||||
let post = <Post as Provider<PlumeRocket>>::list(&rockets, query);
|
||||
Json(json!(post))
|
||||
conn: DbConn,
|
||||
) -> Api<Vec<PostData>> {
|
||||
let user = auth.and_then(|a| User::get(&conn, a.0.user_id).ok());
|
||||
let user_id = user.map(|u| u.id);
|
||||
|
||||
Ok(Json(
|
||||
Post::list_filtered(&conn, title, subtitle, content)?
|
||||
.into_iter()
|
||||
.filter(|p| {
|
||||
p.published
|
||||
|| user_id
|
||||
.and_then(|u| p.is_author(&conn, u).ok())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.filter_map(|p| {
|
||||
Some(PostData {
|
||||
authors: p
|
||||
.get_authors(&conn)
|
||||
.ok()?
|
||||
.into_iter()
|
||||
.map(|a| a.username)
|
||||
.collect(),
|
||||
creation_date: p.creation_date.format("%Y-%m-%d").to_string(),
|
||||
tags: Tag::for_post(&conn, p.id)
|
||||
.ok()?
|
||||
.into_iter()
|
||||
.map(|t| t.tag)
|
||||
.collect(),
|
||||
|
||||
id: p.id,
|
||||
title: p.title,
|
||||
subtitle: p.subtitle,
|
||||
content: p.content.to_string(),
|
||||
source: Some(p.source),
|
||||
blog_id: p.blog_id,
|
||||
published: p.published,
|
||||
license: p.license,
|
||||
cover_id: p.cover_id,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
#[post("/posts", data = "<payload>")]
|
||||
pub fn create(
|
||||
auth: Authorization<Write, Post>,
|
||||
payload: Json<PostEndpoint>,
|
||||
mut rockets: PlumeRocket,
|
||||
) -> Json<serde_json::Value> {
|
||||
rockets.user = User::get(&*rockets.conn, auth.0.user_id).ok();
|
||||
let new_post = <Post as Provider<PlumeRocket>>::create(&rockets, (*payload).clone());
|
||||
Json(new_post.map(|p| json!(p)).unwrap_or_else(|e| {
|
||||
json!({
|
||||
"error": "Invalid data, couldn't create new post",
|
||||
"details": match e {
|
||||
ApiError::Fetch(msg) => msg,
|
||||
ApiError::SerDe(msg) => msg,
|
||||
ApiError::NotFound(msg) => msg,
|
||||
ApiError::Authorization(msg) => msg,
|
||||
}
|
||||
})
|
||||
payload: Json<NewPostData>,
|
||||
rockets: PlumeRocket,
|
||||
) -> Api<PostData> {
|
||||
let conn = &*rockets.conn;
|
||||
let search = &rockets.searcher;
|
||||
let worker = &rockets.worker;
|
||||
|
||||
let author = User::get(conn, auth.0.user_id)?;
|
||||
|
||||
let slug = &payload.title.clone().to_kebab_case();
|
||||
let date = payload.creation_date.clone().and_then(|d| {
|
||||
NaiveDateTime::parse_from_str(format!("{} 00:00:00", d).as_ref(), "%Y-%m-%d %H:%M:%S").ok()
|
||||
});
|
||||
|
||||
let domain = &Instance::get_local(conn)?.public_domain;
|
||||
let (content, mentions, hashtags) = md_to_html(
|
||||
&payload.source,
|
||||
domain,
|
||||
false,
|
||||
Some(Media::get_media_processor(conn, vec![&author])),
|
||||
);
|
||||
|
||||
let blog = payload.blog_id.or_else(|| {
|
||||
let blogs = Blog::find_for_author(conn, &author).ok()?;
|
||||
if blogs.len() == 1 {
|
||||
Some(blogs[0].id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
|
||||
if Post::find_by_slug(conn, slug, blog).is_ok() {
|
||||
return Err(Error::InvalidValue.into());
|
||||
}
|
||||
|
||||
let post = Post::insert(
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blog,
|
||||
slug: slug.to_string(),
|
||||
title: payload.title.clone(),
|
||||
content: SafeString::new(content.as_ref()),
|
||||
published: payload.published.unwrap_or(true),
|
||||
license: payload.license.clone().unwrap_or_else(|| {
|
||||
Instance::get_local(conn)
|
||||
.map(|i| i.default_license)
|
||||
.unwrap_or_else(|_| String::from("CC-BY-SA"))
|
||||
}),
|
||||
creation_date: date,
|
||||
ap_url: String::new(),
|
||||
subtitle: payload.subtitle.clone().unwrap_or_default(),
|
||||
source: payload.source.clone(),
|
||||
cover_id: payload.cover_id,
|
||||
},
|
||||
search,
|
||||
)?;
|
||||
|
||||
PostAuthor::insert(
|
||||
conn,
|
||||
NewPostAuthor {
|
||||
author_id: author.id,
|
||||
post_id: post.id,
|
||||
},
|
||||
)?;
|
||||
|
||||
if let Some(ref tags) = payload.tags {
|
||||
for tag in tags {
|
||||
Tag::insert(
|
||||
conn,
|
||||
NewTag {
|
||||
tag: tag.to_string(),
|
||||
is_hashtag: false,
|
||||
post_id: post.id,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
}
|
||||
for hashtag in hashtags {
|
||||
Tag::insert(
|
||||
conn,
|
||||
NewTag {
|
||||
tag: hashtag.to_camel_case(),
|
||||
is_hashtag: true,
|
||||
post_id: post.id,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
if post.published {
|
||||
for m in mentions.into_iter() {
|
||||
Mention::from_activity(
|
||||
&*conn,
|
||||
&Mention::build_activity(&rockets, &m)?,
|
||||
post.id,
|
||||
true,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
|
||||
let act = post.create_activity(&*conn)?;
|
||||
let dest = User::one_by_instance(&*conn)?;
|
||||
worker.execute(move || broadcast(&author, act, dest));
|
||||
}
|
||||
|
||||
Ok(Json(PostData {
|
||||
authors: post.get_authors(conn)?.into_iter().map(|a| a.fqn).collect(),
|
||||
creation_date: post.creation_date.format("%Y-%m-%d").to_string(),
|
||||
tags: Tag::for_post(conn, post.id)?
|
||||
.into_iter()
|
||||
.map(|t| t.tag)
|
||||
.collect(),
|
||||
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
subtitle: post.subtitle,
|
||||
content: post.content.to_string(),
|
||||
source: Some(post.source),
|
||||
blog_id: post.blog_id,
|
||||
published: post.published,
|
||||
license: post.license,
|
||||
cover_id: post.cover_id,
|
||||
}))
|
||||
}
|
||||
|
||||
#[delete("/posts/<id>")]
|
||||
pub fn delete(auth: Authorization<Write, Post>, rockets: PlumeRocket, id: i32) -> Api<()> {
|
||||
let author = User::get(&*rockets.conn, auth.0.user_id)?;
|
||||
if let Ok(post) = Post::get(&*rockets.conn, id) {
|
||||
if post.is_author(&*rockets.conn, author.id).unwrap_or(false) {
|
||||
post.delete(&*rockets.conn, &rockets.searcher)?;
|
||||
}
|
||||
}
|
||||
Ok(Json(()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue