2018-06-10 13:13:07 +02:00
use activitypub ::{
2018-05-19 00:04:30 +02:00
activity ::Create ,
2018-06-20 21:42:16 +02:00
link ,
2018-06-21 12:38:07 +02:00
object ::{ Note }
2018-05-19 00:04:30 +02:00
} ;
2018-09-27 23:06:40 +02:00
use chrono ::{ self , NaiveDateTime } ;
use diesel ::{ self , RunQueryDsl , QueryDsl , ExpressionMethods } ;
2018-05-10 17:36:32 +02:00
use serde_json ;
2018-05-09 22:35:02 +02:00
2018-06-23 18:36:11 +02:00
use plume_common ::activity_pub ::{
2018-06-26 16:21:58 +02:00
Id , IntoId , PUBLIC_VISIBILTY ,
2018-06-20 11:01:25 +02:00
inbox ::{ FromActivity , Notify }
2018-05-19 09:39:59 +02:00
} ;
2018-06-23 18:36:11 +02:00
use plume_common ::utils ;
2018-09-27 23:06:40 +02:00
use Connection ;
2018-06-23 18:36:11 +02:00
use instance ::Instance ;
use mentions ::Mention ;
use notifications ::* ;
use posts ::Post ;
use users ::User ;
2018-05-09 22:35:02 +02:00
use schema ::comments ;
2018-06-11 12:21:34 +02:00
use safe_string ::SafeString ;
2018-05-09 22:35:02 +02:00
2018-05-10 12:52:56 +02:00
#[ derive(Queryable, Identifiable, Serialize, Clone) ]
2018-05-09 22:35:02 +02:00
pub struct Comment {
pub id : i32 ,
2018-06-11 12:21:34 +02:00
pub content : SafeString ,
2018-05-09 22:35:02 +02:00
pub in_response_to_id : Option < i32 > ,
pub post_id : i32 ,
pub author_id : i32 ,
2018-09-27 23:06:40 +02:00
pub creation_date : NaiveDateTime ,
2018-05-09 22:35:02 +02:00
pub ap_url : Option < String > ,
pub sensitive : bool ,
pub spoiler_text : String
}
2018-06-21 12:28:42 +02:00
#[ derive(Insertable, Default) ]
2018-05-09 22:35:02 +02:00
#[ table_name = " comments " ]
pub struct NewComment {
2018-06-11 12:21:34 +02:00
pub content : SafeString ,
2018-05-09 22:35:02 +02:00
pub in_response_to_id : Option < i32 > ,
pub post_id : i32 ,
pub author_id : i32 ,
pub ap_url : Option < String > ,
pub sensitive : bool ,
pub spoiler_text : String
}
impl Comment {
2018-06-18 15:57:38 +02:00
insert! ( comments , NewComment ) ;
2018-06-18 15:44:23 +02:00
get! ( comments ) ;
2018-06-21 12:38:07 +02:00
list_by! ( comments , list_by_post , post_id as i32 ) ;
2018-06-18 15:37:49 +02:00
find_by! ( comments , find_by_ap_url , ap_url as String ) ;
2018-05-10 12:52:56 +02:00
2018-09-26 17:22:42 +02:00
pub fn get_author ( & self , conn : & Connection ) -> User {
2018-10-20 08:44:33 +02:00
User ::get ( conn , self . author_id ) . expect ( " Comment::get_author: author error " )
2018-05-10 11:44:57 +02:00
}
2018-05-10 17:36:32 +02:00
2018-09-26 17:22:42 +02:00
pub fn get_post ( & self , conn : & Connection ) -> Post {
2018-10-20 08:44:33 +02:00
Post ::get ( conn , self . post_id ) . expect ( " Comment::get_post: post error " )
2018-05-10 17:36:32 +02:00
}
2018-05-19 00:04:30 +02:00
2018-09-26 17:22:42 +02:00
pub fn count_local ( conn : & Connection ) -> usize {
2018-06-10 21:33:42 +02:00
use schema ::users ;
let local_authors = users ::table . filter ( users ::instance_id . eq ( Instance ::local_id ( conn ) ) ) . select ( users ::id ) ;
2018-09-27 23:06:40 +02:00
comments ::table . filter ( comments ::author_id . eq_any ( local_authors ) )
2018-06-10 21:33:42 +02:00
. load ::< Comment > ( conn )
2018-10-20 08:44:33 +02:00
. expect ( " Comment::count_local: loading error " )
. len ( ) // TODO count in database?
2018-06-10 21:33:42 +02:00
}
2018-06-18 18:34:29 +02:00
2018-09-26 17:22:42 +02:00
pub fn to_json ( & self , conn : & Connection , others : & Vec < Comment > ) -> serde_json ::Value {
2018-10-20 08:44:33 +02:00
let mut json = serde_json ::to_value ( self ) . expect ( " Comment::to_json: serialization error " ) ;
2018-06-18 18:34:29 +02:00
json [ " author " ] = self . get_author ( conn ) . to_json ( conn ) ;
2018-06-21 15:05:35 +02:00
let mentions = Mention ::list_for_comment ( conn , self . id ) . into_iter ( )
. map ( | m | m . get_mentioned ( conn ) . map ( | u | u . get_fqn ( conn ) ) . unwrap_or ( String ::new ( ) ) )
. collect ::< Vec < String > > ( ) ;
2018-10-20 08:44:33 +02:00
json [ " mentions " ] = serde_json ::to_value ( mentions ) . expect ( " Comment::to_json: mention error " ) ;
2018-07-25 18:18:41 +02:00
json [ " responses " ] = json! ( others . into_iter ( )
. filter ( | c | c . in_response_to_id . map ( | id | id = = self . id ) . unwrap_or ( false ) )
. map ( | c | c . to_json ( conn , others ) )
. collect ::< Vec < _ > > ( ) ) ;
2018-06-18 18:34:29 +02:00
json
}
2018-06-20 11:01:25 +02:00
2018-09-26 17:22:42 +02:00
pub fn update_ap_url ( & self , conn : & Connection ) -> Comment {
2018-09-09 17:08:53 +02:00
if self . ap_url . is_none ( ) {
diesel ::update ( self )
. set ( comments ::ap_url . eq ( self . compute_id ( conn ) ) )
2018-09-27 23:06:40 +02:00
. execute ( conn )
2018-10-20 08:44:33 +02:00
. expect ( " Comment::update_ap_url: update error " ) ;
Comment ::get ( conn , self . id ) . expect ( " Comment::update_ap_url: get error " )
2018-09-09 17:08:53 +02:00
} else {
self . clone ( )
}
}
2018-09-26 17:22:42 +02:00
pub fn compute_id ( & self , conn : & Connection ) -> String {
2018-09-09 17:22:58 +02:00
format! ( " {} comment/ {} " , self . get_post ( conn ) . ap_url , self . id )
2018-09-09 17:08:53 +02:00
}
2018-09-26 17:22:42 +02:00
pub fn into_activity ( & self , conn : & Connection ) -> Note {
2018-09-09 17:08:53 +02:00
let ( html , mentions ) = utils ::md_to_html ( self . content . get ( ) . as_ref ( ) ) ;
2018-10-20 08:44:33 +02:00
let author = User ::get ( conn , self . author_id ) . expect ( " Comment::into_activity: author error " ) ;
2018-09-09 17:08:53 +02:00
let mut note = Note ::default ( ) ;
let to = vec! [ Id ::new ( PUBLIC_VISIBILTY . to_string ( ) ) ] ;
2018-10-20 08:44:33 +02:00
note . object_props . set_id_string ( self . ap_url . clone ( ) . unwrap_or ( String ::new ( ) ) ) . expect ( " Comment::into_activity: id error " ) ;
note . object_props . set_summary_string ( self . spoiler_text . clone ( ) ) . expect ( " Comment::into_activity: summary error " ) ;
note . object_props . set_content_string ( html ) . expect ( " Comment::into_activity: content error " ) ;
note . object_props . set_in_reply_to_link ( Id ::new ( self . in_response_to_id . map_or_else ( | | Post ::get ( conn , self . post_id ) . expect ( " Comment::into_activity: post error " ) . ap_url , | id | {
let comm = Comment ::get ( conn , id ) . expect ( " Comment::into_activity: comment error " ) ;
2018-09-09 17:08:53 +02:00
comm . ap_url . clone ( ) . unwrap_or ( comm . compute_id ( conn ) )
2018-10-20 08:44:33 +02:00
} ) ) ) . expect ( " Comment::into_activity: in_reply_to error " ) ;
note . object_props . set_published_string ( chrono ::Utc ::now ( ) . to_rfc3339 ( ) ) . expect ( " Comment::into_activity: published error " ) ;
note . object_props . set_attributed_to_link ( author . clone ( ) . into_id ( ) ) . expect ( " Comment::into_activity: attributed_to error " ) ;
note . object_props . set_to_link_vec ( to . clone ( ) ) . expect ( " Comment::into_activity: to error " ) ;
2018-09-09 17:08:53 +02:00
note . object_props . set_tag_link_vec ( mentions . into_iter ( ) . map ( | m | Mention ::build_activity ( conn , m ) ) . collect ::< Vec < link ::Mention > > ( ) )
2018-10-20 08:44:33 +02:00
. expect ( " Comment::into_activity: tag error " ) ;
2018-09-09 17:08:53 +02:00
note
}
2018-09-26 17:22:42 +02:00
pub fn create_activity ( & self , conn : & Connection ) -> Create {
2018-10-20 08:44:33 +02:00
let author = User ::get ( conn , self . author_id ) . expect ( " Comment::create_activity: author error " ) ;
2018-09-09 17:08:53 +02:00
let note = self . into_activity ( conn ) ;
let mut act = Create ::default ( ) ;
2018-10-20 08:44:33 +02:00
act . create_props . set_actor_link ( author . into_id ( ) ) . expect ( " Comment::create_activity: actor error " ) ;
act . create_props . set_object_object ( note . clone ( ) ) . expect ( " Comment::create_activity: object error " ) ;
act . object_props . set_id_string ( format! ( " {} /activity " , self . ap_url . clone ( ) . expect ( " Comment::create_activity: ap_url error " ) ) ) . expect ( " Comment::create_activity: id error " ) ;
act . object_props . set_to_link_vec ( note . object_props . to_link_vec ::< Id > ( ) . expect ( " Comment::create_activity: id error " ) ) . expect ( " Comment::create_activity: to error " ) ;
act . object_props . set_cc_link_vec ::< Id > ( vec! [ ] ) . expect ( " Comment::create_activity: cc error " ) ;
2018-09-09 17:08:53 +02:00
act
2018-06-20 11:01:25 +02:00
}
2018-05-10 17:36:32 +02:00
}
2018-09-27 23:06:40 +02:00
impl FromActivity < Note , Connection > for Comment {
2018-09-26 17:22:42 +02:00
fn from_activity ( conn : & Connection , note : Note , actor : Id ) -> Comment {
2018-10-20 08:44:33 +02:00
let previous_url = note . object_props . in_reply_to . clone ( ) . expect ( " Comment::from_activity: not an answer error " ) . as_str ( ) . expect ( " Comment::from_activity: in_reply_to parsing error " ) . to_string ( ) ;
2018-06-12 21:10:08 +02:00
let previous_comment = Comment ::find_by_ap_url ( conn , previous_url . clone ( ) ) ;
2018-06-20 21:42:16 +02:00
2018-06-17 21:37:10 +02:00
let comm = Comment ::insert ( conn , NewComment {
2018-10-20 08:44:33 +02:00
content : SafeString ::new ( & note . object_props . content_string ( ) . expect ( " Comment::from_activity: content deserialization error " ) ) ,
2018-06-12 21:10:08 +02:00
spoiler_text : note . object_props . summary_string ( ) . unwrap_or ( String ::from ( " " ) ) ,
ap_url : note . object_props . id_string ( ) . ok ( ) ,
in_response_to_id : previous_comment . clone ( ) . map ( | c | c . id ) ,
post_id : previous_comment
. map ( | c | c . post_id )
2018-10-20 08:44:33 +02:00
. unwrap_or_else ( | | Post ::find_by_ap_url ( conn , previous_url ) . expect ( " Comment::from_activity: post error " ) . id ) ,
author_id : User ::from_url ( conn , actor . clone ( ) . into ( ) ) . expect ( " Comment::from_activity: author error " ) . id ,
2018-06-12 21:10:08 +02:00
sensitive : false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate
2018-06-17 21:37:10 +02:00
} ) ;
2018-06-21 15:05:35 +02:00
2018-09-08 00:29:50 +02:00
// save mentions
2018-06-21 15:05:35 +02:00
if let Some ( serde_json ::Value ::Array ( tags ) ) = note . object_props . tag . clone ( ) {
for tag in tags . into_iter ( ) {
serde_json ::from_value ::< link ::Mention > ( tag )
2018-09-08 13:52:27 +02:00
. map ( | m | {
2018-10-20 08:44:33 +02:00
let author = & Post ::get ( conn , comm . post_id ) . expect ( " Comment::from_activity: error " ) . get_authors ( conn ) [ 0 ] ;
let not_author = m . link_props . href_string ( ) . expect ( " Comment::from_activity: no href error " ) ! = author . ap_url . clone ( ) ;
2018-09-08 13:52:27 +02:00
Mention ::from_activity ( conn , m , comm . id , false , not_author )
} ) . ok ( ) ;
2018-06-21 15:05:35 +02:00
}
}
2018-06-20 23:51:47 +02:00
comm . notify ( conn ) ;
2018-06-17 21:37:10 +02:00
comm
}
}
2018-09-27 23:06:40 +02:00
impl Notify < Connection > for Comment {
2018-09-26 17:22:42 +02:00
fn notify ( & self , conn : & Connection ) {
2018-06-20 23:51:47 +02:00
for author in self . get_post ( conn ) . get_authors ( conn ) {
Notification ::insert ( conn , NewNotification {
2018-07-26 15:46:10 +02:00
kind : notification_kind ::COMMENT . to_string ( ) ,
object_id : self . id ,
2018-06-20 23:51:47 +02:00
user_id : author . id
} ) ;
}
2018-06-12 21:10:08 +02:00
}
}