has_many :media_attachments, dependent: :destroy
has_many :polls, dependent: :destroy
- # PuSH subscriptions
- has_many :subscriptions, dependent: :destroy
-
# Report relationships
has_many :reports, dependent: :destroy, inverse_of: :account
has_many :targeted_reports, class_name: 'Report', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account
+++ /dev/null
-# frozen_string_literal: true
-# == Schema Information
-#
-# Table name: subscriptions
-#
-# id :bigint(8) not null, primary key
-# callback_url :string default(""), not null
-# secret :string
-# expires_at :datetime
-# confirmed :boolean default(FALSE), not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# last_successful_delivery_at :datetime
-# domain :string
-# account_id :bigint(8) not null
-#
-
-class Subscription < ApplicationRecord
- MIN_EXPIRATION = 1.day.to_i
- MAX_EXPIRATION = 30.days.to_i
-
- belongs_to :account
-
- validates :callback_url, presence: true
- validates :callback_url, uniqueness: { scope: :account_id }
-
- scope :confirmed, -> { where(confirmed: true) }
- scope :future_expiration, -> { where(arel_table[:expires_at].gt(Time.now.utc)) }
- scope :expired, -> { where(arel_table[:expires_at].lt(Time.now.utc)) }
- scope :active, -> { confirmed.future_expiration }
-
- def lease_seconds=(value)
- self.expires_at = future_expiration(value)
- end
-
- def lease_seconds
- (expires_at - Time.now.utc).to_i
- end
-
- def expired?
- Time.now.utc > expires_at
- end
-
- before_validation :set_min_expiration
-
- private
-
- def future_expiration(value)
- Time.now.utc + future_offset(value).seconds
- end
-
- def future_offset(seconds)
- [
- [MIN_EXPIRATION, seconds.to_i].max,
- MAX_EXPIRATION,
- ].min
- end
-
- def set_min_expiration
- self.lease_seconds = 0 unless expires_at
- end
-end
+++ /dev/null
-# frozen_string_literal: true
-
-class SubscriptionPolicy < ApplicationPolicy
- def index?
- admin?
- end
-end
report_notes
scheduled_statuses
status_pins
- subscriptions
).freeze
ASSOCIATIONS_ON_DESTROY = %w(
sidekiq_options unique: :until_executed, retry: 0
- def perform
- Subscription.expired.in_batches.delete_all
- end
+ def perform; end
end
user_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'
class: Scheduler::UserCleanupScheduler
- subscriptions_cleanup_scheduler:
- cron: '<%= Random.rand(0..59) %> <%= Random.rand(1..3) %> * * 0'
- class: Scheduler::SubscriptionsCleanupScheduler
ip_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
class: Scheduler::IpCleanupScheduler
--- /dev/null
+# frozen_string_literal: true
+
+class DropSubscriptions < ActiveRecord::Migration[5.2]
+ def up
+ drop_table :subscriptions
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
t.index ["tag_id", "status_id"], name: "index_statuses_tags_on_tag_id_and_status_id", unique: true
end
- create_table "subscriptions", force: :cascade do |t|
- t.string "callback_url", default: "", null: false
- t.string "secret"
- t.datetime "expires_at"
- t.boolean "confirmed", default: false, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.datetime "last_successful_delivery_at"
- t.string "domain"
- t.bigint "account_id", null: false
- t.index ["account_id", "callback_url"], name: "index_subscriptions_on_account_id_and_callback_url", unique: true
- end
-
create_table "tags", force: :cascade do |t|
t.string "name", default: "", null: false
t.datetime "created_at", null: false
add_foreign_key "statuses", "statuses", column: "reblog_of_id", on_delete: :cascade
add_foreign_key "statuses_tags", "statuses", on_delete: :cascade
add_foreign_key "statuses_tags", "tags", name: "fk_3081861e21", on_delete: :cascade
- add_foreign_key "subscriptions", "accounts", name: "fk_9847d1cbb5", on_delete: :cascade
add_foreign_key "tombstones", "accounts", on_delete: :cascade
add_foreign_key "user_invite_requests", "users", on_delete: :cascade
add_foreign_key "users", "accounts", name: "fk_50500f500d", on_delete: :cascade
+++ /dev/null
-Fabricator(:subscription) do
- account
- callback_url "http://example.com/callback"
- secret "foobar"
- expires_at "2016-11-28 11:30:07"
- confirmed false
-end
+++ /dev/null
-require 'rails_helper'
-
-RSpec.describe Subscription, type: :model do
- let(:alice) { Fabricate(:account, username: 'alice') }
-
- subject { Fabricate(:subscription, account: alice) }
-
- describe '#expired?' do
- it 'return true when expires_at is past' do
- subject.expires_at = 2.days.ago
- expect(subject.expired?).to be true
- end
-
- it 'return false when expires_at is future' do
- subject.expires_at = 2.days.from_now
- expect(subject.expired?).to be false
- end
- end
-
- describe 'lease_seconds' do
- it 'returns the time remaining until expiration' do
- datetime = 1.day.from_now
- subscription = Subscription.new(expires_at: datetime)
- travel_to(datetime - 12.hours) do
- expect(subscription.lease_seconds).to eq(12.hours)
- end
- end
- end
-
- describe 'lease_seconds=' do
- it 'sets expires_at to min expiration when small value is provided' do
- subscription = Subscription.new
- datetime = 1.day.from_now
- too_low = Subscription::MIN_EXPIRATION - 1000
- travel_to(datetime) do
- subscription.lease_seconds = too_low
- end
-
- expected = datetime + Subscription::MIN_EXPIRATION.seconds
- expect(subscription.expires_at).to be_within(1.0).of(expected)
- end
-
- it 'sets expires_at to value when valid value is provided' do
- subscription = Subscription.new
- datetime = 1.day.from_now
- valid = Subscription::MIN_EXPIRATION + 1000
- travel_to(datetime) do
- subscription.lease_seconds = valid
- end
-
- expected = datetime + valid.seconds
- expect(subscription.expires_at).to be_within(1.0).of(expected)
- end
-
- it 'sets expires_at to max expiration when large value is provided' do
- subscription = Subscription.new
- datetime = 1.day.from_now
- too_high = Subscription::MAX_EXPIRATION + 1000
- travel_to(datetime) do
- subscription.lease_seconds = too_high
- end
-
- expected = datetime + Subscription::MAX_EXPIRATION.seconds
- expect(subscription.expires_at).to be_within(1.0).of(expected)
- end
- end
-end
+++ /dev/null
-# frozen_string_literal: true
-
-require 'rails_helper'
-require 'pundit/rspec'
-
-RSpec.describe SubscriptionPolicy do
- let(:subject) { described_class }
- let(:admin) { Fabricate(:user, admin: true).account }
- let(:john) { Fabricate(:user).account }
-
- permissions :index? do
- context 'admin?' do
- it 'permits' do
- expect(subject).to permit(admin, Subscription)
- end
- end
-
- context '!admin?' do
- it 'denies' do
- expect(subject).to_not permit(john, Subscription)
- end
- end
- end
-end
before do
allow(Redis.current).to receive_messages(publish: nil)
- stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
- stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
- Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
jeff.user.update(current_sign_in_at: Time.zone.now)
jeff.follow!(alice)
hank.follow!(alice)
let!(:bill) { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') }
before do
- stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
- stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
stub_request(:post, 'http://example2.com/inbox').to_return(status: 200)
- Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
jeff.follow!(alice)
hank.follow!(alice)
let!(:favourite) { Fabricate(:favourite, account: account) }
let!(:active_relationship) { Fabricate(:follow, account: account) }
let!(:passive_relationship) { Fabricate(:follow, target_account: account) }
- let!(:subscription) { Fabricate(:subscription, account: account) }
let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
account.favourites,
account.active_relationships,
account.passive_relationships,
- account.subscriptions
].map(&:count)
- }.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0])
+ }.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
end
it 'sends a delete actor activity to all known inboxes' do
let!(:favourite) { Fabricate(:favourite, account: remote_bob) }
let!(:active_relationship) { Fabricate(:follow, account: remote_bob, target_account: account) }
let!(:passive_relationship) { Fabricate(:follow, target_account: remote_bob) }
- let!(:subscription) { Fabricate(:subscription, account: remote_bob) }
it 'deletes associated records' do
is_expected.to change {
remote_bob.favourites,
remote_bob.active_relationships,
remote_bob.passive_relationships,
- remote_bob.subscriptions
].map(&:count)
- }.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0])
+ }.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
end
it 'sends a reject follow to follwer inboxes' do