aboutsummaryrefslogblamecommitdiffstats
path: root/src/stream/activity.rs
blob: 38c7215323f6a03f244767bcced6626e85c8ce82 (plain) (tree)
1
2
3
4
5
6
7
8
9
   
                                                                       






                                                                      
                        
                              
               


                       

               

                                        
                                 
                       



                                        
                                 
                           


        
                                        
                     
            
         
             


                                        
                                 
                       


             


                 



                                                      
                     
                           

                                   
 





                            









                                                    
                   
                                



                        




                          
                                         
                               

 
               
                                   










                                                                       

     
























                                                                                              

                                  



































                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
                                        


















                                                                  
                                                                  
 

                                                           




                                                                                                                     
                                            






                                                                       



                                                                    

     
/**
 * Representation of an activity, as received from the zot api streams.
 *
 * SPDX-FileCopyrightText: 2023 Eilertsens Kodeknekkeri
 * SPDX-FileCopyrightText: 2023 Harald Eilertsen <haraldei@anduin.net>
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

use super::actor::Actor;
use super::datetime::DateTime;
use super::Tag;
use super::verb::Verb;

use serde::Deserialize;
use url::Url;
use uuid::Uuid;

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all="snake_case")]
pub enum ActivityType {
    Activity,
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all="snake_case")]
pub enum ActivityEncoding {
    Zot,
}

#[derive(Debug, Deserialize, PartialEq)]
pub enum ObjectType {
    Article,
    Note,
    Question,
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all="snake_case")]
pub enum ActivityFlag {
    Direct,
    Notshown,
    Private,
    ThreadParent,
}

/**
 * Represents an item as returned by the stream API's.
 */
#[derive(Debug, Deserialize, PartialEq)]
pub struct Activity {
    #[serde(rename="type")]
    pub item_type: ActivityType,
    pub encoding: ActivityEncoding,

    pub uuid: Uuid,
    pub message_id: Url,
    pub message_top: Url,
    pub message_parent: Url,
    pub permalink: Url,

    /*
     * Date and time fields for when the item was
     * created, last edited or commented, as well as
     * when/if it expires.
     */
    pub created: DateTime,
    pub edited: DateTime,
    pub expires: DateTime,
    pub commented: DateTime,

    pub verb: Verb,
    pub object_type: ObjectType,

    pub title: String,
    pub summary: String,
    pub body: String,

    pub owner: Actor,
    pub author: Actor,

    pub signature: String,
    pub flags: Option<Vec<ActivityFlag>>,
    pub tags: Option<Vec<Tag>>,
}

impl Activity {
    pub fn is_post(&self) -> bool {
        self.verb == Verb::Create
            && self.object_type == ObjectType::Note
            && self.has_flag(ActivityFlag::ThreadParent)
    }

    pub fn has_flag(&self, flag: ActivityFlag) -> bool {
        self.flags
            .as_ref()
            .map_or(
                false,
                |flags| flags.iter().find( |f| *f == &flag ).is_some())
    }
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn parse_stream_item_from_json() {
        let json = r#"
          {
            "type": "activity",
            "encoding": "zot",
            "uuid": "2c102ec3-676b-4d84-b2b4-9141467a254f",
            "message_id": "https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f",
            "message_top": "https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f",
            "message_parent": "https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f",
            "created": "2023-12-12 17:00:42",
            "edited": "2023-12-12 17:00:42",
            "expires": "0000-00-00 00:00:00",
            "commented": "2023-12-19 09:01:15",
            "mimetype": "text/bbcode",
            "title": "The item title",
            "summary": "The summary of the post",
            "body": "The body of the post",
            "app": "",
            "verb": "Create",
            "object_type": "Note",
            "target_type": "",
            "permalink": "https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f",
            "location": "",
            "longlat": "",
            "signature": "sha256.ADzsjr5uFUpcwVkUT9liHimr1n2TJmGpTtm0SGSody_6vTbfYhHK3OJJhGknImHYwMradSwVcA9dNAAXzhSoAY5hCmSbnThLun30HVIA3E0ZSDBbt1RyKNomqBCvCBmyyFKhxYoPk34UQisCH6gIQ3eZL-m5PxE9t2oMO_CnpPvLWESoezY3CAZaEIIRj3KKozwC8DxibQmsnCeA32C-2Ejzv8PdZCX1skbIdc5d8Jj_ykyUTqc2DZKMSl9osua3esEMwYZLbxlRQruDfgyjJExdvz57zpeqf1WKzqdIZ5kmguZxch6NLVMiRitooT-sIZOvo9JzgP1ogBQW34W-kG1hHzuGJQkDZKOAA1rLD8qrfwugbbg9wDpjtZY-WHv265KMMsFhctIIupNPVVkuSgs0jMKQmjJTeDE0IxBKx2dCsxiqMWlJll_LSu7b6BtTa7jcuhfMPaKqdMOCRRnGNwehj6qeOXPV7zEZsc4Mzym6N_jRTV556OmUwaCHouEFqTG1ARE5EquYTMk2wXIteC5lT2d0WpEGTnlL1WpqWLx9DCp76Z2JsxMBxjZicKvJSm1gX3ng2ENG2cvECww0IF_zPy2DmHcWOqm795-11uLBNt_60bpP9-sgjrNSj0q6MHgAsFGnpW42M4sFe-6gb-W-HjyHwY2B2yjErYC9KDo",
            "route": "",
            "owner": {
              "name": "Benjamin Franklin",
              "address": "ben@example.com",
              "url": "https://example.com/channel/ben",
              "network": "zot6",
              "photo": {
                "mimetype": "image/jpeg",
                "src": "https://example.com/photo/profile/m/2"
              },
              "id": "rUpgk2qbvnWLoKIXOlZlwlqI5vk8C4NgudFNjbcmnOBjFSXU34TObkZEClaPSfKnpFZpg87tANtko7WGs7QRvA",
              "id_sig": "sha256.ZD8uwYmUEG_d02Y...",
              "key": "-----BEGIN PUBLIC KEY-----\n....\n-----END PUBLIC KEY-----\n"
            },
            "author": {
              "name": "Benjamin Franklin",
              "address": "ben@example.com",
              "url": "https://example.com/channel/ben",
              "network": "zot6",
              "photo": {
                "mimetype": "image/jpeg",
                "src": "https://example.com/photo/profile/m/2"
              },
              "id": "rUpgk2qbvnWLoKIXOlZlwlqI5vk8C4NgudFNjbcmnOBjFSXU34TObkZEClaPSfKnpFZpg87tANtko7WGs7QRvA",
              "id_sig": "sha256.ZD8uwYmUEG_d02Y...",
              "key": "-----BEGIN PUBLIC KEY-----\n....\n-----END PUBLIC KEY-----\n"
            },
            "flags": [
              "thread_parent"
            ],
            "public_scope": "",
            "comment_scope": "contacts",
            "tags": [
              {
                "tag": "a-tag",
                "url": "https://example.com/search?tag=a-tag",
                "type": "hashtag"
              },
              {
                "tag": "fediverse",
                "url": "https://example.com/search?tag=fediverse",
                "type": "hashtag"
              },
              {
                "tag": "hubzilla",
                "url": "https://example.com/search?tag=hubzilla",
                "type": "hashtag"
              }
            ]
          }"#;

        let item: Activity = serde_json::from_str(&json).unwrap();

        assert_eq!(ActivityType::Activity, item.item_type);
        assert_eq!(ActivityEncoding::Zot, item.encoding);
        assert_eq!("2c102ec3-676b-4d84-b2b4-9141467a254f", item.uuid.to_string());
        assert_eq!("https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f", item.message_id.to_string());
        assert_eq!("https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f", item.message_top.to_string());
        assert_eq!("https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f", item.message_parent.to_string());
        assert_eq!("https://example.com/item/2c102ec3-676b-4d84-b2b4-9141467a254f", item.permalink.to_string());
        assert_eq!(Verb::Create, item.verb);
        assert_eq!("The item title", &item.title);
        assert_eq!("The summary of the post", &item.summary);
        assert_eq!("The body of the post", &item.body);
        assert_eq!("2023-12-12 17:00:42", &item.created.to_string());
        assert_eq!("2023-12-12 17:00:42", &item.edited.to_string());
        assert_eq!("0000-00-00 00:00:00", &item.expires.to_string());
        assert_eq!("2023-12-19 09:01:15", &item.commented.to_string());
        assert_eq!(ObjectType::Note, item.object_type);

        assert_eq!(true, item.has_flag(ActivityFlag::ThreadParent));
        assert_eq!(true, item.is_post());
    }
}