lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

social_events.rs (7041B)


      1 #![cfg(feature = "json")]
      2 
      3 use radroots_event::{
      4     envelope::kind::{
      5         KIND_ARTICLE, KIND_CLASSIFIED_LISTING, KIND_FARM, KIND_FARM_CRDT_CHANGE,
      6         KIND_GROUP_METADATA, KIND_HTTP_AUTH, KIND_POST, KIND_PUBLIC_FILE_METADATA, KIND_RELAY_AUTH,
      7         KIND_REPORT, is_home_feed_candidate_kind, is_market_candidate_kind,
      8         is_private_farm_ops_kind, is_public_social_kind,
      9     },
     10     farm::crdt::FarmCrdtDocumentKind,
     11     farm::file::{FarmFileDimensions, FarmFileMetadata},
     12     farm::workspace::FarmWorkspaceRef,
     13     media::file_metadata::FileMetadata,
     14     social::SocialMediaDimensions,
     15     social::group::{GroupEditableMetadata, GroupMetadata},
     16 };
     17 use radroots_event_codec::{
     18     decode::EventParseError, decode::article::article_from_event, decode::farm::farm_from_event,
     19     decode::farm_file::farm_file_metadata_from_event,
     20     decode::file_metadata::file_metadata_from_event, decode::group::group_metadata_from_event,
     21     decode::operational_listing::operational_listing_from_event,
     22     encode::farm_file::to_wire_parts as farm_file_to_wire_parts,
     23     encode::file_metadata::to_wire_parts as public_file_to_wire_parts,
     24     encode::group::group_metadata_to_wire_parts,
     25 };
     26 
     27 const SHA256: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
     28 const OTHER_SHA256: &str = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789";
     29 const D_TAG: &str = "AAAAAAAAAAAAAAAAAAAAAA";
     30 
     31 #[test]
     32 fn social_events_keep_public_and_private_file_metadata_apis_separate() {
     33     let public = public_file_to_wire_parts(&public_file_metadata()).unwrap();
     34     let decoded_public =
     35         file_metadata_from_event(public.kind, &public.tags, &public.content).unwrap();
     36     assert_eq!(decoded_public.url, "https://media.example.test/public.jpg");
     37     assert!(matches!(
     38         farm_file_metadata_from_event(public.kind, &public.tags, &public.content),
     39         Err(EventParseError::MissingTag("d"))
     40     ));
     41 
     42     let private = farm_file_to_wire_parts(&private_farm_file_metadata()).unwrap();
     43     let decoded_private =
     44         farm_file_metadata_from_event(private.kind, &private.tags, &private.content).unwrap();
     45     assert_eq!(decoded_private.owner_document_id, D_TAG);
     46     assert!(matches!(
     47         file_metadata_from_event(private.kind, &private.tags, &private.content),
     48         Err(EventParseError::InvalidTag("radroots:owner_document"))
     49     ));
     50 }
     51 
     52 #[test]
     53 fn social_events_reject_private_farm_ops_semantics_in_public_codecs() {
     54     let private_content = serde_json::json!({
     55         "workspace": {
     56             "pubkey": "workspace_pubkey",
     57             "d_tag": D_TAG
     58         },
     59         "farm_group_id": "field-group",
     60         "document_id": D_TAG,
     61         "document_kind": "FarmTask",
     62         "encoded_change": "abc-DEF_012"
     63     })
     64     .to_string();
     65     let farm_tags = vec![vec!["d".to_string(), D_TAG.to_string()]];
     66 
     67     assert!(matches!(
     68         farm_from_event(KIND_FARM, &farm_tags, &private_content),
     69         Err(EventParseError::InvalidJson("content"))
     70     ));
     71     assert!(matches!(
     72         article_from_event(KIND_FARM_CRDT_CHANGE, &[], "farm task"),
     73         Err(EventParseError::InvalidKind {
     74             expected: "30023",
     75             got: KIND_FARM_CRDT_CHANGE
     76         })
     77     ));
     78     assert!(matches!(
     79         operational_listing_from_event(KIND_FARM_CRDT_CHANGE, &[], "farm task"),
     80         Err(EventParseError::InvalidKind {
     81             expected: "30402",
     82             got: KIND_FARM_CRDT_CHANGE
     83         })
     84     ));
     85     assert!(is_public_social_kind(KIND_POST));
     86     assert!(is_public_social_kind(KIND_ARTICLE));
     87     assert!(is_public_social_kind(KIND_PUBLIC_FILE_METADATA));
     88     assert!(!is_public_social_kind(KIND_FARM_CRDT_CHANGE));
     89     assert!(!is_public_social_kind(KIND_CLASSIFIED_LISTING));
     90     assert!(is_home_feed_candidate_kind(KIND_CLASSIFIED_LISTING));
     91     assert!(is_home_feed_candidate_kind(KIND_FARM));
     92     assert!(is_home_feed_candidate_kind(KIND_PUBLIC_FILE_METADATA));
     93     assert!(!is_home_feed_candidate_kind(30403));
     94     assert!(!is_home_feed_candidate_kind(KIND_REPORT));
     95     assert!(!is_home_feed_candidate_kind(KIND_FARM_CRDT_CHANGE));
     96     assert!(!is_home_feed_candidate_kind(KIND_RELAY_AUTH));
     97     assert!(!is_home_feed_candidate_kind(KIND_HTTP_AUTH));
     98     assert!(is_market_candidate_kind(KIND_CLASSIFIED_LISTING));
     99     assert!(!is_market_candidate_kind(30403));
    100 }
    101 
    102 #[test]
    103 fn social_events_keep_nip29_groups_out_of_public_social_classification() {
    104     let group = GroupMetadata {
    105         d_tag: "field-group".to_string(),
    106         metadata: GroupEditableMetadata {
    107             name: Some("Field Group".to_string()),
    108             about: Some("Localhost field coordination".to_string()),
    109             picture: None,
    110             is_private: false,
    111             is_restricted: false,
    112             is_closed: false,
    113             is_hidden: false,
    114             supported_kinds: Some(vec![KIND_FARM_CRDT_CHANGE]),
    115         },
    116     };
    117     let parts = group_metadata_to_wire_parts(&group).unwrap();
    118     assert_eq!(parts.kind, KIND_GROUP_METADATA);
    119     assert!(!is_public_social_kind(KIND_GROUP_METADATA));
    120     assert!(!is_home_feed_candidate_kind(KIND_GROUP_METADATA));
    121     assert!(is_private_farm_ops_kind(KIND_GROUP_METADATA));
    122     assert_eq!(
    123         group_metadata_from_event(parts.kind, &parts.tags, &parts.content)
    124             .unwrap()
    125             .metadata
    126             .supported_kinds,
    127         Some(vec![KIND_FARM_CRDT_CHANGE])
    128     );
    129 }
    130 
    131 fn public_file_metadata() -> FileMetadata {
    132     FileMetadata {
    133         url: "https://media.example.test/public.jpg".to_string(),
    134         mime_type: "image/jpeg".to_string(),
    135         sha256: SHA256.to_string(),
    136         original_sha256: Some(OTHER_SHA256.to_string()),
    137         size: Some(4096),
    138         dimensions: Some(SocialMediaDimensions {
    139             width: 1200,
    140             height: 800,
    141         }),
    142         blurhash: None,
    143         thumbnails: None,
    144         summary: Some("Public field photo".to_string()),
    145         alt: Some("Rows after harvest".to_string()),
    146         fallback: None,
    147         magnet: None,
    148         content_hashes: None,
    149         services: None,
    150         content: Some("caption".to_string()),
    151     }
    152 }
    153 
    154 fn private_farm_file_metadata() -> FarmFileMetadata {
    155     FarmFileMetadata {
    156         d_tag: D_TAG.to_string(),
    157         workspace: FarmWorkspaceRef {
    158             pubkey: "workspace_pubkey".to_string(),
    159             d_tag: D_TAG.to_string(),
    160         },
    161         farm_group_id: "field-group".to_string(),
    162         owner_document_id: D_TAG.to_string(),
    163         owner_document_kind: FarmCrdtDocumentKind::FarmTask,
    164         caption: Some("private caption".to_string()),
    165         url: "https://media.example.test/private.jpg".to_string(),
    166         mime_type: "image/jpeg".to_string(),
    167         sha256: SHA256.to_string(),
    168         original_sha256: Some(OTHER_SHA256.to_string()),
    169         size_bytes: Some(4096),
    170         dimensions: Some(FarmFileDimensions { w: 1200, h: 800 }),
    171         blurhash: None,
    172         thumb: None,
    173         image: None,
    174         alt: Some("Private farm task attachment".to_string()),
    175         fallbacks: Vec::new(),
    176     }
    177 }