Compare commits
No commits in common. "098fcb19789b82d1a765ad807e3154ae29dda03d" and "34ab5fd793f13d08c277ccfac914c79e20517cd3" have entirely different histories.
098fcb1978
...
34ab5fd793
|
@ -167,45 +167,8 @@ jobs:
|
||||||
name: Create database
|
name: Create database
|
||||||
command: ./bin/rails db:create
|
command: ./bin/rails db:create
|
||||||
- run:
|
- run:
|
||||||
command: ./bin/rails db:migrate VERSION=20171010025614
|
name: Run migrations
|
||||||
name: Run migrations up to v2.0.0
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails tests:migrations:populate_v2
|
|
||||||
name: Populate database with test data
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails db:migrate
|
command: ./bin/rails db:migrate
|
||||||
name: Run all remaining migrations
|
|
||||||
|
|
||||||
test-two-step-migrations:
|
|
||||||
<<: *defaults
|
|
||||||
docker:
|
|
||||||
- image: circleci/ruby:2.7-buster-node
|
|
||||||
environment: *ruby_environment
|
|
||||||
- image: circleci/postgres:12.2
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: root
|
|
||||||
POSTGRES_HOST_AUTH_METHOD: trust
|
|
||||||
- image: circleci/redis:5-alpine
|
|
||||||
steps:
|
|
||||||
- *attach_workspace
|
|
||||||
- *install_system_dependencies
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails db:create
|
|
||||||
name: Create database
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails db:migrate VERSION=20171010025614
|
|
||||||
name: Run migrations up to v2.0.0
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails tests:migrations:populate_v2
|
|
||||||
name: Populate database with test data
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails db:migrate
|
|
||||||
name: Run all pre-deployment migrations
|
|
||||||
evironment:
|
|
||||||
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
|
|
||||||
- run:
|
|
||||||
command: ./bin/rails db:migrate
|
|
||||||
name: Run all post-deployment remaining migrations
|
|
||||||
|
|
||||||
test-ruby2.7:
|
test-ruby2.7:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
|
@ -275,9 +238,6 @@ workflows:
|
||||||
- test-migrations:
|
- test-migrations:
|
||||||
requires:
|
requires:
|
||||||
- install-ruby2.7
|
- install-ruby2.7
|
||||||
- test-two-step-migrations:
|
|
||||||
requires:
|
|
||||||
- install-ruby2.7
|
|
||||||
- test-ruby2.7:
|
- test-ruby2.7:
|
||||||
requires:
|
requires:
|
||||||
- install-ruby2.7
|
- install-ruby2.7
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
name: Build container image
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "main"
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
jobs:
|
|
||||||
build-image:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: docker/setup-buildx-action@v1
|
|
||||||
- uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- uses: docker/metadata-action@v3
|
|
||||||
id: meta
|
|
||||||
with:
|
|
||||||
images: tootsuite/mastodon
|
|
||||||
flavor: |
|
|
||||||
latest=auto
|
|
||||||
tags: |
|
|
||||||
type=edge,branch=main
|
|
||||||
type=semver,pattern={{ raw }}
|
|
||||||
- uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
cache-from: type=registry,ref=tootsuite/mastodon:latest
|
|
||||||
cache-to: type=inline
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -3,18 +3,6 @@ Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [3.4.5] - 2022-01-31
|
|
||||||
### Added
|
|
||||||
- Add more advanced migration tests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17393))
|
|
||||||
- Add github workflow to build Docker images ([unasuke](https://github.com/mastodon/mastodon/pull/16973), [Gargron](https://github.com/mastodon/mastodon/pull/16980), [Gargron](https://github.com/mastodon/mastodon/pull/17000))
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Fix some old migrations failing when skipping releases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17394))
|
|
||||||
- Fix migrations script failing in certain edge cases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17398))
|
|
||||||
- Fix Docker build ([tribela](https://github.com/mastodon/mastodon/pull/17188))
|
|
||||||
- Fix Ruby 3.0 dependencies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16723))
|
|
||||||
- Fix followers synchronization mechanism ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16510))
|
|
||||||
|
|
||||||
## [3.4.4] - 2021-11-26
|
## [3.4.4] - 2021-11-26
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ RUN npm install -g yarn && \
|
||||||
COPY Gemfile* package.json yarn.lock /opt/mastodon/
|
COPY Gemfile* package.json yarn.lock /opt/mastodon/
|
||||||
|
|
||||||
RUN cd /opt/mastodon && \
|
RUN cd /opt/mastodon && \
|
||||||
bundle config set --local deployment 'true' && \
|
bundle config set deployment 'true' && \
|
||||||
bundle config set --local without 'development test' && \
|
bundle config set without 'development test' && \
|
||||||
bundle install -j"$(nproc)" && \
|
bundle install -j"$(nproc)" && \
|
||||||
yarn install --pure-lockfile
|
yarn install --pure-lockfile
|
||||||
|
|
||||||
|
|
|
@ -545,9 +545,8 @@ GEM
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.7.0, < 2.0)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
ruby-saml (1.13.0)
|
ruby-saml (1.11.0)
|
||||||
nokogiri (>= 1.10.5)
|
nokogiri (>= 1.5.10)
|
||||||
rexml
|
|
||||||
ruby2_keywords (0.0.4)
|
ruby2_keywords (0.0.4)
|
||||||
rufus-scheduler (3.6.0)
|
rufus-scheduler (3.6.0)
|
||||||
fugit (~> 1.1, >= 1.1.6)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
|
|
|
@ -60,7 +60,6 @@ class Account < ApplicationRecord
|
||||||
|
|
||||||
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
|
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
|
||||||
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[[:word:]]+)?)/i
|
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[[:word:]]+)?)/i
|
||||||
URL_PREFIX_RE = /\Ahttp(s?):\/\/[^\/]+/
|
|
||||||
|
|
||||||
include AccountAssociations
|
include AccountAssociations
|
||||||
include AccountAvatar
|
include AccountAvatar
|
||||||
|
@ -380,7 +379,7 @@ class Account < ApplicationRecord
|
||||||
def synchronization_uri_prefix
|
def synchronization_uri_prefix
|
||||||
return 'local' if local?
|
return 'local' if local?
|
||||||
|
|
||||||
@synchronization_uri_prefix ||= "#{uri[URL_PREFIX_RE]}/"
|
@synchronization_uri_prefix ||= uri[/http(s?):\/\/[^\/]+\//]
|
||||||
end
|
end
|
||||||
|
|
||||||
class Field < ActiveModelSerializers::Model
|
class Field < ActiveModelSerializers::Model
|
||||||
|
|
|
@ -251,13 +251,10 @@ module AccountInteractions
|
||||||
.where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
|
.where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote_followers_hash(url)
|
def remote_followers_hash(url_prefix)
|
||||||
url_prefix = url[Account::URL_PREFIX_RE]
|
Rails.cache.fetch("followers_hash:#{id}:#{url_prefix}") do
|
||||||
return if url_prefix.blank?
|
|
||||||
|
|
||||||
Rails.cache.fetch("followers_hash:#{id}:#{url_prefix}/") do
|
|
||||||
digest = "\x00" * 32
|
digest = "\x00" * 32
|
||||||
followers.where(Account.arel_table[:uri].matches("#{Account.sanitize_sql_like(url_prefix)}/%", false, true)).or(followers.where(uri: url_prefix)).pluck_each(:uri) do |uri|
|
followers.where(Account.arel_table[:uri].matches(url_prefix + '%', false, true)).pluck_each(:uri) do |uri|
|
||||||
Xorcist.xor!(digest, Digest::SHA256.digest(uri))
|
Xorcist.xor!(digest, Digest::SHA256.digest(uri))
|
||||||
end
|
end
|
||||||
digest.unpack('H*')[0]
|
digest.unpack('H*')[0]
|
||||||
|
|
|
@ -44,7 +44,11 @@ class ActivityPub::DeliveryWorker
|
||||||
end
|
end
|
||||||
|
|
||||||
def synchronization_header
|
def synchronization_header
|
||||||
"collectionId=\"#{account_followers_url(@source_account)}\", digest=\"#{@source_account.remote_followers_hash(@inbox_url)}\", url=\"#{account_followers_synchronization_url(@source_account)}\""
|
"collectionId=\"#{account_followers_url(@source_account)}\", digest=\"#{@source_account.remote_followers_hash(inbox_url_prefix)}\", url=\"#{account_followers_synchronization_url(@source_account)}\""
|
||||||
|
end
|
||||||
|
|
||||||
|
def inbox_url_prefix
|
||||||
|
@inbox_url[/http(s?):\/\/[^\/]+\//]
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_request
|
def perform_request
|
||||||
|
|
|
@ -1,46 +1,6 @@
|
||||||
class RemoveFauxRemoteAccountDuplicates < ActiveRecord::Migration[5.2]
|
class RemoveFauxRemoteAccountDuplicates < ActiveRecord::Migration[5.2]
|
||||||
disable_ddl_transaction!
|
disable_ddl_transaction!
|
||||||
|
|
||||||
class StreamEntry < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
belongs_to :account, inverse_of: :stream_entries
|
|
||||||
end
|
|
||||||
|
|
||||||
class Status < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
belongs_to :account, inverse_of: :statuses
|
|
||||||
has_many :favourites, inverse_of: :status, dependent: :destroy
|
|
||||||
has_many :mentions, dependent: :destroy, inverse_of: :status
|
|
||||||
end
|
|
||||||
|
|
||||||
class Favourite < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
belongs_to :account, inverse_of: :favourites
|
|
||||||
belongs_to :status, inverse_of: :favourites
|
|
||||||
end
|
|
||||||
|
|
||||||
class Mention < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
belongs_to :account, inverse_of: :mentions
|
|
||||||
belongs_to :status
|
|
||||||
end
|
|
||||||
|
|
||||||
class Notification < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
belongs_to :account, optional: true
|
|
||||||
belongs_to :from_account, class_name: 'Account', optional: true
|
|
||||||
belongs_to :activity, polymorphic: true, optional: true
|
|
||||||
end
|
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
has_many :stream_entries, inverse_of: :account, dependent: :destroy
|
|
||||||
has_many :statuses, inverse_of: :account, dependent: :destroy
|
|
||||||
has_many :favourites, inverse_of: :account, dependent: :destroy
|
|
||||||
has_many :mentions, inverse_of: :account, dependent: :destroy
|
|
||||||
has_many :notifications, inverse_of: :account, dependent: :destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
def up
|
def up
|
||||||
local_domain = Rails.configuration.x.local_domain
|
local_domain = Rails.configuration.x.local_domain
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
class AddInstanceActor < ActiveRecord::Migration[5.2]
|
class AddInstanceActor < ActiveRecord::Migration[5.2]
|
||||||
class Account < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
validates :username, uniqueness: { scope: :domain, case_sensitive: false }
|
|
||||||
end
|
|
||||||
|
|
||||||
def up
|
def up
|
||||||
Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain)
|
Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
class UpdatePtLocales < ActiveRecord::Migration[5.2]
|
class UpdatePtLocales < ActiveRecord::Migration[5.2]
|
||||||
class User < ApplicationRecord
|
|
||||||
# Dummy class, to make migration possible across version changes
|
|
||||||
end
|
|
||||||
|
|
||||||
disable_ddl_transaction!
|
disable_ddl_transaction!
|
||||||
|
|
||||||
def up
|
def up
|
||||||
|
|
|
@ -20,7 +20,7 @@ FROM (
|
||||||
HAVING count(follows.id) >= 5
|
HAVING count(follows.id) >= 5
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT accounts.id AS account_id,
|
SELECT accounts.id AS account_id,
|
||||||
sum(status_stats.reblogs_count + status_stats.favourites_count) / (1.0 + sum(status_stats.reblogs_count + status_stats.favourites_count)) AS rank,
|
sum(reblogs_count + favourites_count) / (1.0 + sum(reblogs_count + favourites_count)) AS rank,
|
||||||
'most_interactions' AS reason
|
'most_interactions' AS reason
|
||||||
FROM status_stats
|
FROM status_stats
|
||||||
INNER JOIN statuses ON statuses.id = status_stats.status_id
|
INNER JOIN statuses ON statuses.id = status_stats.status_id
|
||||||
|
@ -32,7 +32,7 @@ FROM (
|
||||||
AND accounts.locked = 'f'
|
AND accounts.locked = 'f'
|
||||||
AND accounts.discoverable = 't'
|
AND accounts.discoverable = 't'
|
||||||
GROUP BY accounts.id
|
GROUP BY accounts.id
|
||||||
HAVING sum(status_stats.reblogs_count + status_stats.favourites_count) >= 5
|
HAVING sum(reblogs_count + favourites_count) >= 5
|
||||||
) t0
|
) t0
|
||||||
GROUP BY account_id
|
GROUP BY account_id
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
|
|
|
@ -18,7 +18,7 @@ FROM (
|
||||||
HAVING count(follows.id) >= 5
|
HAVING count(follows.id) >= 5
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT account_summaries.account_id AS account_id,
|
SELECT account_summaries.account_id AS account_id,
|
||||||
sum(status_stats.reblogs_count + status_stats.favourites_count) / (1.0 + sum(status_stats.reblogs_count + status_stats.favourites_count)) AS rank,
|
sum(reblogs_count + favourites_count) / (1.0 + sum(reblogs_count + favourites_count)) AS rank,
|
||||||
'most_interactions' AS reason
|
'most_interactions' AS reason
|
||||||
FROM status_stats
|
FROM status_stats
|
||||||
INNER JOIN statuses ON statuses.id = status_stats.status_id
|
INNER JOIN statuses ON statuses.id = status_stats.status_id
|
||||||
|
@ -28,7 +28,7 @@ FROM (
|
||||||
AND account_summaries.sensitive = 'f'
|
AND account_summaries.sensitive = 'f'
|
||||||
AND follow_recommendation_suppressions.id IS NULL
|
AND follow_recommendation_suppressions.id IS NULL
|
||||||
GROUP BY account_summaries.account_id
|
GROUP BY account_summaries.account_id
|
||||||
HAVING sum(status_stats.reblogs_count + status_stats.favourites_count) >= 5
|
HAVING sum(reblogs_count + favourites_count) >= 5
|
||||||
) t0
|
) t0
|
||||||
GROUP BY account_id
|
GROUP BY account_id
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
|
|
|
@ -43,7 +43,7 @@ services:
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
image: tootsuite/mastodon:v3.4.5
|
image: tootsuite/mastodon
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
||||||
|
@ -63,7 +63,7 @@ services:
|
||||||
|
|
||||||
streaming:
|
streaming:
|
||||||
build: .
|
build: .
|
||||||
image: tootsuite/mastodon:v3.4.5
|
image: tootsuite/mastodon
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: node ./streaming
|
command: node ./streaming
|
||||||
|
@ -80,7 +80,7 @@ services:
|
||||||
|
|
||||||
sidekiq:
|
sidekiq:
|
||||||
build: .
|
build: .
|
||||||
image: tootsuite/mastodon:v3.4.5
|
image: tootsuite/mastodon
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec sidekiq
|
command: bundle exec sidekiq
|
||||||
|
|
|
@ -295,7 +295,7 @@ module Mastodon
|
||||||
table = Arel::Table.new(table_name)
|
table = Arel::Table.new(table_name)
|
||||||
|
|
||||||
total = estimate_rows_in_table(table_name).to_i
|
total = estimate_rows_in_table(table_name).to_i
|
||||||
if total < 1
|
if total == 0
|
||||||
count_arel = table.project(Arel.star.count.as('count'))
|
count_arel = table.project(Arel.star.count.as('count'))
|
||||||
count_arel = yield table, count_arel if block_given?
|
count_arel = yield table, count_arel if block_given?
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
5
|
4
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
namespace :tests do
|
|
||||||
namespace :migrations do
|
|
||||||
desc 'Populate the database with test data for 2.0.0'
|
|
||||||
task populate_v2: :environment do
|
|
||||||
admin_key = OpenSSL::PKey::RSA.new(2048)
|
|
||||||
user_key = OpenSSL::PKey::RSA.new(2048)
|
|
||||||
remote_key = OpenSSL::PKey::RSA.new(2048)
|
|
||||||
remote_key2 = OpenSSL::PKey::RSA.new(2048)
|
|
||||||
remote_key3 = OpenSSL::PKey::RSA.new(2048)
|
|
||||||
admin_private_key = ActiveRecord::Base.connection.quote(admin_key.to_pem)
|
|
||||||
admin_public_key = ActiveRecord::Base.connection.quote(admin_key.public_key.to_pem)
|
|
||||||
user_private_key = ActiveRecord::Base.connection.quote(user_key.to_pem)
|
|
||||||
user_public_key = ActiveRecord::Base.connection.quote(user_key.public_key.to_pem)
|
|
||||||
remote_public_key = ActiveRecord::Base.connection.quote(remote_key.public_key.to_pem)
|
|
||||||
remote_public_key2 = ActiveRecord::Base.connection.quote(remote_key2.public_key.to_pem)
|
|
||||||
remote_public_key_ap = ActiveRecord::Base.connection.quote(remote_key3.public_key.to_pem)
|
|
||||||
local_domain = ActiveRecord::Base.connection.quote(Rails.configuration.x.local_domain)
|
|
||||||
|
|
||||||
ActiveRecord::Base.connection.execute(<<~SQL)
|
|
||||||
-- accounts
|
|
||||||
|
|
||||||
INSERT INTO "accounts"
|
|
||||||
(id, username, domain, private_key, public_key, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 'admin', NULL, #{admin_private_key}, #{admin_public_key}, now(), now()),
|
|
||||||
(2, 'user', NULL, #{user_private_key}, #{user_public_key}, now(), now());
|
|
||||||
|
|
||||||
INSERT INTO "accounts"
|
|
||||||
(id, username, domain, private_key, public_key, created_at, updated_at, remote_url, salmon_url)
|
|
||||||
VALUES
|
|
||||||
(3, 'remote', 'remote.com', NULL, #{remote_public_key}, now(), now(),
|
|
||||||
'https://remote.com/@remote', 'https://remote.com/salmon/1'),
|
|
||||||
(4, 'Remote', 'remote.com', NULL, #{remote_public_key}, now(), now(),
|
|
||||||
'https://remote.com/@Remote', 'https://remote.com/salmon/1'),
|
|
||||||
(5, 'REMOTE', 'Remote.com', NULL, #{remote_public_key2}, now(), now(),
|
|
||||||
'https://remote.com/stale/@REMOTE', 'https://remote.com/stale/salmon/1');
|
|
||||||
|
|
||||||
INSERT INTO "accounts"
|
|
||||||
(id, username, domain, private_key, public_key, created_at, updated_at, protocol, inbox_url, outbox_url, followers_url)
|
|
||||||
VALUES
|
|
||||||
(6, 'bob', 'activitypub.com', NULL, #{remote_public_key_ap}, now(), now(),
|
|
||||||
1, 'https://activitypub.com/users/bob/inbox', 'https://activitypub.com/users/bob/outbox', 'https://activitypub.com/users/bob/followers');
|
|
||||||
|
|
||||||
INSERT INTO "accounts"
|
|
||||||
(id, username, domain, private_key, public_key, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(7, 'user', #{local_domain}, #{user_private_key}, #{user_public_key}, now(), now()),
|
|
||||||
(8, 'pt_user', NULL, #{user_private_key}, #{user_public_key}, now(), now());
|
|
||||||
|
|
||||||
-- users
|
|
||||||
|
|
||||||
INSERT INTO "users"
|
|
||||||
(id, account_id, email, created_at, updated_at, admin)
|
|
||||||
VALUES
|
|
||||||
(1, 1, 'admin@localhost', now(), now(), true),
|
|
||||||
(2, 2, 'user@localhost', now(), now(), false);
|
|
||||||
|
|
||||||
INSERT INTO "users"
|
|
||||||
(id, account_id, email, created_at, updated_at, admin, locale)
|
|
||||||
VALUES
|
|
||||||
(3, 7, 'ptuser@localhost', now(), now(), false, 'pt');
|
|
||||||
|
|
||||||
-- statuses
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, text, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 1, 'test', now(), now()),
|
|
||||||
(2, 1, '@remote@remote.com hello', now(), now()),
|
|
||||||
(3, 1, '@Remote@remote.com hello', now(), now()),
|
|
||||||
(4, 1, '@REMOTE@remote.com hello', now(), now());
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, text, created_at, updated_at, uri, local)
|
|
||||||
VALUES
|
|
||||||
(5, 1, 'activitypub status', now(), now(), 'https://localhost/users/admin/statuses/4', true);
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, text, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(6, 3, 'test', now(), now());
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, text, created_at, updated_at, in_reply_to_id, in_reply_to_account_id)
|
|
||||||
VALUES
|
|
||||||
(7, 4, '@admin hello', now(), now(), 3, 1);
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, text, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(8, 5, 'test', now(), now());
|
|
||||||
|
|
||||||
INSERT INTO "statuses"
|
|
||||||
(id, account_id, reblog_of_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(9, 1, 2, now(), now());
|
|
||||||
|
|
||||||
-- mentions (from previous statuses)
|
|
||||||
|
|
||||||
INSERT INTO "mentions"
|
|
||||||
(status_id, account_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(2, 3, now(), now()),
|
|
||||||
(3, 4, now(), now()),
|
|
||||||
(4, 5, now(), now());
|
|
||||||
|
|
||||||
-- stream entries
|
|
||||||
|
|
||||||
INSERT INTO "stream_entries"
|
|
||||||
(activity_id, account_id, activity_type, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 1, 'status', now(), now()),
|
|
||||||
(2, 1, 'status', now(), now()),
|
|
||||||
(3, 1, 'status', now(), now()),
|
|
||||||
(4, 1, 'status', now(), now()),
|
|
||||||
(5, 1, 'status', now(), now()),
|
|
||||||
(6, 3, 'status', now(), now()),
|
|
||||||
(7, 4, 'status', now(), now()),
|
|
||||||
(8, 5, 'status', now(), now()),
|
|
||||||
(9, 1, 'status', now(), now());
|
|
||||||
|
|
||||||
|
|
||||||
-- custom emoji
|
|
||||||
|
|
||||||
INSERT INTO "custom_emojis"
|
|
||||||
(shortcode, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
('test', now(), now()),
|
|
||||||
('Test', now(), now()),
|
|
||||||
('blobcat', now(), now());
|
|
||||||
|
|
||||||
INSERT INTO "custom_emojis"
|
|
||||||
(shortcode, domain, uri, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
('blobcat', 'remote.org', 'https://remote.org/emoji/blobcat', now(), now()),
|
|
||||||
('blobcat', 'Remote.org', 'https://remote.org/emoji/blobcat', now(), now()),
|
|
||||||
('Blobcat', 'remote.org', 'https://remote.org/emoji/Blobcat', now(), now());
|
|
||||||
|
|
||||||
-- favourites
|
|
||||||
|
|
||||||
INSERT INTO "favourites"
|
|
||||||
(account_id, status_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 1, now(), now()),
|
|
||||||
(1, 7, now(), now()),
|
|
||||||
(4, 1, now(), now()),
|
|
||||||
(3, 1, now(), now()),
|
|
||||||
(5, 1, now(), now());
|
|
||||||
|
|
||||||
-- pinned statuses
|
|
||||||
|
|
||||||
INSERT INTO "status_pins"
|
|
||||||
(account_id, status_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 1, now(), now()),
|
|
||||||
(3, 6, now(), now()),
|
|
||||||
(4, 7, now(), now());
|
|
||||||
|
|
||||||
-- follows
|
|
||||||
|
|
||||||
INSERT INTO "follows"
|
|
||||||
(account_id, target_account_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(1, 5, now(), now()),
|
|
||||||
(6, 2, now(), now()),
|
|
||||||
(5, 2, now(), now()),
|
|
||||||
(6, 1, now(), now());
|
|
||||||
|
|
||||||
-- follow requests
|
|
||||||
|
|
||||||
INSERT INTO "follow_requests"
|
|
||||||
(account_id, target_account_id, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(2, 5, now(), now()),
|
|
||||||
(5, 1, now(), now());
|
|
||||||
SQL
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -539,57 +539,46 @@ describe AccountInteractions do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#remote_followers_hash' do
|
describe '#followers_hash' do
|
||||||
let(:me) { Fabricate(:account, username: 'Me') }
|
let(:me) { Fabricate(:account, username: 'Me') }
|
||||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||||
let(:remote_2) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
|
let(:remote_2) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
|
||||||
let(:remote_3) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') }
|
let(:remote_3) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
||||||
let(:remote_4) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
remote_1.follow!(me)
|
remote_1.follow!(me)
|
||||||
remote_2.follow!(me)
|
remote_2.follow!(me)
|
||||||
remote_3.follow!(me)
|
remote_3.follow!(me)
|
||||||
remote_4.follow!(me)
|
|
||||||
me.follow!(remote_1)
|
me.follow!(remote_1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns correct hash for remote domains' do
|
context 'on a local user' do
|
||||||
expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
|
it 'returns correct hash for remote domains' do
|
||||||
expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e'
|
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||||
expect(me.remote_followers_hash('https://foo.org.evil.com/')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e'
|
||||||
expect(me.remote_followers_hash('https://foo')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
end
|
||||||
|
|
||||||
|
it 'invalidates cache as needed when removing or adding followers' do
|
||||||
|
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||||
|
remote_1.unfollow!(me)
|
||||||
|
expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
|
||||||
|
remote_1.follow!(me)
|
||||||
|
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'invalidates cache as needed when removing or adding followers' do
|
context 'on a remote user' do
|
||||||
expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
|
it 'returns correct hash for remote domains' do
|
||||||
remote_3.unfollow!(me)
|
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
end
|
||||||
remote_1.unfollow!(me)
|
|
||||||
expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
|
|
||||||
remote_1.follow!(me)
|
|
||||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#local_followers_hash' do
|
it 'invalidates cache as needed when removing or adding followers' do
|
||||||
let(:me) { Fabricate(:account, username: 'Me') }
|
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
me.unfollow!(remote_1)
|
||||||
|
expect(remote_1.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||||
before do
|
me.follow!(remote_1)
|
||||||
me.follow!(remote_1)
|
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns correct hash for local users' do
|
|
||||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'invalidates cache as needed when removing or adding followers' do
|
|
||||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
|
||||||
me.unfollow!(remote_1)
|
|
||||||
expect(remote_1.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
|
||||||
me.follow!(remote_1)
|
|
||||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe ActivityPub::DeliveryWorker do
|
||||||
let(:payload) { 'test' }
|
let(:payload) { 'test' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/').and_return('somehash')
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'perform' do
|
describe 'perform' do
|
||||||
|
|
Loading…
Reference in New Issue