2024-01-03 12:29:25 +00:00
|
|
|
use crate::backend::error::MyResult;
|
2024-01-03 16:06:52 +00:00
|
|
|
use crate::common::EditVersion;
|
2024-02-13 15:49:26 +00:00
|
|
|
use crate::common::EditView;
|
2024-02-13 12:09:45 +00:00
|
|
|
use activitypub_federation::fetch::object_id::ObjectId;
|
|
|
|
use activitypub_federation::traits::Object;
|
2023-11-27 15:34:45 +00:00
|
|
|
use anyhow::anyhow;
|
|
|
|
use diffy::{apply, Patch};
|
2023-11-14 23:16:51 +00:00
|
|
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
2024-02-13 12:09:45 +00:00
|
|
|
use serde::Deserialize;
|
2023-12-01 13:04:51 +00:00
|
|
|
|
2024-02-13 12:09:45 +00:00
|
|
|
use crate::common::utils::extract_domain;
|
2023-11-14 23:16:51 +00:00
|
|
|
use url::{ParseError, Url};
|
|
|
|
|
2024-02-13 12:09:45 +00:00
|
|
|
pub fn generate_activity_id<T>(for_url: &ObjectId<T>) -> Result<Url, ParseError>
|
|
|
|
where
|
|
|
|
T: Object + Send + 'static,
|
|
|
|
for<'de2> <T as Object>::Kind: Deserialize<'de2>,
|
|
|
|
{
|
|
|
|
let domain = extract_domain(for_url);
|
2023-11-14 23:16:51 +00:00
|
|
|
let id: String = thread_rng()
|
|
|
|
.sample_iter(&Alphanumeric)
|
|
|
|
.take(7)
|
|
|
|
.map(char::from)
|
|
|
|
.collect();
|
2024-02-13 12:09:45 +00:00
|
|
|
Url::parse(&format!("http://{}/objects/{}", domain, id))
|
2023-11-14 23:16:51 +00:00
|
|
|
}
|
2023-11-27 15:34:45 +00:00
|
|
|
|
|
|
|
/// Starting from empty string, apply edits until the specified version is reached. If no version is
|
|
|
|
/// given, apply all edits up to latest version.
|
|
|
|
///
|
|
|
|
/// TODO: testing
|
|
|
|
/// TODO: should cache all these generated versions
|
2024-02-13 15:49:26 +00:00
|
|
|
pub fn generate_article_version(edits: &Vec<EditView>, version: &EditVersion) -> MyResult<String> {
|
2023-11-27 15:34:45 +00:00
|
|
|
let mut generated = String::new();
|
2023-12-01 13:04:51 +00:00
|
|
|
if version == &EditVersion::default() {
|
|
|
|
return Ok(generated);
|
|
|
|
}
|
2023-11-27 15:34:45 +00:00
|
|
|
for e in edits {
|
2024-02-13 15:49:26 +00:00
|
|
|
let patch = Patch::from_str(&e.edit.diff)?;
|
2023-11-27 15:34:45 +00:00
|
|
|
generated = apply(&generated, &patch)?;
|
2024-02-13 15:49:26 +00:00
|
|
|
if &e.edit.hash == version {
|
2023-11-27 15:34:45 +00:00
|
|
|
return Ok(generated);
|
|
|
|
}
|
|
|
|
}
|
2023-11-28 12:04:33 +00:00
|
|
|
Err(anyhow!("failed to generate article version").into())
|
2023-11-27 15:34:45 +00:00
|
|
|
}
|
2023-12-05 11:54:38 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
2024-02-13 15:49:26 +00:00
|
|
|
use crate::common::{DbEdit, DbPerson};
|
2023-12-05 11:54:38 +00:00
|
|
|
use activitypub_federation::fetch::object_id::ObjectId;
|
2024-01-26 13:21:59 +00:00
|
|
|
use chrono::Utc;
|
2023-12-05 11:54:38 +00:00
|
|
|
use diffy::create_patch;
|
|
|
|
|
2024-02-13 15:49:26 +00:00
|
|
|
fn create_edits() -> MyResult<Vec<EditView>> {
|
|
|
|
let generate_edit = |a, b| -> MyResult<EditView> {
|
2023-12-05 11:54:38 +00:00
|
|
|
let diff = create_patch(a, b).to_string();
|
2024-02-13 15:49:26 +00:00
|
|
|
Ok(EditView {
|
|
|
|
edit: DbEdit {
|
|
|
|
id: 0,
|
|
|
|
creator_id: 0,
|
|
|
|
hash: EditVersion::new(&diff),
|
|
|
|
ap_id: ObjectId::parse("http://example.com")?,
|
|
|
|
diff,
|
|
|
|
summary: String::new(),
|
|
|
|
article_id: 0,
|
|
|
|
previous_version_id: Default::default(),
|
|
|
|
created: Utc::now(),
|
|
|
|
},
|
|
|
|
creator: DbPerson {
|
|
|
|
id: 0,
|
|
|
|
username: "".to_string(),
|
|
|
|
ap_id: ObjectId::parse("http://example.com").unwrap(),
|
|
|
|
inbox_url: "".to_string(),
|
|
|
|
public_key: "".to_string(),
|
|
|
|
private_key: None,
|
|
|
|
last_refreshed_at: Default::default(),
|
|
|
|
local: false,
|
|
|
|
},
|
2023-12-05 11:54:38 +00:00
|
|
|
})
|
|
|
|
};
|
|
|
|
Ok([
|
|
|
|
generate_edit("", "test\n")?,
|
|
|
|
generate_edit("test\n", "sda\n")?,
|
|
|
|
generate_edit("sda\n", "123\n")?,
|
|
|
|
]
|
|
|
|
.to_vec())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_generate_article_version() -> MyResult<()> {
|
|
|
|
let edits = create_edits()?;
|
2024-02-13 15:49:26 +00:00
|
|
|
let generated = generate_article_version(&edits, &edits[1].edit.hash)?;
|
2023-12-05 11:54:38 +00:00
|
|
|
assert_eq!("sda\n", generated);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_generate_invalid_version() -> MyResult<()> {
|
|
|
|
let edits = create_edits()?;
|
2024-01-30 15:06:02 +00:00
|
|
|
let generated = generate_article_version(&edits, &EditVersion::new("invalid"));
|
2023-12-05 11:54:38 +00:00
|
|
|
assert!(generated.is_err());
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_generate_first_version() -> MyResult<()> {
|
|
|
|
let edits = create_edits()?;
|
|
|
|
let generated = generate_article_version(&edits, &EditVersion::default())?;
|
|
|
|
assert_eq!("", generated);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|