License federation (#343)
* Federate license * Make it possible to use no license
This commit is contained in:
+30
-19
@@ -1,4 +1,5 @@
|
||||
use activitypub::{
|
||||
CustomObject,
|
||||
activity::{Create, Delete, Update},
|
||||
link,
|
||||
object::{Article, Image, Tombstone},
|
||||
@@ -18,7 +19,7 @@ use plume_api::posts::PostEndpoint;
|
||||
use plume_common::{
|
||||
activity_pub::{
|
||||
inbox::{Deletable, FromActivity},
|
||||
Hashtag, Id, IntoId, Source, PUBLIC_VISIBILTY,
|
||||
Hashtag, Id, IntoId, Licensed, Source, PUBLIC_VISIBILTY,
|
||||
},
|
||||
utils::md_to_html,
|
||||
};
|
||||
@@ -32,6 +33,8 @@ use tags::Tag;
|
||||
use users::User;
|
||||
use {ap_url, Connection, BASE_URL};
|
||||
|
||||
pub type LicensedArticle = CustomObject<Licensed, Article>;
|
||||
|
||||
#[derive(Queryable, Identifiable, Serialize, Clone, AsChangeset)]
|
||||
#[changeset_options(treat_none_as_null = "true")]
|
||||
pub struct Post {
|
||||
@@ -418,7 +421,7 @@ impl Post {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_activity(&self, conn: &Connection) -> Article {
|
||||
pub fn to_activity(&self, conn: &Connection) -> LicensedArticle {
|
||||
let mut to = self.get_receivers_urls(conn);
|
||||
to.push(PUBLIC_VISIBILTY.to_string());
|
||||
|
||||
@@ -516,7 +519,9 @@ impl Post {
|
||||
.object_props
|
||||
.set_cc_link_vec::<Id>(vec![])
|
||||
.expect("Post::to_activity: cc error");
|
||||
article
|
||||
let mut license = Licensed::default();
|
||||
license.set_license_string(self.license.clone()).expect("Post::to_activity: license error");
|
||||
LicensedArticle::new(article, license)
|
||||
}
|
||||
|
||||
pub fn create_activity(&self, conn: &Connection) -> Create {
|
||||
@@ -527,7 +532,7 @@ impl Post {
|
||||
.expect("Post::create_activity: id error");
|
||||
act.object_props
|
||||
.set_to_link_vec::<Id>(
|
||||
article
|
||||
article.object
|
||||
.object_props
|
||||
.to_link_vec()
|
||||
.expect("Post::create_activity: Couldn't copy 'to'"),
|
||||
@@ -535,7 +540,7 @@ impl Post {
|
||||
.expect("Post::create_activity: to error");
|
||||
act.object_props
|
||||
.set_cc_link_vec::<Id>(
|
||||
article
|
||||
article.object
|
||||
.object_props
|
||||
.cc_link_vec()
|
||||
.expect("Post::create_activity: Couldn't copy 'cc'"),
|
||||
@@ -558,7 +563,7 @@ impl Post {
|
||||
.expect("Post::update_activity: id error");
|
||||
act.object_props
|
||||
.set_to_link_vec::<Id>(
|
||||
article
|
||||
article.object
|
||||
.object_props
|
||||
.to_link_vec()
|
||||
.expect("Post::update_activity: Couldn't copy 'to'"),
|
||||
@@ -566,7 +571,7 @@ impl Post {
|
||||
.expect("Post::update_activity: to error");
|
||||
act.object_props
|
||||
.set_cc_link_vec::<Id>(
|
||||
article
|
||||
article.object
|
||||
.object_props
|
||||
.cc_link_vec()
|
||||
.expect("Post::update_activity: Couldn't copy 'cc'"),
|
||||
@@ -577,44 +582,48 @@ impl Post {
|
||||
.expect("Post::update_activity: actor error");
|
||||
act.update_props
|
||||
.set_object_object(article)
|
||||
.expect("Article::update_activity: object error");
|
||||
.expect("Post::update_activity: object error");
|
||||
act
|
||||
}
|
||||
|
||||
pub fn handle_update(conn: &Connection, updated: &Article, searcher: &Searcher) {
|
||||
let id = updated
|
||||
pub fn handle_update(conn: &Connection, updated: &LicensedArticle, searcher: &Searcher) {
|
||||
let id = updated.object
|
||||
.object_props
|
||||
.id_string()
|
||||
.expect("Post::handle_update: id error");
|
||||
let mut post = Post::find_by_ap_url(conn, &id).expect("Post::handle_update: finding error");
|
||||
|
||||
if let Ok(title) = updated.object_props.name_string() {
|
||||
if let Ok(title) = updated.object.object_props.name_string() {
|
||||
post.slug = title.to_kebab_case();
|
||||
post.title = title;
|
||||
}
|
||||
|
||||
if let Ok(content) = updated.object_props.content_string() {
|
||||
if let Ok(content) = updated.object.object_props.content_string() {
|
||||
post.content = SafeString::new(&content);
|
||||
}
|
||||
|
||||
if let Ok(subtitle) = updated.object_props.summary_string() {
|
||||
if let Ok(subtitle) = updated.object.object_props.summary_string() {
|
||||
post.subtitle = subtitle;
|
||||
}
|
||||
|
||||
if let Ok(ap_url) = updated.object_props.url_string() {
|
||||
if let Ok(ap_url) = updated.object.object_props.url_string() {
|
||||
post.ap_url = ap_url;
|
||||
}
|
||||
|
||||
if let Ok(source) = updated.ap_object_props.source_object::<Source>() {
|
||||
if let Ok(source) = updated.object.ap_object_props.source_object::<Source>() {
|
||||
post.source = source.content;
|
||||
}
|
||||
|
||||
if let Ok(license) = updated.custom_props.license_string() {
|
||||
post.license = license;
|
||||
}
|
||||
|
||||
let mut txt_hashtags = md_to_html(&post.source)
|
||||
.2
|
||||
.into_iter()
|
||||
.map(|s| s.to_camel_case())
|
||||
.collect::<HashSet<_>>();
|
||||
if let Some(serde_json::Value::Array(mention_tags)) = updated.object_props.tag.clone() {
|
||||
if let Some(serde_json::Value::Array(mention_tags)) = updated.object.object_props.tag.clone() {
|
||||
let mut mentions = vec![];
|
||||
let mut tags = vec![];
|
||||
let mut hashtags = vec![];
|
||||
@@ -782,8 +791,10 @@ impl Post {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromActivity<Article, (&'a Connection, &'a Searcher)> for Post {
|
||||
fn from_activity((conn, searcher): &(&'a Connection, &'a Searcher), article: Article, _actor: Id) -> Post {
|
||||
impl<'a> FromActivity<LicensedArticle, (&'a Connection, &'a Searcher)> for Post {
|
||||
fn from_activity((conn, searcher): &(&'a Connection, &'a Searcher), article: LicensedArticle, _actor: Id) -> Post {
|
||||
let license = article.custom_props.license_string().unwrap_or_default();
|
||||
let article = article.object;
|
||||
if let Some(post) = Post::find_by_ap_url(
|
||||
conn,
|
||||
&article.object_props.id_string().unwrap_or_default(),
|
||||
@@ -829,7 +840,7 @@ impl<'a> FromActivity<Article, (&'a Connection, &'a Searcher)> for Post {
|
||||
.expect("Post::from_activity: content error"),
|
||||
),
|
||||
published: true,
|
||||
license: String::from("CC-BY-SA"), // TODO
|
||||
license: license,
|
||||
// FIXME: This is wrong: with this logic, we may use the display URL as the AP ID. We need two different fields
|
||||
ap_url: article.object_props.url_string().unwrap_or_else(|_|
|
||||
article
|
||||
|
||||
Reference in New Issue
Block a user