mirror of
https://github.com/mastodon/mastodon.git
synced 2025-01-03 15:52:34 +01:00
Humble beginnings of fasp data sharing.
Subscriptions can be made and new statuses will be announced to subscribed fasp.
This commit is contained in:
parent
f136a9cf0f
commit
e234a89e06
16 changed files with 195 additions and 0 deletions
|
@ -0,0 +1,4 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::Fasp::DataSharing::V0::BackfillRequestsController < ApplicationController
|
||||||
|
end
|
|
@ -0,0 +1,25 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::Fasp::DataSharing::V0::EventSubscriptionsController < Api::Fasp::BaseController
|
||||||
|
def create
|
||||||
|
subscription = current_provider.fasp_subscriptions.create!(subscription_params)
|
||||||
|
|
||||||
|
render json: { subscription: { id: subscription.id } }, status: 201
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
subscription = current_provider.fasp_subscriptions.find(params[:id])
|
||||||
|
subscription.destroy
|
||||||
|
|
||||||
|
head 204
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def subscription_params
|
||||||
|
params
|
||||||
|
.permit(:category, :subscriptionType, :maxBatchSize, threshold: {})
|
||||||
|
.to_unsafe_h
|
||||||
|
.transform_keys { |k| k.to_s.underscore }
|
||||||
|
end
|
||||||
|
end
|
|
@ -26,6 +26,7 @@ class Fasp::Request
|
||||||
def headers(verb, url, body = '')
|
def headers(verb, url, body = '')
|
||||||
result = {
|
result = {
|
||||||
'accept' => 'application/json',
|
'accept' => 'application/json',
|
||||||
|
'content-type' => 'application/json',
|
||||||
'content-digest' => content_digest(body),
|
'content-digest' => content_digest(body),
|
||||||
}
|
}
|
||||||
result.merge(signature_headers(verb, url, result))
|
result.merge(signature_headers(verb, url, result))
|
||||||
|
|
16
app/models/concerns/status/fasp_concern.rb
Normal file
16
app/models/concerns/status/fasp_concern.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Status::FaspConcern
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
after_commit :announce_new_content_to_subscribed_fasp, on: :create
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def announce_new_content_to_subscribed_fasp
|
||||||
|
store_uri unless uri # TODO: solve this more elegantly
|
||||||
|
Fasp::AnnounceNewContentWorker.perform_async(uri)
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,6 +23,7 @@ class Fasp::Provider < ApplicationRecord
|
||||||
include DebugConcern
|
include DebugConcern
|
||||||
|
|
||||||
has_many :fasp_debug_callbacks, inverse_of: :fasp_provider, class_name: 'Fasp::DebugCallback', dependent: :delete_all
|
has_many :fasp_debug_callbacks, inverse_of: :fasp_provider, class_name: 'Fasp::DebugCallback', dependent: :delete_all
|
||||||
|
has_many :fasp_subscriptions, inverse_of: :fasp_provider, class_name: 'Fasp::Subscription', dependent: :delete_all
|
||||||
|
|
||||||
before_create :create_keypair
|
before_create :create_keypair
|
||||||
|
|
||||||
|
|
40
app/models/fasp/subscription.rb
Normal file
40
app/models/fasp/subscription.rb
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: fasp_subscriptions
|
||||||
|
#
|
||||||
|
# id :bigint(8) not null, primary key
|
||||||
|
# category :string not null
|
||||||
|
# max_batch_size :integer not null
|
||||||
|
# subscription_type :string not null
|
||||||
|
# threshold_likes :integer
|
||||||
|
# threshold_replies :integer
|
||||||
|
# threshold_shares :integer
|
||||||
|
# threshold_timeframe :integer
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# fasp_provider_id :bigint(8) not null
|
||||||
|
#
|
||||||
|
class Fasp::Subscription < ApplicationRecord
|
||||||
|
CATEGORIES = %w(account content).freeze
|
||||||
|
TYPES = %w(lifecycle trends).freeze
|
||||||
|
|
||||||
|
belongs_to :fasp_provider, class_name: 'Fasp::Provider'
|
||||||
|
|
||||||
|
validates :category, presence: true, inclusion: CATEGORIES
|
||||||
|
validates :subscription_type, presence: true,
|
||||||
|
inclusion: TYPES
|
||||||
|
|
||||||
|
scope :content, -> { where(category: 'content') }
|
||||||
|
scope :account, -> { where(category: 'account') }
|
||||||
|
scope :lifecycle, -> { where(subscription_type: 'lifecycle') }
|
||||||
|
scope :trends, -> { where(subscription_type: 'trends') }
|
||||||
|
|
||||||
|
def threshold=(threshold)
|
||||||
|
self.threshold_timeframe = threshold['timeframe'] || 15
|
||||||
|
self.threshold_shares = threshold['shares'] || 3
|
||||||
|
self.threshold_likes = threshold['likes'] || 3
|
||||||
|
self.threshold_replies = threshold['replies'] || 3
|
||||||
|
end
|
||||||
|
end
|
|
@ -34,6 +34,7 @@ class Status < ApplicationRecord
|
||||||
include Discard::Model
|
include Discard::Model
|
||||||
include Paginable
|
include Paginable
|
||||||
include RateLimitable
|
include RateLimitable
|
||||||
|
include Status::FaspConcern
|
||||||
include Status::SafeReblogInsert
|
include Status::SafeReblogInsert
|
||||||
include Status::SearchConcern
|
include Status::SearchConcern
|
||||||
include Status::SnapshotConcern
|
include Status::SnapshotConcern
|
||||||
|
|
28
app/workers/fasp/announce_new_content_worker.rb
Normal file
28
app/workers/fasp/announce_new_content_worker.rb
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Fasp::AnnounceNewContentWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
sidekiq_options queue: 'fasp', retry: 5
|
||||||
|
|
||||||
|
def perform(uri)
|
||||||
|
Fasp::Subscription.includes(:fasp_provider).content.lifecycle.each do |subscription|
|
||||||
|
announce(subscription, uri)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def announce(subscription, uri)
|
||||||
|
Fasp::Request.new(subscription.fasp_provider).post('/data_sharing/v0/announcements', body: {
|
||||||
|
source: {
|
||||||
|
subscription: {
|
||||||
|
id: subscription.id.to_s,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
category: 'content',
|
||||||
|
eventType: 'new',
|
||||||
|
objectUris: [uri],
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,6 +10,14 @@ namespace :api, format: false do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
namespace :data_sharing do
|
||||||
|
namespace :v0 do
|
||||||
|
resources :backfill_requests, only: [:create]
|
||||||
|
|
||||||
|
resources :event_subscriptions, only: [:create, :destroy]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
resource :registration, only: [:create]
|
resource :registration, only: [:create]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
- [mailers, 2]
|
- [mailers, 2]
|
||||||
- [pull]
|
- [pull]
|
||||||
- [scheduler]
|
- [scheduler]
|
||||||
|
- [fasp]
|
||||||
|
|
||||||
:scheduler:
|
:scheduler:
|
||||||
:listened_queues_only: true
|
:listened_queues_only: true
|
||||||
|
|
18
db/migrate/20241213130230_create_fasp_subscriptions.rb
Normal file
18
db/migrate/20241213130230_create_fasp_subscriptions.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateFaspSubscriptions < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
create_table :fasp_subscriptions do |t|
|
||||||
|
t.string :category, null: false
|
||||||
|
t.string :subscription_type, null: false
|
||||||
|
t.integer :max_batch_size, null: false
|
||||||
|
t.integer :threshold_timeframe
|
||||||
|
t.integer :threshold_shares
|
||||||
|
t.integer :threshold_likes
|
||||||
|
t.integer :threshold_replies
|
||||||
|
t.references :fasp_provider, null: false, foreign_key: true
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
db/schema.rb
15
db/schema.rb
|
@ -470,6 +470,20 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_16_224825) do
|
||||||
t.index ["base_url"], name: "index_fasp_providers_on_base_url", unique: true
|
t.index ["base_url"], name: "index_fasp_providers_on_base_url", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "fasp_subscriptions", force: :cascade do |t|
|
||||||
|
t.string "category", null: false
|
||||||
|
t.string "subscription_type", null: false
|
||||||
|
t.integer "max_batch_size", null: false
|
||||||
|
t.integer "threshold_timeframe"
|
||||||
|
t.integer "threshold_shares"
|
||||||
|
t.integer "threshold_likes"
|
||||||
|
t.integer "threshold_replies"
|
||||||
|
t.bigint "fasp_provider_id", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["fasp_provider_id"], name: "index_fasp_subscriptions_on_fasp_provider_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "favourites", force: :cascade do |t|
|
create_table "favourites", force: :cascade do |t|
|
||||||
t.datetime "created_at", precision: nil, null: false
|
t.datetime "created_at", precision: nil, null: false
|
||||||
t.datetime "updated_at", precision: nil, null: false
|
t.datetime "updated_at", precision: nil, null: false
|
||||||
|
@ -1310,6 +1324,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_16_224825) do
|
||||||
add_foreign_key "custom_filters", "accounts", on_delete: :cascade
|
add_foreign_key "custom_filters", "accounts", on_delete: :cascade
|
||||||
add_foreign_key "email_domain_blocks", "email_domain_blocks", column: "parent_id", on_delete: :cascade
|
add_foreign_key "email_domain_blocks", "email_domain_blocks", column: "parent_id", on_delete: :cascade
|
||||||
add_foreign_key "fasp_debug_callbacks", "fasp_providers"
|
add_foreign_key "fasp_debug_callbacks", "fasp_providers"
|
||||||
|
add_foreign_key "fasp_subscriptions", "fasp_providers"
|
||||||
add_foreign_key "favourites", "accounts", name: "fk_5eb6c2b873", on_delete: :cascade
|
add_foreign_key "favourites", "accounts", name: "fk_5eb6c2b873", on_delete: :cascade
|
||||||
add_foreign_key "favourites", "statuses", name: "fk_b0e856845e", on_delete: :cascade
|
add_foreign_key "favourites", "statuses", name: "fk_b0e856845e", on_delete: :cascade
|
||||||
add_foreign_key "featured_tags", "accounts", on_delete: :cascade
|
add_foreign_key "featured_tags", "accounts", on_delete: :cascade
|
||||||
|
|
12
spec/fabricators/fasp/subscription_fabricator.rb
Normal file
12
spec/fabricators/fasp/subscription_fabricator.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Fabricator('Fasp::Subscription') do
|
||||||
|
category 'MyString'
|
||||||
|
subscription_type 'MyString'
|
||||||
|
max_batch_size 1
|
||||||
|
threshold_timeframe 1
|
||||||
|
threshold_shares 1
|
||||||
|
threshold_likes 1
|
||||||
|
threshold_replies 1
|
||||||
|
fasp_provider nil
|
||||||
|
end
|
7
spec/models/fasp/subscription_spec.rb
Normal file
7
spec/models/fasp/subscription_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Fasp::Subscription do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::Fasp::DataSharing::V0::BackfillRequests' do
|
||||||
|
describe 'GET /index' do
|
||||||
|
pending "add some examples (or delete) #{__FILE__}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::Fasp::DataSharing::V0::EventSubscriptions' do
|
||||||
|
describe 'GET /index' do
|
||||||
|
pending "add some examples (or delete) #{__FILE__}"
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue