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