From 93cc0355ed055e4289cf874b6310272368ed5bbc Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Mon, 9 Dec 2024 18:39:51 +0530
Subject: [PATCH 1/7] Run black and isort only on code files
Signed-off-by: Keshav Priyadarshi
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 40647a8..ba7a25d 100644
--- a/Makefile
+++ b/Makefile
@@ -52,11 +52,11 @@ envfile:
isort:
@echo "-> Apply isort changes to ensure proper imports ordering"
- @${ACTIVATE} isort --profile black .
+ @${ACTIVATE} isort --profile black aboutcode/ fedcode/ federatedcode/ tests/
black:
@echo "-> Apply black code formatter"
- @${ACTIVATE} black ${BLACK_ARGS} .
+ @${ACTIVATE} black ${BLACK_ARGS} aboutcode/ fedcode/ federatedcode/ tests/
doc8:
@echo "-> Run doc8 validation"
From bc99d06030940c38e4a7f64480e70da25b072c70 Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Mon, 9 Dec 2024 18:40:42 +0530
Subject: [PATCH 2/7] Bump aboutcode.hashid to v0.2.0
Signed-off-by: Keshav Priyadarshi
---
pyproject-aboutcode.federatedcode.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject-aboutcode.federatedcode.toml b/pyproject-aboutcode.federatedcode.toml
index f6455a6..29d212a 100644
--- a/pyproject-aboutcode.federatedcode.toml
+++ b/pyproject-aboutcode.federatedcode.toml
@@ -36,7 +36,7 @@ classifiers = [
dependencies = [
"packageurl_python >= 0.15.6",
- "aboutcode.hashid>=0.1.0",
+ "aboutcode.hashid>=0.2.0",
"python-dotenv>=1.0.1",
"click>=8.1.7",
"requests>=2.32.3",
From b23b9f353eaae7a965659acfece766723ea787c3 Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Tue, 10 Dec 2024 16:43:07 +0530
Subject: [PATCH 3/7] Person should be either local user or remote actor
Signed-off-by: Keshav Priyadarshi
---
...kage_local_remove_person_local_and_more.py | 44 +++++++++++++++++++
fedcode/models.py | 28 +++++++++---
2 files changed, 67 insertions(+), 5 deletions(-)
create mode 100644 fedcode/migrations/0003_remove_package_local_remove_person_local_and_more.py
diff --git a/fedcode/migrations/0003_remove_package_local_remove_person_local_and_more.py b/fedcode/migrations/0003_remove_package_local_remove_person_local_and_more.py
new file mode 100644
index 0000000..306acac
--- /dev/null
+++ b/fedcode/migrations/0003_remove_package_local_remove_person_local_and_more.py
@@ -0,0 +1,44 @@
+# Generated by Django 5.0.1 on 2024-12-10 10:01
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("fedcode", "0002_alter_package_options_alter_federaterequest_done_and_more"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name="package",
+ name="local",
+ ),
+ migrations.RemoveField(
+ model_name="person",
+ name="local",
+ ),
+ migrations.AlterField(
+ model_name="person",
+ name="user",
+ field=models.OneToOneField(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ migrations.AddConstraint(
+ model_name="person",
+ constraint=models.CheckConstraint(
+ check=models.Q(
+ models.Q(("remote_actor__isnull", True), ("user__isnull", False)),
+ models.Q(("remote_actor__isnull", False), ("user__isnull", True)),
+ _connector="OR",
+ ),
+ name="either_local_or_remote",
+ ),
+ ),
+ ]
diff --git a/fedcode/models.py b/fedcode/models.py
index 41fc4e4..6db7b80 100644
--- a/fedcode/models.py
+++ b/fedcode/models.py
@@ -64,10 +64,6 @@ class Actor(models.Model):
blank=False,
)
- local = models.BooleanField(
- default=True,
- )
-
class Meta:
abstract = True
@@ -237,6 +233,7 @@ def to_ap(self):
"type": "Note",
"author": self.acct,
"content": self.content,
+ "update_date": self.updated_at,
}
@@ -365,6 +362,7 @@ class Person(Actor):
user = models.OneToOneField(
User,
null=True,
+ blank=True,
on_delete=models.CASCADE,
)
@@ -381,6 +379,21 @@ class Person(Actor):
help_text="Notes created by this user",
)
+ class Meta:
+ constraints = [
+ models.CheckConstraint(
+ check=(
+ models.Q(user__isnull=False, remote_actor__isnull=True)
+ | models.Q(user__isnull=True, remote_actor__isnull=False)
+ ),
+ name="either_local_or_remote",
+ ),
+ ]
+
+ @property
+ def local(self):
+ return bool(self.user)
+
@property
def avatar_absolute_url(self):
return f'{"https://"}{FEDERATEDCODE_DOMAIN}{self.avatar.url}'
@@ -410,6 +423,8 @@ def absolute_url_ap(self):
@property
def inbox_url(self):
+ if not self.local:
+ return self.remote_actor.url
return full_reverse("user-inbox", self.user.username)
@property
@@ -477,7 +492,10 @@ class Meta:
ordering = ["-updated_at"]
def __str__(self):
- return f"{self.person.user.username} - {self.package.purl}"
+ username = self.person.remote_actor.username
+ if self.person.local:
+ username = self.person.user.username
+ return f"{username} - {self.package.purl}"
class Repository(models.Model):
From 403ba4fbe9214e05f8ee80ffc523b90a16466075 Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Tue, 10 Dec 2024 19:28:10 +0530
Subject: [PATCH 4/7] Include update date in Note.to_ap
Signed-off-by: Keshav Priyadarshi
---
fedcode/models.py | 2 +-
tests/test_ap_api.py | 5 +++++
tests/test_vocabulary_toap.py | 2 ++
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/fedcode/models.py b/fedcode/models.py
index 6db7b80..79a9b05 100644
--- a/fedcode/models.py
+++ b/fedcode/models.py
@@ -233,7 +233,7 @@ def to_ap(self):
"type": "Note",
"author": self.acct,
"content": self.content,
- "update_date": self.updated_at,
+ "update_date": str(self.updated_at),
}
diff --git a/tests/test_ap_api.py b/tests/test_ap_api.py
index 8705520..1f30a7a 100644
--- a/tests/test_ap_api.py
+++ b/tests/test_ap_api.py
@@ -209,12 +209,14 @@ def test_get_user_inbox(person, vulnerability, review, package):
"type": "Note",
"author": "pkg:maven/org.apache.logging@127.0.0.1:8000",
"content": "yaml data1",
+ "update_date": str(note1.updated_at),
},
{
"id": f"https://127.0.0.1:8000/notes/{note2.id}",
"type": "Note",
"author": "pkg:maven/org.apache.logging@127.0.0.1:8000",
"content": "yaml data2",
+ "update_date": str(note2.updated_at),
},
],
},
@@ -282,6 +284,7 @@ def test_get_user_outbox(person, vulnerability, review, note):
"content": note.content,
"id": f"https://127.0.0.1:8000/notes/{note.id}",
"type": "Note",
+ "update_date": str(note.updated_at),
}
],
},
@@ -383,6 +386,7 @@ def test_get_package_inbox(package, service):
"[] fixing_vulnerabilities: []",
"id": f"https://127.0.0.1:8000/notes/{note1.id}",
"type": "Note",
+ "update_date": str(note1.updated_at),
}
],
"totalItems": 1,
@@ -413,6 +417,7 @@ def test_get_package_outbox(service, package):
"content": "yaml data1",
"id": f"https://127.0.0.1:8000/notes/{note1.id}",
"type": "Note",
+ "update_date": str(note1.updated_at),
}
],
"totalItems": 1,
diff --git a/tests/test_vocabulary_toap.py b/tests/test_vocabulary_toap.py
index 623653b..acac9d5 100644
--- a/tests/test_vocabulary_toap.py
+++ b/tests/test_vocabulary_toap.py
@@ -158,6 +158,7 @@ def test_objects_to_ap(repo, review, vulnerability, note, rep, mute_post_save_si
"id": f"https://127.0.0.1:8000/notes/{note.id}",
"author": note.acct,
"content": note.content,
+ "update_date": str(note.updated_at),
}
assert rep.to_ap == {
@@ -168,5 +169,6 @@ def test_objects_to_ap(repo, review, vulnerability, note, rep, mute_post_save_si
"id": f"https://127.0.0.1:8000/notes/{note.id}",
"author": note.acct,
"content": note.content,
+ "update_date": str(note.updated_at),
},
}
From e80a5f169db564203078418c38e17eaaf9bb61bf Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Tue, 10 Dec 2024 19:29:15 +0530
Subject: [PATCH 5/7] Run test only on code files
Signed-off-by: Keshav Priyadarshi
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index ba7a25d..48fe6cd 100644
--- a/Makefile
+++ b/Makefile
@@ -92,7 +92,7 @@ migrate:
test:
@echo "-> Run the test suite"
- @${ACTIVATE} pytest -vvs
+ @${ACTIVATE} pytest -vvs tests/ fedcode/ federatedcode/ aboutcode/
docs:
rm -rf docs/_build/
From e9ca650f20d40cbf299078c4b0c5ae682f934a54 Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Tue, 10 Dec 2024 19:41:22 +0530
Subject: [PATCH 6/7] Send a simple POST request for federation
Signed-off-by: Keshav Priyadarshi
---
fedcode/management/commands/federate.py | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/fedcode/management/commands/federate.py b/fedcode/management/commands/federate.py
index 0046af2..61b6ffe 100644
--- a/fedcode/management/commands/federate.py
+++ b/fedcode/management/commands/federate.py
@@ -9,6 +9,7 @@
from traceback import format_exc as traceback_format_exc
+import requests
from django.core.management.base import BaseCommand
from fedcode.models import FederateRequest
@@ -17,19 +18,17 @@
def send_fed_req_task():
- """
- send_fed_req_task is a task to send the http signed request to the target and save the status of the request
- """
+ """Send activity request to the target and save the status."""
+
for rq in FederateRequest.objects.all().order_by("created_at"):
if not rq.done:
try:
- HttpSignature.signed_request(
- rq.target, rq.body, FEDERATEDCODE_PRIVATE_KEY, rq.key_id
- )
+ headers = {"Content-Type": "application/json"}
+ requests.post(rq.target, json=rq.body, headers=headers)
rq.done = True
rq.save()
except Exception as e:
- rq.error_message = e
+ rq.error_message = f"Failed to federate {rq!r} {e!r} \n {traceback_format_exc()}"
finally:
rq.save()
From 1b8da549cabbc0c72bba338c992996629fab835c Mon Sep 17 00:00:00 2001
From: Keshav Priyadarshi
Date: Tue, 10 Dec 2024 20:09:46 +0530
Subject: [PATCH 7/7] Add endpoint to subscribe to package activity
Signed-off-by: Keshav Priyadarshi
---
fedcode/templates/pkg_profile.html | 8 ++++++--
fedcode/views.py | 22 +++++++++++++++++++++-
federatedcode/urls.py | 8 +++++++-
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/fedcode/templates/pkg_profile.html b/fedcode/templates/pkg_profile.html
index 36759b6..eb09305 100644
--- a/fedcode/templates/pkg_profile.html
+++ b/fedcode/templates/pkg_profile.html
@@ -82,8 +82,12 @@
- @{{ follower.person.user.username }}
-
+ {% if follower.person.local %}
+ @{{ follower.person.user.username }}
+ {% else %}
+ @{{ follower.person.remote_actor.username }}
+ {% endif %}
+
{% endfor %}
diff --git a/fedcode/views.py b/fedcode/views.py
index 254b38a..d470455 100644
--- a/fedcode/views.py
+++ b/fedcode/views.py
@@ -10,6 +10,7 @@
import json
import logging
import os.path
+from urllib.parse import urlparse
import requests
from django.contrib import messages
@@ -59,6 +60,7 @@
from fedcode.models import Note
from fedcode.models import Package
from fedcode.models import Person
+from fedcode.models import RemoteActor
from fedcode.models import Repository
from fedcode.models import Reputation
from fedcode.models import Review
@@ -696,6 +698,24 @@ def post(self, request, *args, **kwargs):
return HttpResponseBadRequest("Invalid message")
+@method_decorator(has_valid_header, name="dispatch")
+class RemoteUserSubscribe(View):
+ def get(self, request, *args, **kwargs):
+ """Endpoint to for existing remote user to subscribe to package."""
+ purl = request.GET.get("purl").rstrip("/")
+ package = get_object_or_404(Package, purl=purl)
+ remote_actor = get_object_or_404(RemoteActor, username=kwargs["username"])
+ host = request.get_host()
+ if urlparse(remote_actor.url).netloc == host:
+ _, created = Follow.objects.get_or_create(package=package, person=remote_actor.person)
+ message = f"Already subscribed package {purl}"
+ if created:
+ message = f"Successfully subscribed package {purl}"
+
+ return JsonResponse({"status": "success", "message": message})
+ return HttpResponseBadRequest()
+
+
@method_decorator(has_valid_header, name="dispatch")
class PackageInbox(View):
def get(self, request, *args, **kwargs):
@@ -736,7 +756,7 @@ def get(self, request, *args, **kwargs):
(or at least the ones you're authorized to see).
(client-to-server and/or server-to-server)"""
- actor = Package.objects.get(purl=kwargs["purl_string"])
+ actor = get_object_or_404(Package, purl=kwargs["purl_string"])
return JsonResponse(
{"notes": ap_collection(actor.notes)},
content_type=AP_CONTENT_TYPE,
diff --git a/federatedcode/urls.py b/federatedcode/urls.py
index a059387..fb16091 100644
--- a/federatedcode/urls.py
+++ b/federatedcode/urls.py
@@ -6,8 +6,8 @@
# See https://github.com/nexB/federatedcode for support or download.
# See https://aboutcode.org for more information about AboutCode.org OSS projects.
#
+
from django.conf import settings
-from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include
from django.urls import path
@@ -28,6 +28,7 @@
from fedcode.views import PersonSignUp
from fedcode.views import PersonUpdateView
from fedcode.views import PersonView
+from fedcode.views import RemoteUserSubscribe
from fedcode.views import RepositoryListView
from fedcode.views import ReviewListView
from fedcode.views import ReviewView
@@ -92,6 +93,11 @@
path("api/v0/users/@/inbox", UserInbox.as_view(), name="user-inbox"),
path("api/v0/users/@/outbox", UserOutbox.as_view(), name="user-outbox"),
path("api/v0/purls/@/inbox", PackageInbox.as_view(), name="purl-inbox"),
+ path(
+ "api/v0/users/@/subscribe",
+ RemoteUserSubscribe.as_view(),
+ name="purl-subscribe",
+ ),
path(
"api/v0/purls/@/outbox",
PackageOutbox.as_view(),