0
0
Fork 0

Use likes and shares totalItems on status creations and updates (#32620)

This commit is contained in:
Jonny Saunders 2024-10-27 21:55:18 -07:00 committed by GitHub
parent 77cd16f4ee
commit 9074c1fac9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 326 additions and 14 deletions

View file

@ -928,6 +928,32 @@ RSpec.describe ActivityPub::Activity::Create do
expect(poll.votes.first).to be_nil
end
end
context 'with counts' do
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
likes: {
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/likes'].join,
type: 'Collection',
totalItems: 50,
},
shares: {
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/shares'].join,
type: 'Collection',
totalItems: 100,
},
}
end
it 'uses the counts from the created object' do
status = sender.statuses.first
expect(status.untrusted_favourites_count).to eq 50
expect(status.untrusted_reblogs_count).to eq 100
end
end
end
context 'when object URI uses bearcaps' do

View file

@ -115,5 +115,69 @@ RSpec.describe ActivityPub::Activity::Update do
expect(status.edited_at).to be_nil
end
end
context 'with a Note object' do
let(:updated) { nil }
let(:favourites) { 50 }
let(:reblogs) { 100 }
let!(:status) { Fabricate(:status, uri: 'https://example.com/statuses/poll', account: sender) }
let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Update',
actor: sender.uri,
object: {
type: 'Note',
id: status.uri,
content: 'Foo',
updated: updated,
likes: {
id: "#{status.uri}/likes",
type: 'Collection',
totalItems: favourites,
},
shares: {
id: "#{status.uri}/shares",
type: 'Collection',
totalItems: reblogs,
},
},
}.with_indifferent_access
end
shared_examples 'updates counts' do
it 'updates the reblog count' do
expect(status.untrusted_reblogs_count).to eq reblogs
end
it 'updates the favourites count' do
expect(status.untrusted_favourites_count).to eq favourites
end
end
context 'with an implicit update' do
before do
status.update!(uri: ActivityPub::TagManager.instance.uri_for(status))
subject.perform
end
it_behaves_like 'updates counts'
end
context 'with an explicit update' do
let(:favourites) { 150 }
let(:reblogs) { 200 }
let(:updated) { Time.now.utc.iso8601 }
before do
status.update!(uri: ActivityPub::TagManager.instance.uri_for(status))
subject.perform
end
it_behaves_like 'updates counts'
end
end
end
end

View file

@ -164,6 +164,31 @@ RSpec.describe Status do
end
end
describe '#untrusted_reblogs_count' do
before do
alice.update(domain: 'example.com')
subject.status_stat.tap do |status_stat|
status_stat.untrusted_reblogs_count = 0
status_stat.save
end
subject.save
end
it 'is incremented by the number of reblogs' do
Fabricate(:status, account: bob, reblog: subject)
Fabricate(:status, account: alice, reblog: subject)
expect(subject.untrusted_reblogs_count).to eq 2
end
it 'is decremented when reblog is removed' do
reblog = Fabricate(:status, account: bob, reblog: subject)
expect(subject.untrusted_reblogs_count).to eq 1
reblog.destroy
expect(subject.untrusted_reblogs_count).to eq 0
end
end
describe '#replies_count' do
it 'is the number of replies' do
Fabricate(:status, account: bob, thread: subject)
@ -194,6 +219,31 @@ RSpec.describe Status do
end
end
describe '#untrusted_favourites_count' do
before do
alice.update(domain: 'example.com')
subject.status_stat.tap do |status_stat|
status_stat.untrusted_favourites_count = 0
status_stat.save
end
subject.save
end
it 'is incremented by favorites' do
Fabricate(:favourite, account: bob, status: subject)
Fabricate(:favourite, account: alice, status: subject)
expect(subject.untrusted_favourites_count).to eq 2
end
it 'is decremented when favourite is removed' do
favourite = Fabricate(:favourite, account: bob, status: subject)
expect(subject.untrusted_favourites_count).to eq 1
favourite.destroy
expect(subject.untrusted_favourites_count).to eq 0
end
end
describe '#proper' do
it 'is itself for original statuses' do
expect(subject.proper).to eq subject

View file

@ -39,6 +39,42 @@ RSpec.describe 'API V1 Trends Statuses' do
end
Trends::Statuses.new(threshold: 1, decay_threshold: -1).refresh
end
context 'with a comically inflated external interactions count' do
def prepare_fake_trends
fake_remote_account = Fabricate(:account, domain: 'other.com')
fake_status = Fabricate(:status, account: fake_remote_account, text: 'I am a big faker', trendable: true, language: 'en')
fake_status.status_stat.tap do |status_stat|
status_stat.reblogs_count = 0
status_stat.favourites_count = 0
status_stat.untrusted_reblogs_count = 1_000_000_000
status_stat.untrusted_favourites_count = 1_000_000_000
status_stat.save
end
real_remote_account = Fabricate(:account, domain: 'other.com')
real_status = Fabricate(:status, account: real_remote_account, text: 'I make real friends online', trendable: true, language: 'en')
real_status.status_stat.tap do |status_stat|
status_stat.reblogs_count = 10
status_stat.favourites_count = 10
status_stat.untrusted_reblogs_count = 10
status_stat.untrusted_favourites_count = 10
status_stat.save
end
Trends.statuses.add(fake_status, 100)
Trends.statuses.add(real_status, 101)
Trends::Statuses.new(threshold: 1, decay_threshold: 1).refresh
end
it 'ignores the feeble attempts at deception' do
prepare_fake_trends
stub_const('Api::BaseController::DEFAULT_STATUSES_LIMIT', 10)
get '/api/v1/trends/statuses'
expect(response).to have_http_status(200)
expect(response.parsed_body.length).to eq(1)
expect(response.parsed_body[0]['content']).to eq('I make real friends online')
end
end
end
end
end

View file

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe REST::StatusSerializer do
subject do
serialized_record_json(
status,
described_class,
options: {
scope: current_user,
scope_name: :current_user,
}
)
end
let(:current_user) { Fabricate(:user) }
let(:alice) { Fabricate(:account, username: 'alice') }
let(:bob) { Fabricate(:account, username: 'bob', domain: 'other.com') }
let(:status) { Fabricate(:status, account: alice) }
context 'with a remote status' do
let(:status) { Fabricate(:status, account: bob) }
before do
status.status_stat.tap do |status_stat|
status_stat.reblogs_count = 10
status_stat.favourites_count = 20
status_stat.save
end
end
context 'with only trusted counts' do
it 'shows the trusted counts' do
expect(subject['reblogs_count']).to eq(10)
expect(subject['favourites_count']).to eq(20)
end
end
context 'with untrusted counts' do
before do
status.status_stat.tap do |status_stat|
status_stat.untrusted_reblogs_count = 30
status_stat.untrusted_favourites_count = 40
status_stat.save
end
end
it 'shows the untrusted counts' do
expect(subject['reblogs_count']).to eq(30)
expect(subject['favourites_count']).to eq(40)
end
end
end
end

View file

@ -34,8 +34,8 @@ RSpec.configure do |config|
end
end
def serialized_record_json(record, serializer, adapter: nil)
options = { serializer: serializer }
def serialized_record_json(record, serializer, adapter: nil, options: {})
options[:serializer] = serializer
options[:adapter] = adapter if adapter.present?
JSON.parse(
ActiveModelSerializers::SerializableResource.new(