{"id":13929020,"url":"https://github.com/discourse/discourse-activity-pub","last_synced_at":"2025-06-12T03:41:44.389Z","repository":{"id":171385673,"uuid":"611806378","full_name":"discourse/discourse-activity-pub","owner":"discourse","description":"Adds ActivityPub support to Discourse.","archived":false,"fork":false,"pushed_at":"2025-06-04T17:57:12.000Z","size":1449,"stargazers_count":83,"open_issues_count":2,"forks_count":4,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-06-04T21:45:41.820Z","etag":null,"topics":["discourse","discourse-plugin"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/discourse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-03-09T15:29:04.000Z","updated_at":"2025-06-04T17:57:14.000Z","dependencies_parsed_at":"2024-02-07T20:29:32.919Z","dependency_job_id":"1692b856-9876-414c-a8c1-744e8832b19b","html_url":"https://github.com/discourse/discourse-activity-pub","commit_stats":null,"previous_names":["discourse/discourse-activity-pub"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/discourse/discourse-activity-pub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fdiscourse-activity-pub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fdiscourse-activity-pub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fdiscourse-activity-pub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fdiscourse-activity-pub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/discourse","download_url":"https://codeload.github.com/discourse/discourse-activity-pub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discourse%2Fdiscourse-activity-pub/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259391371,"owners_count":22850441,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discourse","discourse-plugin"],"created_at":"2024-08-07T18:02:03.188Z","updated_at":"2025-06-12T03:41:44.367Z","avatar_url":"https://github.com/discourse.png","language":"Ruby","funding_links":[],"categories":["others","Ruby"],"sub_categories":[],"readme":"# Discourse ActivityPub Plugin\n\nAllows you to publish Discourse posts via ActivityPub so they can be read on services that support ActivityPub such as Mastodon. For more information, please see https://meta.discourse.org/t/activitypub-plugin/266794\n\n## Contributing\n\nThis section is about contributing to the plugin and assumes familiarity with Discourse plugin development. If you want to learn more about Discourse plugin development check out the guides on [meta.discourse.org](https://meta.discourse.org/t/developing-discourse-plugins-part-1-create-a-basic-plugin/30515).\n\n### Server\n\nThink about the plugin server as comprising three parts:\n\n1. the AP module;\n2. the plugin; and\n3. Discourse integration.\n\n#### The AP Module\n\nThe AP module:\n\n- receives activities from external actors;\n- manages a processing pipeline for activities; and\n- sends activities to external actors.\n\nAs far as practicable this module should:\n\n- be non-Discourse specific;\n- reflect ActivityPub specifications; and\n- reflect, and support common practices in the fediverse.\n\nThis focus allows for:\n\n- clear separation of concerns;\n- possible packaging of this functionality as a gem; and\n- flexibility in how the plugin interacts with ActivityPub standards and practices.\n\n#### The Plugin\n\nThink of the \"The Plugin\" as comprising all of the non-AP classes (besides `discourse/discourse` extensions). These\nclasses:\n\n- store and migrate ActivityPub data;\n- establish relationships between the stored data;\n- manage ActivityPub workers (jobs);\n- perform specific ActivityPub functions, e.g. handlers, parsers, trackers and validators; and\n- provide a backend for the ActivityPub functionality in the Discourse client.\n\nAs far as possible these classes should not *directly* integrate with `discourse/discourse`, even if they are Discourse-specific in their functionality. This separation aids in maintainability and extensibility. Over time some of the plugin classes may become generic `AP` classes, e.g. `lib/request.rb`, and some may become part of `discourse/discourse`, e.g. `lib/username_validator.rb`.\n\n#### Discourse Integration\n\nAll direct `discourse/discourse` server integration is in the `plugin.rb` and the `/extensions`. Ideally, all `/extensions` will become integrations in the `plugin.rb` as `discourse/discourse` implements new server-side hooks and plugin methods. Some specific `discourse/discourse` updates to improve integration are suggested in `TODO` comments throughout the plugin code.\n\n### Tests\n\nWhen writing tests there's a few things to keep in mind:\n\n1. The plugin has a few different interconnected states which sometimes need to be tested separately:\n   - Plugin: enabled / disabled\n   - Actor (i.e. Category): enabled / disabled\n   - Publishing (i.e. login required): enabled / disabled\n   - Publication type: first post / full topic\n\n2. When testing code involving external requests use and extend the helper functions in `spec/plugin_helper.rb`.\n\n3. When adding attributes to a `discourse/discourse` serializer make sure that serializer is covered by sql query count tests.\n\n### Domains\n\nIf the environment variable `RAILS_DEVELOPMENT_HOSTS` is set the plugin will use the first domain in the variable as the local domain for the purposes of ActivityPub. For example, if you run Discourse like so\n\n```\nRAILS_DEVELOPMENT_HOSTS=discourse.ngrok.io bin/rails s\n```\n\nYou will be able to use ActivityPub category handles on remote ActivityPub servers like so\n\n```\nannouncements@discourse.ngrok.io\n```\n\n### Logging\n\nWhen running in a Development environment the plugin's logger (`DiscourseActivityPub::Logger`) will log all ActivityPub messages with both the Rails logger *and* the AP Logger, which is set to log to `discourse/discourse/logs/activity_pub.log`. The AP logger will also log all incoming and outgoing ActivityPub objects in that dedicated file (formatted as yaml to make them easier to read).\n\n### Delivery\n\nUse the env variable `DISCOURSE_ACTIVITY_PUB_DELIVERY_DELAY` to manually override the delivery delay of ActivityPub objects, e.g.\n\n```\nDISCOURSE_ACTIVITY_PUB_DELIVERY_DELAY=0\n```\n\n### Multiple Local Instances\n\nWhen testing Discourse to Discourse federation you may need to run multiple instances of Discourse locally. This will be an environment-specific question. One way of doing this is cloning two separate versions of `discourse/discourse` and using directory-specific environment variables (e.g. [direnv](https://direnv.net/) on a Mac) to manage the ports and database connections. A `.env` configuration that has worked is:\n\n`~/discourse/discourse`\n\n```\nDISCOURSE_DEV_ALLOW_ANON_TO_IMPERSONATE=1\nRAILS_DEVELOPMENT_HOSTS=discourse.ngrok.io\nALLOW_EMBER_CLI_PROXY_BYPASS=1\nDISCOURSE_DEV_DB=discourse_development\nDISCOURSE_DEV_LOG_LEVEL=debug\nLOAD_PLUGINS=1\nDISCOURSE_ACTIVITY_PUB_DELIVERY_DELAY=0\nOBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES\n```\n\n`~/discourse/discourse_two`\n\n```\nDISCOURSE_DEV_ALLOW_ANON_TO_IMPERSONATE=1\nRAILS_DEVELOPMENT_HOSTS=discourse-two.ngrok.io\nALLOW_EMBER_CLI_PROXY_BYPASS=1\nDISCOURSE_DEV_DB=discourse_development_two\nUNICORN_PORT=6000\nPORT=6200\nREDIS_PORT=6380\nDISCOURSE_REDIS_PORT=6380\nDISCOURSE_DEV_LOG_LEVEL=debug\nLOAD_PLUGINS=1\nDISCOURSE_ACTIVITY_PUB_DELIVERY_DELAY=0\nOBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscourse%2Fdiscourse-activity-pub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiscourse%2Fdiscourse-activity-pub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscourse%2Fdiscourse-activity-pub/lists"}