From 2f443414a7e029f83292873257d2940b5a10cc64 Mon Sep 17 00:00:00 2001
From: Andrew Godwin
Date: Sun, 27 Nov 2022 16:43:20 -0700
Subject: Collect more actor information in fetch

Fixes #31
---
 static/css/style.css         | 17 ++++++++++++++++-
 templates/identity/view.html | 11 +++++++++++
 users/models/identity.py     | 42 ++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/static/css/style.css b/static/css/style.css
index baddcea..1dbf30e 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -59,7 +59,8 @@ a {
     text-decoration: none;
 }
 
-p a {
+p a,
+td a {
     text-decoration: underline;
 }
 
@@ -690,6 +691,20 @@ h1.identity small {
     text-decoration: underline;
 }
 
+table.metadata {
+    margin: -10px 0 0 0;
+}
+
+table.metadata td {
+    padding: 0;
+}
+
+table.metadata td.name {
+    padding-right: 10px;
+    font-weight: bold;
+}
+
+
 /* Posts */
 
 .post {
diff --git a/templates/identity/view.html b/templates/identity/view.html
index f69ce9a..ff42db6 100644
--- a/templates/identity/view.html
+++ b/templates/identity/view.html
@@ -43,6 +43,17 @@
         </div>
     {% endif %}
 
+    {% if identity.metadata %}
+        <table class="metadata">
+            {% for entry in identity.safe_metadata %}
+                <tr>
+                    <td class="name">{{ entry.name }}</td>
+                    <td class="value">{{ entry.value }}</td>
+                </tr>
+            {% endfor %}
+            </table>
+    {% endif %}
+
     {% if not identity.local %}
         {% if identity.outdated and not identity.name %}
             <p class="system-note">
diff --git a/users/models/identity.py b/users/models/identity.py
index 8583487..805755a 100644
--- a/users/models/identity.py
+++ b/users/models/identity.py
@@ -12,8 +12,8 @@ from django.utils import timezone
 from django.utils.functional import lazy
 
 from core.exceptions import ActorMismatchError
-from core.html import sanitize_post
-from core.ld import canonicalise, media_type_from_filename
+from core.html import sanitize_post, strip_html
+from core.ld import canonicalise, get_list, media_type_from_filename
 from core.models import Config
 from core.signatures import HttpSignature, RsaKeys
 from core.uploads import upload_namer
@@ -73,9 +73,12 @@ class Identity(StatorModel):
 
     profile_uri = models.CharField(max_length=500, blank=True, null=True)
     inbox_uri = models.CharField(max_length=500, blank=True, null=True)
+    shared_inbox_uri = models.CharField(max_length=500, blank=True, null=True)
     outbox_uri = models.CharField(max_length=500, blank=True, null=True)
     icon_uri = models.CharField(max_length=500, blank=True, null=True)
     image_uri = models.CharField(max_length=500, blank=True, null=True)
+    followers_uri = models.CharField(max_length=500, blank=True, null=True)
+    following_uri = models.CharField(max_length=500, blank=True, null=True)
 
     icon = models.ImageField(
         upload_to=partial(upload_namer, "profile_images"), blank=True, null=True
@@ -84,6 +87,12 @@ class Identity(StatorModel):
         upload_to=partial(upload_namer, "background_images"), blank=True, null=True
     )
 
+    # Should be a list of {"name":..., "value":...} dicts
+    metadata = models.JSONField(blank=True, null=True)
+
+    # Should be a list of object URIs (we don't want a full M2M here)
+    pinned = models.JSONField(blank=True, null=True)
+
     private_key = models.TextField(null=True, blank=True)
     public_key = models.TextField(null=True, blank=True)
     public_key_id = models.TextField(null=True, blank=True)
@@ -149,6 +158,18 @@ class Identity(StatorModel):
     def safe_summary(self):
         return sanitize_post(self.summary)
 
+    @property
+    def safe_metadata(self):
+        if not self.metadata:
+            return []
+        return [
+            {
+                "name": data["name"],
+                "value": strip_html(data["value"]),
+            }
+            for data in self.metadata
+        ]
+
     ### Alternate constructors/fetchers ###
 
     @classmethod
@@ -365,6 +386,9 @@ class Identity(StatorModel):
         self.profile_uri = document.get("url")
         self.inbox_uri = document.get("inbox")
         self.outbox_uri = document.get("outbox")
+        self.followers_uri = document.get("followers")
+        self.following_uri = document.get("following")
+        self.shared_inbox_uri = document.get("endpoints", {}).get("sharedInbox")
         self.summary = document.get("summary")
         self.username = document.get("preferredUsername")
         if self.username and "@value" in self.username:
@@ -379,6 +403,20 @@ class Identity(StatorModel):
         self.discoverable = document.get(
             "http://joinmastodon.org/ns#discoverable", True
         )
+        # Profile links/metadata
+        self.metadata = []
+        for attachment in get_list(document, "attachment"):
+            if (
+                attachment["type"] == "http://schema.org#PropertyValue"
+                and "name" in attachment
+                and "http://schema.org#value" in attachment
+            ):
+                self.metadata.append(
+                    {
+                        "name": attachment.get("name"),
+                        "value": strip_html(attachment.get("http://schema.org#value")),
+                    }
+                )
         # Now go do webfinger with that info to see if we can get a canonical domain
         actor_url_parts = urlparse(self.actor_uri)
         get_domain = sync_to_async(Domain.get_remote_domain)
-- 
cgit v1.2.3