Compare commits
11 commits
kb_develop
...
kbtopic-fi
Author | SHA1 | Date | |
---|---|---|---|
|
705a137b1f | ||
|
c3eb6d97e0 | ||
|
4a0bd8a0fd | ||
|
0c3fab40df | ||
|
c5a7a70355 | ||
|
2472c85096 | ||
|
dc97219d37 | ||
|
8c2519832e | ||
|
49ca570448 | ||
|
d1e6027cf6 | ||
|
7348de7e41 |
11 changed files with 119 additions and 30 deletions
42
CHANGELOG.md
42
CHANGELOG.md
|
@ -2,6 +2,48 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [4.3.2] - 2024-12-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `tootctl feeds vacuum` (#33065 by @ClearlyClaire)
|
||||||
|
- Add error message when user tries to follow their own account (#31910 by @lenikadali)
|
||||||
|
- Add client_secret_expires_at to OAuth Applications (#30317 by @ThisIsMissEm)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change design of Content Warnings and filters (#32543 by @ClearlyClaire)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix processing incoming post edits with mentions to unresolvable accounts (#33129 by @ClearlyClaire)
|
||||||
|
- Fix error when including multiple instances of `embed.js` (#33107 by @YKWeyer)
|
||||||
|
- Fix inactive users' timelines being backfilled on follow and unsuspend (#33094 by @ClearlyClaire)
|
||||||
|
- Fix direct inbox delivery pushing posts into inactive followers' timelines (#33067 by @ClearlyClaire)
|
||||||
|
- Fix `TagFollow` records not being correctly handled in account operations (#33063 by @ClearlyClaire)
|
||||||
|
- Fix pushing hashtag-followed posts to feeds of inactive users (#33018 by @Gargron)
|
||||||
|
- Fix duplicate notifications in notification groups when using slow mode (#33014 by @ClearlyClaire)
|
||||||
|
- Fix posts made in the future being allowed to trend (#32996 by @ClearlyClaire)
|
||||||
|
- Fix uploading higher-than-wide GIF profile picture with libvips enabled (#32911 by @ClearlyClaire)
|
||||||
|
- Fix domain attribution field having autocorrect and autocapitalize enabled (#32903 by @ClearlyClaire)
|
||||||
|
- Fix titles being escaped twice (#32889 by @ClearlyClaire)
|
||||||
|
- Fix list creation limit check (#32869 by @ClearlyClaire)
|
||||||
|
- Fix error in `tootctl email_domain_blocks` when supplying `--with-dns-records` (#32863 by @mjankowski)
|
||||||
|
- Fix `min_id` and `max_id` causing error in search API (#32857 by @Gargron)
|
||||||
|
- Fix inefficiencies when processing removal of posts that use featured tags (#32787 by @ClearlyClaire)
|
||||||
|
- Fix alt-text pop-in not using the translated description (#32766 by @ClearlyClaire)
|
||||||
|
- Fix preview cards with long titles erroneously causing layout changes (#32678 by @ClearlyClaire)
|
||||||
|
- Fix embed modal layout on mobile (#32641 by @DismalShadowX)
|
||||||
|
- Fix and improve batch attachment deletion handling when using OpenStack Swift (#32637 by @hugogameiro)
|
||||||
|
- Fix blocks not being applied on link timeline (#32625 by @tribela)
|
||||||
|
- Fix follow counters being incorrectly changed (#32622 by @oneiros)
|
||||||
|
- Fix 'unknown' media attachment type rendering (#32613 and #32713 by @ThisIsMissEm and @renatolond)
|
||||||
|
- Fix tl language native name (#32606 by @seav)
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Update dependencies
|
||||||
|
|
||||||
## [4.3.1] - 2024-10-21
|
## [4.3.1] - 2024-10-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -60,19 +60,13 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
|
||||||
already_accepted = friend.accepted?
|
already_accepted = friend.accepted?
|
||||||
friend.update!(passive_state: :pending, active_state: :idle, passive_follow_activity_id: @json['id'])
|
friend.update!(passive_state: :pending, active_state: :idle, passive_follow_activity_id: @json['id'])
|
||||||
else
|
else
|
||||||
@friend = FriendDomain.new(domain: @account.domain, passive_state: :pending, passive_follow_activity_id: @json['id'])
|
@friend = FriendDomain.create!(domain: @account.domain, passive_state: :pending, passive_follow_activity_id: @json['id'], inbox_url: @account.preferred_inbox_url)
|
||||||
@friend.inbox_url = @json['inboxUrl'].presence || @friend.default_inbox_url
|
|
||||||
@friend.save!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if already_accepted || Setting.unlocked_friend
|
friend.accept! if already_accepted || Setting.unlocked_friend
|
||||||
friend.accept!
|
|
||||||
|
|
||||||
# Notify for admin even if unlocked
|
# Notify for admin
|
||||||
notify_staff_about_pending_friend_server! unless already_accepted
|
notify_staff_about_pending_friend_server! unless already_accepted
|
||||||
else
|
|
||||||
notify_staff_about_pending_friend_server!
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def friend
|
def friend
|
||||||
|
|
|
@ -125,6 +125,8 @@ class FeedManager
|
||||||
# @param [Account] into_account
|
# @param [Account] into_account
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def merge_into_home(from_account, into_account)
|
def merge_into_home(from_account, into_account)
|
||||||
|
return unless into_account.user&.signed_in_recently?
|
||||||
|
|
||||||
timeline_key = key(:home, into_account.id)
|
timeline_key = key(:home, into_account.id)
|
||||||
aggregate = into_account.user&.aggregates_reblogs?
|
aggregate = into_account.user&.aggregates_reblogs?
|
||||||
query = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
|
query = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
|
||||||
|
@ -151,6 +153,8 @@ class FeedManager
|
||||||
# @param [List] list
|
# @param [List] list
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def merge_into_list(from_account, list)
|
def merge_into_list(from_account, list)
|
||||||
|
return unless list.account.user&.signed_in_recently?
|
||||||
|
|
||||||
timeline_key = key(:list, list.id)
|
timeline_key = key(:list, list.id)
|
||||||
aggregate = list.account.user&.aggregates_reblogs?
|
aggregate = list.account.user&.aggregates_reblogs?
|
||||||
query = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
|
query = from_account.statuses.list_eligible_visibility.includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4)
|
||||||
|
|
|
@ -116,6 +116,7 @@ class FriendDomain < ApplicationRecord
|
||||||
object: ActivityPub::TagManager::COLLECTIONS[:public],
|
object: ActivityPub::TagManager::COLLECTIONS[:public],
|
||||||
|
|
||||||
# Cannot use inbox_url method because this model also has inbox_url column
|
# Cannot use inbox_url method because this model also has inbox_url column
|
||||||
|
# This is deprecated property. Newer version's kmyblue will ignore it.
|
||||||
inboxUrl: "https://#{Rails.configuration.x.web_domain}/inbox",
|
inboxUrl: "https://#{Rails.configuration.x.web_domain}/inbox",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -261,6 +261,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
def update_mentions!
|
def update_mentions!
|
||||||
previous_mentions = @status.active_mentions.includes(:account).to_a
|
previous_mentions = @status.active_mentions.includes(:account).to_a
|
||||||
current_mentions = []
|
current_mentions = []
|
||||||
|
unresolved_mentions = []
|
||||||
|
|
||||||
@raw_mentions.each do |href|
|
@raw_mentions.each do |href|
|
||||||
next if href.blank?
|
next if href.blank?
|
||||||
|
@ -274,6 +275,12 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
mention ||= account.mentions.new(status: @status)
|
mention ||= account.mentions.new(status: @status)
|
||||||
|
|
||||||
current_mentions << mention
|
current_mentions << mention
|
||||||
|
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||||
|
# Since previous mentions are about already-known accounts,
|
||||||
|
# they don't try to resolve again and won't fall into this case.
|
||||||
|
# In other words, this failure case is only for new mentions and won't
|
||||||
|
# affect `removed_mentions` so they can safely be retried asynchronously
|
||||||
|
unresolved_mentions << href
|
||||||
end
|
end
|
||||||
|
|
||||||
current_mentions.each do |mention|
|
current_mentions.each do |mention|
|
||||||
|
@ -286,6 +293,11 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
removed_mentions = previous_mentions - current_mentions
|
removed_mentions = previous_mentions - current_mentions
|
||||||
|
|
||||||
Mention.where(id: removed_mentions.map(&:id)).update_all(silent: true) unless removed_mentions.empty?
|
Mention.where(id: removed_mentions.map(&:id)).update_all(silent: true) unless removed_mentions.empty?
|
||||||
|
|
||||||
|
# Queue unresolved mentions for later
|
||||||
|
unresolved_mentions.uniq.each do |uri|
|
||||||
|
MentionResolveWorker.perform_in(rand(30...600).seconds, @status.id, uri, { 'request_id' => @request_id })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_emojis!
|
def update_emojis!
|
||||||
|
|
|
@ -59,7 +59,7 @@ services:
|
||||||
web:
|
web:
|
||||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||||
build: .
|
build: .
|
||||||
image: kmyblue:16.0-dev
|
image: kmyblue:16.1
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec puma -C config/puma.rb
|
command: bundle exec puma -C config/puma.rb
|
||||||
|
@ -83,7 +83,7 @@ services:
|
||||||
build:
|
build:
|
||||||
dockerfile: ./streaming/Dockerfile
|
dockerfile: ./streaming/Dockerfile
|
||||||
context: .
|
context: .
|
||||||
image: kmyblue-streaming:16.0-dev
|
image: kmyblue-streaming:16.1
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: node ./streaming/index.js
|
command: node ./streaming/index.js
|
||||||
|
@ -101,7 +101,7 @@ services:
|
||||||
|
|
||||||
sidekiq:
|
sidekiq:
|
||||||
build: .
|
build: .
|
||||||
image: kmyblue:16.0-dev
|
image: kmyblue:16.1
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec sidekiq
|
command: bundle exec sidekiq
|
||||||
|
|
|
@ -5,6 +5,7 @@ require_relative 'base'
|
||||||
module Mastodon::CLI
|
module Mastodon::CLI
|
||||||
class Feeds < Base
|
class Feeds < Base
|
||||||
include Redisable
|
include Redisable
|
||||||
|
include DatabaseHelper
|
||||||
|
|
||||||
option :all, type: :boolean, default: false
|
option :all, type: :boolean, default: false
|
||||||
option :concurrency, type: :numeric, default: 5, aliases: [:c]
|
option :concurrency, type: :numeric, default: 5, aliases: [:c]
|
||||||
|
@ -59,6 +60,38 @@ module Mastodon::CLI
|
||||||
say('OK', :green)
|
say('OK', :green)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc 'vacuum', 'Remove home feeds of inactive users from Redis'
|
||||||
|
long_desc <<-LONG_DESC
|
||||||
|
Running this task should not be needed in most cases, as Mastodon will
|
||||||
|
automatically clean up feeds from inactive accounts every day.
|
||||||
|
|
||||||
|
However, this task is more aggressive in order to clean up feeds that
|
||||||
|
may have been missed because of bugs or database mishaps.
|
||||||
|
LONG_DESC
|
||||||
|
def vacuum
|
||||||
|
with_read_replica do
|
||||||
|
say('Deleting orphaned home feeds…')
|
||||||
|
redis.scan_each(match: 'feed:home:*').each_slice(1000) do |keys|
|
||||||
|
ids = keys.map { |key| key.split(':')[2] }.compact_blank
|
||||||
|
|
||||||
|
known_ids = User.confirmed.signed_in_recently.where(account_id: ids).pluck(:account_id)
|
||||||
|
|
||||||
|
keys_to_delete = keys.filter { |key| known_ids.exclude?(key.split(':')[2]&.to_i) }
|
||||||
|
redis.del(keys_to_delete)
|
||||||
|
end
|
||||||
|
|
||||||
|
say('Deleting orphaned list feeds…')
|
||||||
|
redis.scan_each(match: 'feed:list:*').each_slice(1000) do |keys|
|
||||||
|
ids = keys.map { |key| key.split(':')[2] }.compact_blank
|
||||||
|
|
||||||
|
known_ids = List.where(account_id: User.confirmed.signed_in_recently.select(:account_id)).where(id: ids).pluck(:id)
|
||||||
|
|
||||||
|
keys_to_delete = keys.filter { |key| known_ids.exclude?(key.split(':')[2]&.to_i) }
|
||||||
|
redis.del(keys_to_delete)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def active_user_accounts
|
def active_user_accounts
|
||||||
|
|
|
@ -13,13 +13,13 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def kmyblue_minor
|
def kmyblue_minor
|
||||||
0
|
1
|
||||||
end
|
end
|
||||||
|
|
||||||
def kmyblue_flag
|
def kmyblue_flag
|
||||||
# 'LTS'
|
# 'LTS'
|
||||||
'dev'
|
# 'dev'
|
||||||
# nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def major
|
def major
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
(function (allowedPrefixes) {
|
||||||
const allowedPrefixes = (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.dataset.allowedPrefixes) ? document.currentScript.dataset.allowedPrefixes.split(' ') : [];
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,4 +124,4 @@ const allowedPrefixes = (document.currentScript && document.currentScript.tagNam
|
||||||
container.appendChild(iframe);
|
container.appendChild(iframe);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})();
|
})((document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.dataset.allowedPrefixes) ? document.currentScript.dataset.allowedPrefixes.split(' ') : []);
|
||||||
|
|
|
@ -380,11 +380,10 @@ RSpec.describe ActivityPub::Activity::Follow do
|
||||||
context 'when given a friend server' do
|
context 'when given a friend server' do
|
||||||
subject { described_class.new(json, sender) }
|
subject { described_class.new(json, sender) }
|
||||||
|
|
||||||
let(:sender) { Fabricate(:account, domain: 'abc.com', url: 'https://abc.com/#actor') }
|
let(:sender) { Fabricate(:account, domain: 'abc.com', url: 'https://abc.com/#actor', shared_inbox_url: 'https://abc.com/shared_inbox') }
|
||||||
let!(:friend) { Fabricate(:friend_domain, domain: 'abc.com', inbox_url: 'https://example.com/inbox', passive_state: :idle) }
|
let!(:friend) { Fabricate(:friend_domain, domain: 'abc.com', inbox_url: 'https://example.com/inbox', passive_state: :idle) }
|
||||||
let!(:owner_user) { Fabricate(:user, role: UserRole.find_by(name: 'Owner')) }
|
let!(:owner_user) { Fabricate(:user, role: UserRole.find_by(name: 'Owner')) }
|
||||||
let!(:patch_user) { Fabricate(:user, role: Fabricate(:user_role, name: 'OhagiOps', permissions: UserRole::FLAGS[:manage_federation])) }
|
let!(:patch_user) { Fabricate(:user, role: Fabricate(:user_role, name: 'OhagiOps', permissions: UserRole::FLAGS[:manage_federation])) }
|
||||||
let(:inbox_url) { nil }
|
|
||||||
|
|
||||||
let(:json) do
|
let(:json) do
|
||||||
{
|
{
|
||||||
|
@ -393,7 +392,6 @@ RSpec.describe ActivityPub::Activity::Follow do
|
||||||
type: 'Follow',
|
type: 'Follow',
|
||||||
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
||||||
object: 'https://www.w3.org/ns/activitystreams#Public',
|
object: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
inboxUrl: inbox_url,
|
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -415,25 +413,34 @@ RSpec.describe ActivityPub::Activity::Follow do
|
||||||
expect(friend).to_not be_nil
|
expect(friend).to_not be_nil
|
||||||
expect(friend.they_are_pending?).to be true
|
expect(friend.they_are_pending?).to be true
|
||||||
expect(friend.passive_follow_activity_id).to eq 'foo'
|
expect(friend.passive_follow_activity_id).to eq 'foo'
|
||||||
expect(friend.inbox_url).to eq 'https://abc.com/inbox'
|
expect(friend.inbox_url).to eq 'https://abc.com/shared_inbox'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when no record and inbox_url is specified' do
|
context 'when old spec which no record and inbox_url is specified' do
|
||||||
let(:inbox_url) { 'https://ohagi.com/inbox' }
|
let(:json) do
|
||||||
|
{
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
id: 'foo',
|
||||||
|
type: 'Follow',
|
||||||
|
actor: ActivityPub::TagManager.instance.uri_for(sender),
|
||||||
|
object: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
|
inboxUrl: 'https://evil.org/bad_inbox',
|
||||||
|
}.with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
friend.destroy!
|
friend.destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'marks the friend as pending' do
|
it 'marks the friend as pending but inboxUrl is not working' do
|
||||||
subject.perform
|
subject.perform
|
||||||
|
|
||||||
friend = FriendDomain.find_by(domain: 'abc.com')
|
friend = FriendDomain.find_by(domain: 'abc.com')
|
||||||
expect(friend).to_not be_nil
|
expect(friend).to_not be_nil
|
||||||
expect(friend.they_are_pending?).to be true
|
expect(friend.they_are_pending?).to be true
|
||||||
expect(friend.passive_follow_activity_id).to eq 'foo'
|
expect(friend.passive_follow_activity_id).to eq 'foo'
|
||||||
expect(friend.inbox_url).to eq 'https://ohagi.com/inbox'
|
expect(friend.inbox_url).to eq 'https://abc.com/shared_inbox'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ RSpec.describe FriendDomain do
|
||||||
type: 'Follow',
|
type: 'Follow',
|
||||||
actor: 'https://cb6e6126.ngrok.io/actor',
|
actor: 'https://cb6e6126.ngrok.io/actor',
|
||||||
object: 'https://www.w3.org/ns/activitystreams#Public',
|
object: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
inboxUrl: 'https://cb6e6126.ngrok.io/inbox',
|
|
||||||
}))).to have_been_made.once
|
}))).to have_been_made.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue