diff --git a/examples/send_to_mastodon.py b/examples/send_to_mastodon.py index c82fbe53e69a2de02ee1fbb7e6c4607985b884a6..adf1514e621e99546ab312d1fe5b4c8e90b3abd1 100644 --- a/examples/send_to_mastodon.py +++ b/examples/send_to_mastodon.py @@ -7,11 +7,13 @@ import logging from pathlib import Path import sys from config import CONFIG +from datetime import datetime, timezone # Add src directory to Python path src_path = Path(__file__).parent.parent / "src" sys.path.insert(0, str(src_path)) +from pyfed.models import APPerson, APNote, APCreate from pyfed.federation.delivery import ActivityDelivery from pyfed.federation.discovery import InstanceDiscovery from pyfed.security.key_management import KeyManager @@ -73,25 +75,77 @@ async def send_activity_to_mastodon(): logger.info(f"Found actor's inbox: {inbox_url}") # 3. Create the Activity with ngrok domain - note_activity = { - "@context": "https://www.w3.org/ns/activitystreams", - "type": "Create", - "actor": f"https://{CONFIG['domain']}/users/{CONFIG['user']}", - "object": { - "type": "Note", - "content": "Hello @kene29@mastodon.social! This is a test message from PyFed.", - "attributedTo": f"https://{CONFIG['domain']}/users/{CONFIG['user']}", - "to": [actor_url], - "cc": ["https://www.w3.org/ns/activitystreams#Public"] - }, - "to": [actor_url], - "cc": ["https://www.w3.org/ns/activitystreams#Public"] - } + note_id = f"https://{CONFIG['domain']}/notes/{int(asyncio.get_event_loop().time() * 1000)}" + # note_activity = { + # "@context": [ + # "https://www.w3.org/ns/activitystreams", + # "https://w3id.org/security/v1" + # ], + # "id": f"{note_id}/activity", + # "type": "Create", + # "actor": f"https://{CONFIG['domain']}/users/{CONFIG['user']}", + # "published": datetime.utcnow().isoformat() + "Z", + # "object": { + # "id": note_id, + # "type": "Note", + # "content": "Hello @kene29@mastodon.social! This is a test message from PyFed.", + # "attributedTo": f"https://{CONFIG['domain']}/users/{CONFIG['user']}", + # "to": [actor_url], + # "cc": ["https://www.w3.org/ns/activitystreams#Public"], + # "published": datetime.utcnow().isoformat() + "Z", + # "url": note_id, + # "tag": [{ + # "type": "Mention", + # "href": actor_url, + # "name": "@kene29@mastodon.social" + # }] + # }, + # "to": [actor_url], + # "cc": ["https://www.w3.org/ns/activitystreams#Public"] + # } + + # Create actor + actor = APPerson( + id=f"https://{CONFIG['domain']}/users/{CONFIG['user']}", + name="Alice", + preferred_username="alice", + inbox="https://example.com/users/alice/inbox", + outbox="https://example.com/users/alice/outbox", + followers="https://example.com/users/alice/followers" + ) + + # Create note with string attributed_to + note = APNote( + id=note_id, + content=f"Hello @kene29! This is a test note!", + attributed_to=str(actor.id), # Convert URL to string + to=[inbox_url], + cc=["https://www.w3.org/ns/activitystreams#Public"], + published=datetime.utcnow().isoformat() + "Z", + url=str(note_id), + tag=[{ + "type": "Mention", + "href": actor_url, + "name": "@kene29@mastodon.social" + }] + ) + + # Create activity + create_activity = APCreate( + id=f"https://example.com/activities/{datetime.now(timezone.utc).timestamp()}", + actor=str(actor.id), # Convert URL to string + object=note, + to=note.to, + cc=note.cc, + published=datetime.utcnow().isoformat() + "Z", + ) # 4. Deliver the activity to the inbox - logger.info(f"Delivering activity: {note_activity}") + logger.info("Serializing activity...") + activity_dict = create_activity.serialize() + logger.info(f"Delivering activity: {activity_dict}") result = await delivery.deliver_activity( - activity=note_activity, + activity=activity_dict, recipients=[inbox_url] # Use the inbox URL instead of actor URL ) logger.info(f"Delivery result: {result}") diff --git a/src/pyfed/federation/delivery.py b/src/pyfed/federation/delivery.py index c7f0e2f6afc75bd5b40d178ef8673b112be985e3..48d2cfc332c3e8daf2a5c8d2c65fd1c157f8f5a4 100644 --- a/src/pyfed/federation/delivery.py +++ b/src/pyfed/federation/delivery.py @@ -100,6 +100,7 @@ class ActivityDelivery: if inbox_result.success: result.success.extend(inbox_result.success) + logger.info("inbox result: {inbox_result}") else: result.failed.extend(inbox_result.failed) result.status_code = inbox_result.status_code @@ -148,7 +149,7 @@ class ActivityDelivery: headers=headers, body=activity # Pass the original activity for consistent hashing ) - + DEBUG = True # Send the request with the exact same JSON string we hashed async with self.session.post( inbox_url, @@ -158,11 +159,16 @@ class ActivityDelivery: "Content-Type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" } ) as response: + + if DEBUG: + logger.debug(response) + # import pdb; pdb.set_trace() result.status_code = response.status error_text = await response.text() if response.status in [200, 201, 202]: result.success = [inbox_url] + logger.debug(f"\n\n\n\nresult after being successful: {result}") return result if response.status == 429: diff --git a/src/pyfed/serializers/json_serializer.py b/src/pyfed/serializers/json_serializer.py index 54e34d70453cbc1e788196b13f4f41d59d2664ee..dbd34fafaa50078193aa4b1124153b094f37ebee 100644 --- a/src/pyfed/serializers/json_serializer.py +++ b/src/pyfed/serializers/json_serializer.py @@ -105,7 +105,7 @@ class ActivityPubSerializer: # Add context if needed if include_context: - processed_data["@context"] = "https://www.w3.org/ns/activitystreams" + processed_data["@context"] = ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"] return processed_data