Commit 2656c1d26d6b
tarball3 files changed+148-9
@@ -220,8 +220,10 @@ pub(super) async fn run_detached(
220220
from_pack,221221
shortcode,222222
to,223
+ usage,223224
} => {224
- let image = pack_image(&client, &from_pack, &shortcode).await?;225
+ let mut image = pack_image(&client, &from_pack, &shortcode).await?;226
+ apply_usage(&mut image, usage);225227
let image = rehost_image(&client, image, max_bytes).await?;226228
insert(&mutations, to, vec![(shortcode, image)], None, Vec::new()).await227229
}@@ -230,8 +232,12 @@ pub(super) async fn run_detached(
230232
event_id,231233
to,232234
shortcode,235
+ usage,233236
} => {234
- let image = sticker_image(&client, room_id, event_id).await?;237
+ let mut image = sticker_image(&client, room_id, event_id).await?;238
+ let body = sticker_body(&image, &shortcode);239
+ image.insert("body".to_owned(), body.into());240
+ apply_usage(&mut image, usage);235241
let image = rehost_image(&client, image, max_bytes).await?;236242
insert(&mutations, to, vec![(shortcode, image)], None, Vec::new()).await237243
}@@ -239,7 +245,19 @@ pub(super) async fn run_detached(
239245
from_pack,240246
to,241247
display_name,242
- } => clone_pack(&client, &mutations, max_bytes, &from_pack, to, display_name).await,248
+ usage,249
+ } => {250
+ clone_pack(251
+ &client,252
+ &mutations,253
+ max_bytes,254
+ &from_pack,255
+ to,256
+ display_name,257
+ usage,258
+ )259
+ .await260
+ }243261
_ => Err(Error::new(ErrorKind::Other, "pack command was misrouted")),244262
}245263
}@@ -251,6 +269,7 @@ async fn clone_pack(
251269
from_pack: &str,252270
to: ImagePackSource,253271
display_name: Option<String>,272
+ usage: Option<Vec<PackUsage>>,254273
) -> Result<CommandOutput, Error> {255274
let source = resolve_pack_id(client, from_pack)256275
.ok_or_else(|| Error::new(ErrorKind::Invalid, "no pack has that id"))?;@@ -265,7 +284,8 @@ async fn clone_pack(
265284
Some(JsonValue::Object(images)) => images266285
.iter()267286
.filter_map(|(shortcode, image)| {268
- let image = with_pack_usage(image.as_object()?.clone(), &meta);287
+ let mut image = with_pack_usage(image.as_object()?.clone(), &meta);288
+ apply_usage(&mut image, usage.clone());269289
Some((shortcode.clone(), image))270290
})271291
.collect(),@@ -340,7 +360,7 @@ async fn send_sticker(
340360
.and_then(mxc)341361
.ok_or_else(|| Error::new(ErrorKind::Invalid, "that image has no usable url"))?;342362
let content = json!({343
- "body": image.get("body").and_then(JsonValue::as_str).unwrap_or(shortcode),363
+ "body": sticker_body(&image, shortcode),344364
"url": url,345365
"info": image.get("info").cloned().unwrap_or_else(|| json!({})),346366
});@@ -487,12 +507,43 @@ async fn write_pack(
487507
}488508
489509
fn with_pack_usage(mut image: JsonObject, meta: &JsonObject) -> JsonObject {490
- if !image.contains_key("usage")491
- && let Some(usage) = meta.get("usage")492
- {493
- image.insert("usage".to_owned(), usage.clone());510
+ let usage = known_usage(image.get("usage"))511
+ .or_else(|| known_usage(meta.get("usage")))512
+ .unwrap_or_else(|| vec![PackUsage::Emoticon, PackUsage::Sticker]);513
+ image.insert("usage".to_owned(), usage_json(usage));514
+ image515
+}516
+517
+fn known_usage(value: Option<&JsonValue>) -> Option<Vec<PackUsage>> {518
+ let values = value?.as_array()?;519
+ let usage = [520
+ ("emoticon", PackUsage::Emoticon),521
+ ("sticker", PackUsage::Sticker),522
+ ]523
+ .into_iter()524
+ .filter_map(|(name, usage)| {525
+ values526
+ .iter()527
+ .any(|value| value.as_str() == Some(name))528
+ .then_some(usage)529
+ })530
+ .collect::<Vec<_>>();531
+ (!usage.is_empty()).then_some(usage)532
+}533
+534
+fn apply_usage(image: &mut JsonObject, usage: Option<Vec<PackUsage>>) {535
+ if let Some(usage) = usage {536
+ image.insert("usage".to_owned(), usage_json(usage));494537
}538
+}539
+540
+fn sticker_body(image: &JsonObject, shortcode: &str) -> String {495541
image542
+ .get("body")543
+ .and_then(JsonValue::as_str)544
+ .filter(|body| !body.trim().is_empty())545
+ .unwrap_or(shortcode)546
+ .to_owned()496547
}497548
498549
fn free_shortcode(images: &JsonObject, wanted: &str) -> String {@@ -573,6 +624,54 @@ fn object(value: JsonValue) -> JsonObject {
573624
}574625
}575626
627
+#[cfg(test)]628
+mod tests {629
+ use super::*;630
+631
+ #[test]632
+ fn pack_usage_inherits_known_values_then_defaults() {633
+ let pack = object(json!({ "usage": ["sticker", "unknown"] }));634
+ let inherited = with_pack_usage(object(json!({ "usage": [] })), &pack);635
+ assert_eq!(inherited.get("usage"), Some(&json!(["sticker"])));636
+637
+ let pack = object(json!({ "usage": ["emoticon"] }));638
+ let inherited = with_pack_usage(object(json!({ "usage": ["unknown"] })), &pack);639
+ assert_eq!(inherited.get("usage"), Some(&json!(["emoticon"])));640
+641
+ let pack = object(json!({ "usage": ["sticker"] }));642
+ let inherited = with_pack_usage(object(json!({ "usage": ["emoticon", "unknown"] })), &pack);643
+ assert_eq!(inherited.get("usage"), Some(&json!(["emoticon"])));644
+645
+ let pack = object(json!({ "usage": [] }));646
+ let inherited = with_pack_usage(object(json!({})), &pack);647
+ assert_eq!(648
+ inherited.get("usage"),649
+ Some(&json!(["emoticon", "sticker"]))650
+ );651
+652
+ let pack = object(json!({ "usage": ["unknown"] }));653
+ let inherited = with_pack_usage(object(json!({})), &pack);654
+ assert_eq!(655
+ inherited.get("usage"),656
+ Some(&json!(["emoticon", "sticker"]))657
+ );658
+ }659
+660
+ #[test]661
+ fn sticker_body_falls_back_when_missing_or_blank() {662
+ assert_eq!(sticker_body(&object(json!({})), "wave"), "wave");663
+ assert_eq!(sticker_body(&object(json!({ "body": "" })), "wave"), "wave");664
+ assert_eq!(665
+ sticker_body(&object(json!({ "body": " \t\n " })), "wave"),666
+ "wave"667
+ );668
+ assert_eq!(669
+ sticker_body(&object(json!({ "body": " hello " })), "wave"),670
+ " hello "671
+ );672
+ }673
+}674
+576675
fn parse(json: &str) -> Result<JsonObject, Error> {577676
serde_json::from_str(json)578677
.map_err(|source| Error::with_source(ErrorKind::Server, "the pack is malformed", source))@@ -455,12 +455,14 @@ pub enum PackCommand {
455455
from_pack: String,456456
shortcode: String,457457
to: ImagePackSource,458
+ usage: Option<Vec<PackUsage>>,458459
},459460
CloneSticker {460461
room_id: OwnedRoomId,461462
event_id: OwnedEventId,462463
to: ImagePackSource,463464
shortcode: String,465
+ usage: Option<Vec<PackUsage>>,464466
},465467
/// makes the room pack if its state key is free, else merges. images that can't be466468
/// fetched are skipped and listed, the rest are written@@ -468,6 +470,7 @@ pub enum PackCommand {
468470
from_pack: String,469471
to: ImagePackSource,470472
display_name: Option<String>,473
+ usage: Option<Vec<PackUsage>>,471474
},472475
}473476
@@ -1097,11 +1097,23 @@ impl ClientHandle {
10971097
shortcode: String,10981098
to: ImagePackSource,10991099
) -> Result<String, Error> {1100
+ self.clone_pack_image_with_usage(from_pack, shortcode, to, None)1101
+ .await1102
+ }1103
+1104
+ pub async fn clone_pack_image_with_usage(1105
+ &self,1106
+ from_pack: String,1107
+ shortcode: String,1108
+ to: ImagePackSource,1109
+ usage: Option<Vec<PackUsage>>,1110
+ ) -> Result<String, Error> {11001111
let (mut shortcodes, _) = self11011112
.run_clone(PackCommand::CloneImage {11021113
from_pack,11031114
shortcode,11041115
to,1116
+ usage,11051117
})11061118
.await?;11071119
shortcodes@@ -1117,12 +1129,25 @@ impl ClientHandle {
11171129
to: ImagePackSource,11181130
shortcode: String,11191131
) -> Result<String, Error> {1132
+ self.clone_sticker_with_usage(room_id, event_id, to, shortcode, None)1133
+ .await1134
+ }1135
+1136
+ pub async fn clone_sticker_with_usage(1137
+ &self,1138
+ room_id: OwnedRoomId,1139
+ event_id: OwnedEventId,1140
+ to: ImagePackSource,1141
+ shortcode: String,1142
+ usage: Option<Vec<PackUsage>>,1143
+ ) -> Result<String, Error> {11201144
let (mut shortcodes, _) = self11211145
.run_clone(PackCommand::CloneSticker {11221146
room_id,11231147
event_id,11241148
to,11251149
shortcode,1150
+ usage,11261151
})11271152
.await?;11281153
shortcodes@@ -1137,11 +1162,23 @@ impl ClientHandle {
11371162
to: ImagePackSource,11381163
display_name: Option<String>,11391164
) -> Result<Vec<String>, Error> {1165
+ self.clone_pack_with_usage(from_pack, to, display_name, None)1166
+ .await1167
+ }1168
+1169
+ pub async fn clone_pack_with_usage(1170
+ &self,1171
+ from_pack: String,1172
+ to: ImagePackSource,1173
+ display_name: Option<String>,1174
+ usage: Option<Vec<PackUsage>>,1175
+ ) -> Result<Vec<String>, Error> {11401176
let (_, skipped) = self11411177
.run_clone(PackCommand::ClonePack {11421178
from_pack,11431179
to,11441180
display_name,1181
+ usage,11451182
})11461183
.await?;11471184
Ok(skipped)