Skip to content

Commit b68ef5e

Browse files
authored
Merge pull request #50 from aboutcode-org/47-client-subscribe
Add support for subscribing to package updates over AP from PurlDB or VulnerableCode
2 parents 789b002 + f30a37f commit b68ef5e

File tree

11 files changed

+106
-20
lines changed

11 files changed

+106
-20
lines changed

aboutcode/federatedcode/client/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import os
1111
from typing import Union
12+
from urllib.parse import quote
1213
from urllib.parse import urljoin
1314

1415
import requests
@@ -60,3 +61,10 @@ def get_package_scan(purl: Union[PackageURL, str]):
6061
if response.status_code == 404:
6162
raise ScanNotAvailableError(f"No scan available for {purl!s}")
6263
raise err
64+
65+
66+
def subscribe_package(federatedcode_host, remote_username, purl):
67+
"""Subscribe package for their metadata update from FederatedCode."""
68+
69+
url_path = f"api/v0/users/@{remote_username}/subscribe/?purl={quote(purl)}"
70+
return requests.get(urljoin(federatedcode_host, url_path))

aboutcode/federatedcode/contrib/__init__.py

Whitespace-only changes.

aboutcode/federatedcode/contrib/django/__init__.py

Whitespace-only changes.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# FederatedCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/federatedcode for support or download.
7+
# See https://aboutcode.org for more information about AboutCode.org OSS projects.
8+
#
9+
10+
from django.db import models
11+
from django.utils.translation import gettext_lazy as _
12+
13+
14+
class FederatedCodePackageActivityMixin(models.Model):
15+
"""Abstract Model for FederatedCode package activity."""
16+
17+
author = models.CharField(
18+
max_length=300,
19+
null=False,
20+
blank=False,
21+
help_text=_("Author of package activity."),
22+
)
23+
24+
content = models.JSONField(
25+
null=False,
26+
blank=False,
27+
help_text=_("Package activity content."),
28+
)
29+
30+
activity_update_date = models.DateTimeField(
31+
null=True,
32+
blank=True,
33+
db_index=True,
34+
help_text=_("Timestamp indicating when original activity was last updated."),
35+
)
36+
37+
class Meta:
38+
abstract = True
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# FederatedCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/federatedcode for support or download.
7+
# See https://aboutcode.org for more information about AboutCode.org OSS projects.
8+
#
9+
10+
11+
import saneyaml
12+
13+
14+
def get_package_activity_type(activity: dict) -> str:
15+
return activity.get("type")
16+
17+
18+
def get_package_activity_object(activity: dict) -> dict:
19+
return activity.get("object")
20+
21+
22+
def get_package_activity_author(activity: dict) -> str:
23+
activity_object = get_package_activity_object(activity)
24+
return activity_object.get("author")
25+
26+
27+
def get_package_activity_content(activity: dict) -> dict:
28+
activity_object = get_package_activity_object(activity)
29+
content = activity_object.get("content")
30+
return saneyaml.load(content)
31+
32+
33+
def get_package_activity_update_date(activity: dict) -> str:
34+
activity_object = get_package_activity_object(activity)
35+
return activity_object.get("update_date")

fedcode/management/commands/federate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# See https://aboutcode.org for more information about AboutCode.org OSS projects.
88
#
99

10+
import json
1011
from traceback import format_exc as traceback_format_exc
1112

1213
import requests
@@ -24,9 +25,8 @@ def send_fed_req_task():
2425
if not rq.done:
2526
try:
2627
headers = {"Content-Type": "application/json"}
27-
requests.post(rq.target, json=rq.body, headers=headers)
28+
requests.post(rq.target, json=json.loads(rq.body), headers=headers)
2829
rq.done = True
29-
rq.save()
3030
except Exception as e:
3131
rq.error_message = f"Failed to federate {rq!r} {e!r} \n {traceback_format_exc()}"
3232
finally:

fedcode/models.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#
99

1010
import uuid
11+
from urllib.parse import urljoin
1112

1213
from django.contrib.auth.models import User
1314
from django.contrib.contenttypes.fields import GenericForeignKey
@@ -424,11 +425,13 @@ def absolute_url_ap(self):
424425
@property
425426
def inbox_url(self):
426427
if not self.local:
427-
return self.remote_actor.url
428+
return urljoin(self.remote_actor.url, "inbox")
428429
return full_reverse("user-inbox", self.user.username)
429430

430431
@property
431432
def outbox_url(self):
433+
if not self.local:
434+
return urljoin(self.remote_actor.url, "outbox")
432435
return full_reverse("user-outbox", self.user.username)
433436

434437
@property
@@ -444,10 +447,11 @@ def key_id(self):
444447

445448
@property
446449
def to_ap(self):
450+
name = self.user.username if self.local else self.remote_actor.username
447451
return {
448452
"id": self.absolute_url_ap,
449453
"type": "Person",
450-
"name": self.user.username,
454+
"name": name,
451455
"summary": self.summary,
452456
"inbox": self.inbox_url,
453457
"outbox": self.outbox_url,

fedcode/pipes/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
# See https://aboutcode.org for more information about AboutCode.org OSS projects.
88
#
99

10+
import json
11+
1012
import saneyaml
1113
from packageurl import PackageURL
1214

@@ -22,7 +24,7 @@ def create_note(pkg, note_dict):
2224
create_activity = CreateActivity(actor=pkg.to_ap, object=note.to_ap)
2325
Activity.federate(
2426
targets=pkg.followers_inboxes,
25-
body=create_activity.to_ap(),
27+
body=json.dumps(create_activity.to_ap()),
2628
key_id=pkg.key_id,
2729
)
2830

@@ -36,7 +38,7 @@ def delete_note(pkg, note_dict):
3638
deleted_activity = DeleteActivity(actor=pkg.to_ap, object=note_ap)
3739
Activity.federate(
3840
targets=pkg.followers_inboxes,
39-
body=deleted_activity.to_ap,
41+
body=json.dumps(deleted_activity.to_ap),
4042
key_id=pkg.key_id,
4143
)
4244

fedcode/views.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -698,22 +698,19 @@ def post(self, request, *args, **kwargs):
698698
return HttpResponseBadRequest("Invalid message")
699699

700700

701-
@method_decorator(has_valid_header, name="dispatch")
702701
class RemoteUserSubscribe(View):
703702
def get(self, request, *args, **kwargs):
704-
"""Endpoint to for existing remote user to subscribe to package."""
703+
"""Endpoint for existing remote user to subscribe to package."""
705704
purl = request.GET.get("purl").rstrip("/")
706705
package = get_object_or_404(Package, purl=purl)
707706
remote_actor = get_object_or_404(RemoteActor, username=kwargs["username"])
708-
host = request.get_host()
709-
if urlparse(remote_actor.url).netloc == host:
710-
_, created = Follow.objects.get_or_create(package=package, person=remote_actor.person)
711-
message = f"Already subscribed package {purl}"
712-
if created:
713-
message = f"Successfully subscribed package {purl}"
714-
715-
return JsonResponse({"status": "success", "message": message})
716-
return HttpResponseBadRequest()
707+
708+
_, created = Follow.objects.get_or_create(package=package, person=remote_actor.person)
709+
message = f"Already subscribed to package {purl}"
710+
if created:
711+
message = f"Successfully subscribed to package {purl}"
712+
713+
return JsonResponse({"status": "success", "message": message})
717714

718715

719716
@method_decorator(has_valid_header, name="dispatch")

federatedcode/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
path("api/v0/users/@<str:username>/outbox", UserOutbox.as_view(), name="user-outbox"),
9595
path("api/v0/purls/@<path:purl_string>/inbox", PackageInbox.as_view(), name="purl-inbox"),
9696
path(
97-
"api/v0/users/@<str:username>/subscribe",
97+
"api/v0/users/@<str:username>/subscribe/",
9898
RemoteUserSubscribe.as_view(),
9999
name="purl-subscribe",
100100
),

0 commit comments

Comments
 (0)