Repository: importantimport/hatsu (language: rust)

Issue:
Implement FEP-4adb, FEP-2c59
https://codeberg.org/fediverse/fep/src/branch/main/fep/4adb/fep-4adb.md


Discussion / hints:
I think the default should be `acct:example.com@example.com`.

```jsonc
{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "xrd": "http://docs.oasis-open.org/ns/xri/xrd-1.0#",
      "aliases": {
        "@id": "xrd:Alias",
        "@type": "@id",
        "@container": "@list"
      },
    }
  ],
  "id": "https://hatsu.local/users/example.com",
  "preferredUsername": "example.com",
  "aliases": ["acct:example.com@example.com", "acct:example.com@hatsu.local"],
  ...
}
```
~~User customization via HTML Meta is also supported. Perhaps a documentation page should be added?~~

Since it has little to do with the HTML, I prefer to add it to the JSON Feed Extension.

```html
<!-- "aliases": ["acct:i@example.com", "acct:example.com@hatsu.local"] -->
<meta name="hatsu-aliases" content="i" />
```

or add it to the JSON Feed Extension:

```jsonc
{
  "_hatsu": {
    "about": "https://github.com/importantimport/hatsu/issues/1",
    "aliases": "i"
  },
  ...
}
```
FEP-4adb has been implemented and I expect to support customization and close this issue in `v0.2.0`.
Notably, it is currently in conflict with [FEP-ef61](https://codeberg.org/fediverse/fep/src/branch/main/fep/ef61/fep-ef61.md).

Fix patch:
diff --git a/crates/apub/src/actors/db_user.rs b/crates/apub/src/actors/db_user.rs
index 43843286..35f27ee4 100644
--- a/crates/apub/src/actors/db_user.rs
+++ b/crates/apub/src/actors/db_user.rs
@@ -111,6 +111,12 @@ impl Object for ApubUser {
     }
 
     async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
+        let aliases = self
+            .hatsu
+            .clone()
+            .and_then(|hatsu| hatsu.aliases)
+            .unwrap_or(self.preferred_username.clone());
+
         Ok(Service {
             kind: ServiceType::Service.to_string(),
             name: self.name.clone(),
@@ -134,20 +140,12 @@ impl Object for ApubUser {
             following: Url::parse(&self.following)?,
             tag: vec![],
             // FEP-4adb
-            // TODO: customize via _hatsu.preferred_username
             aliases: Some(vec![
-                format!(
-                    "acct:{}@{}",
-                    &self.preferred_username, &self.preferred_username
-                ),
+                format!("acct:{}@{}", &aliases, &self.preferred_username),
                 format!("acct:{}@{}", &self.preferred_username, data.domain()),
             ]),
             // FEP-2c59
-            // TODO: customize via _hatsu.preferred_username
-            webfinger: Some(format!(
-                "acct:{}@{}",
-                &self.preferred_username, &self.preferred_username
-            )),
+            webfinger: Some(format!("acct:{}@{}", &aliases, &self.preferred_username)),
             public_key: self.public_key(),
         })
     }
diff --git a/crates/db_schema/src/user.rs b/crates/db_schema/src/user.rs
index f45ae1d8..18354312 100644
--- a/crates/db_schema/src/user.rs
+++ b/crates/db_schema/src/user.rs
@@ -34,6 +34,7 @@ pub struct UserFeed {
 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, FromJsonQueryResult)]
 pub struct UserHatsu {
     pub about: Option<String>,
+    pub aliases: Option<String>,
     pub banner_image: Option<String>,
 }
 
diff --git a/crates/feed/src/user_feed_hatsu.rs b/crates/feed/src/user_feed_hatsu.rs
index 267473fb..e7c2505c 100644
--- a/crates/feed/src/user_feed_hatsu.rs
+++ b/crates/feed/src/user_feed_hatsu.rs
@@ -12,6 +12,7 @@ use url::Url;
 #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
 pub struct UserFeedHatsu {
     pub about: Option<Url>,
+    pub aliases: Option<String>,
     pub banner_image: Option<Url>,
 }
 
@@ -42,6 +43,7 @@ impl UserFeedHatsu {
     pub fn into_db(self) -> DbUserHatsu {
         DbUserHatsu {
             about: self.about.and_then(|url| Some(url.to_string())),
+            aliases: self.aliases,
             banner_image: self.banner_image.and_then(|url| Some(url.to_string())),
         }
     }
diff --git a/docs/src/others/json-feed-extension.md b/docs/src/others/json-feed-extension.md
index 1fbcc6d3..f5102276 100644
--- a/docs/src/others/json-feed-extension.md
+++ b/docs/src/others/json-feed-extension.md
@@ -11,6 +11,7 @@ All extension keys for the Hatsu JSON Feed Extension are optional.
 The following applies to the [Top-level JSON Feed](https://www.jsonfeed.org/version/1.1/#top-level-a-name-top-level-a).
 
 - `about` (optional but strongly recommended, string) is the URL used to introduce this extension to humans. should be [https://github.com/importantimport/hatsu/issues/1](https://github.com/importantimport/hatsu/issues/1) .
+- `aliases` (optional, string) is the customized username used for [FEP-4adb](https://codeberg.org/fediverse/fep/src/branch/main/fep/4adb/fep-4adb.md) and [FEP-2c59](https://codeberg.org/fediverse/fep/src/branch/main/fep/2c59/fep-2c59.md).
 - `banner_image` (optional, string) is the URL of the banner image for the website in hatsu.
 
 ## Items


Test patch: