Compare commits
18 commits
kb_develop
...
releases/1
Author | SHA1 | Date | |
---|---|---|---|
|
fcb81c4eac | ||
|
2de228f84f | ||
|
bc968abfbe | ||
|
83900d2581 | ||
|
e53c6b13eb | ||
|
13e5eed811 | ||
|
af7aae66f8 | ||
|
f16bd4fcb1 | ||
|
305021b543 | ||
|
aef6d96d55 | ||
|
de9ab9042f | ||
|
f096449e7f | ||
|
08d6cf2a38 | ||
|
a670b10552 | ||
|
2db9d6ac92 | ||
|
490923d104 | ||
|
704e6264fd | ||
|
78948753b1 |
19 changed files with 100 additions and 22 deletions
|
@ -5,6 +5,7 @@
|
||||||
kmyblueフォークは、以下の方の貢献によって成り立っています。
|
kmyblueフォークは、以下の方の貢献によって成り立っています。
|
||||||
本家Mastodonの貢献者については、`AUTHORS.md`をご覧ください。
|
本家Mastodonの貢献者については、`AUTHORS.md`をご覧ください。
|
||||||
|
|
||||||
|
- [aoisensi](https://github.com/aoisensi)
|
||||||
- [KMY](https://github.com/kmycode)
|
- [KMY](https://github.com/kmycode)
|
||||||
- [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS)
|
- [S-H-GAMELINKS](https://github.com/S-H-GAMELINKS)
|
||||||
- [Yuicho](https://github.com/yuicho)
|
- [Yuicho](https://github.com/yuicho)
|
||||||
|
@ -12,6 +13,6 @@ kmyblueフォークは、以下の方の貢献によって成り立っていま
|
||||||
## 特記
|
## 特記
|
||||||
|
|
||||||
kmyblueフォークの開発にあたって、API・Activity仕様の設計(一部機能については内部仕様)策定の過程で下記リポジトリのコードを参考にしました。
|
kmyblueフォークの開発にあたって、API・Activity仕様の設計(一部機能については内部仕様)策定の過程で下記リポジトリのコードを参考にしました。
|
||||||
kmyblueフォークに直接貢献したわけではありませんが、以下のリポジトリにある絵文字リアクション機能・検索範囲機能のコードのうち、ごく一部ではありますがkmyblueへ転写した箇所がございますため、お名前記載させていただきます。
|
kmyblueフォークに直接貢献したわけではありませんが、以下のリポジトリにある絵文字リアクション機能・検索範囲機能のコードのうち一部にkmyblueへ転写した箇所がございますため、お名前記載させていただきます。
|
||||||
|
|
||||||
- [Fedibird](https://github.com/fedibird/mastodon)
|
- [Fedibird](https://github.com/fedibird/mastodon)
|
||||||
|
|
|
@ -34,7 +34,8 @@ module Admin
|
||||||
UpdateStatusService.new.call(
|
UpdateStatusService.new.call(
|
||||||
@status,
|
@status,
|
||||||
edit_status_account_id,
|
edit_status_account_id,
|
||||||
no_history: true
|
no_history: true,
|
||||||
|
bypass_validation: true
|
||||||
)
|
)
|
||||||
log_action(:remove_history, @status)
|
log_action(:remove_history, @status)
|
||||||
redirect_to admin_account_status_path
|
redirect_to admin_account_status_path
|
||||||
|
@ -46,7 +47,8 @@ module Admin
|
||||||
@status,
|
@status,
|
||||||
edit_status_account_id,
|
edit_status_account_id,
|
||||||
media_ids: [],
|
media_ids: [],
|
||||||
media_attributes: []
|
media_attributes: [],
|
||||||
|
bypass_validation: true
|
||||||
)
|
)
|
||||||
log_action(:remove_media, @status)
|
log_action(:remove_media, @status)
|
||||||
redirect_to admin_account_status_path
|
redirect_to admin_account_status_path
|
||||||
|
@ -57,7 +59,8 @@ module Admin
|
||||||
UpdateStatusService.new.call(
|
UpdateStatusService.new.call(
|
||||||
@status,
|
@status,
|
||||||
edit_status_account_id,
|
edit_status_account_id,
|
||||||
sensitive: true
|
sensitive: true,
|
||||||
|
bypass_validation: true
|
||||||
)
|
)
|
||||||
log_action(:force_sensitive, @status)
|
log_action(:force_sensitive, @status)
|
||||||
redirect_to admin_account_status_path
|
redirect_to admin_account_status_path
|
||||||
|
@ -68,7 +71,8 @@ module Admin
|
||||||
UpdateStatusService.new.call(
|
UpdateStatusService.new.call(
|
||||||
@status,
|
@status,
|
||||||
edit_status_account_id,
|
edit_status_account_id,
|
||||||
spoiler_text: 'CW'
|
spoiler_text: 'CW',
|
||||||
|
bypass_validation: true
|
||||||
)
|
)
|
||||||
log_action(:force_cw, @status)
|
log_action(:force_cw, @status)
|
||||||
redirect_to admin_account_status_path
|
redirect_to admin_account_status_path
|
||||||
|
|
|
@ -337,7 +337,7 @@ export function uploadCompose(files) {
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
dispatch(uploadComposeSuccess(data, file));
|
dispatch(uploadComposeSuccess(data, file));
|
||||||
|
|
||||||
if (defaultSensitive && !spoiler) {
|
if (defaultSensitive && !spoiler && (media.size + i) === 0) {
|
||||||
dispatch(changeComposeSpoilerness());
|
dispatch(changeComposeSpoilerness());
|
||||||
}
|
}
|
||||||
} else if (status === 202) {
|
} else if (status === 202) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ export function importFetchedStatuses(statuses) {
|
||||||
processStatus(status.reblog);
|
processStatus(status.reblog);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.quote && status.quote.id) {
|
if (status.quote && status.quote.id && !getState().getIn(['statuses', status.id])) {
|
||||||
processStatus(status.quote);
|
processStatus(status.quote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -629,7 +629,7 @@ export default function compose(state = initialState, action) {
|
||||||
map.set('spoiler', true);
|
map.set('spoiler', true);
|
||||||
map.set('spoiler_text', action.spoiler_text);
|
map.set('spoiler_text', action.spoiler_text);
|
||||||
} else {
|
} else {
|
||||||
map.set('spoiler', false);
|
map.set('spoiler', action.status.get('sensitive'));
|
||||||
map.set('spoiler_text', '');
|
map.set('spoiler_text', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
input[type='text']:not(#cw-spoiler-input),
|
input[type='text']:not(#cw-spoiler-input),
|
||||||
input[type='search'],
|
input[type='search'],
|
||||||
input[type='number'],
|
input[type='number'],
|
||||||
|
textarea[id='upload-modal__description'],
|
||||||
input:not([type]) {
|
input:not([type]) {
|
||||||
background: $ui-base-color !important;
|
background: $ui-base-color !important;
|
||||||
color: $primary-text-color !important;
|
color: $primary-text-color !important;
|
||||||
|
@ -24,6 +25,7 @@ input:not([type]) {
|
||||||
color: $classic-secondary-color !important;
|
color: $classic-secondary-color !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compose-form__warning,
|
||||||
.modal-root__modal {
|
.modal-root__modal {
|
||||||
background: lighten($classic-base-color, 12%);
|
background: lighten($classic-base-color, 12%);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4142,6 +4142,10 @@ a.status-card {
|
||||||
.announcements {
|
.announcements {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
.announcements__pagination > * {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Admin::StatusBatchAction
|
||||||
authorize([:admin, status], :update?)
|
authorize([:admin, status], :update?)
|
||||||
|
|
||||||
if target_account.local?
|
if target_account.local?
|
||||||
UpdateStatusService.new.call(status, representative_account.id, sensitive: true)
|
UpdateStatusService.new.call(status, representative_account.id, sensitive: true, bypass_validation: true)
|
||||||
else
|
else
|
||||||
status.update(sensitive: true)
|
status.update(sensitive: true)
|
||||||
end
|
end
|
||||||
|
@ -119,7 +119,7 @@ class Admin::StatusBatchAction
|
||||||
status_text = "#{status.spoiler_text}\n\n#{status_text}" if status.spoiler_text
|
status_text = "#{status.spoiler_text}\n\n#{status_text}" if status.spoiler_text
|
||||||
|
|
||||||
if target_account.local?
|
if target_account.local?
|
||||||
UpdateStatusService.new.call(status, representative_account.id, spoiler_text: 'CW', text: status_text)
|
UpdateStatusService.new.call(status, representative_account.id, spoiler_text: 'CW', text: status_text, bypass_validation: true)
|
||||||
else
|
else
|
||||||
status.update(spoiler_text: 'CW', text: status_text)
|
status.update(spoiler_text: 'CW', text: status_text)
|
||||||
end
|
end
|
||||||
|
|
|
@ -186,6 +186,10 @@ module Account::Interactions
|
||||||
active_relationships.exists?(target_account: other_account)
|
active_relationships.exists?(target_account: other_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def following_or_self?(other_account)
|
||||||
|
id == other_account.id || following?(other_account)
|
||||||
|
end
|
||||||
|
|
||||||
def following_anyone?
|
def following_anyone?
|
||||||
active_relationships.exists?
|
active_relationships.exists?
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ class InstanceInfo < ApplicationRecord
|
||||||
meisskey
|
meisskey
|
||||||
misskey
|
misskey
|
||||||
pleroma
|
pleroma
|
||||||
|
rosekey
|
||||||
sharkey
|
sharkey
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Trends::Tags < Trends::Base
|
||||||
|
|
||||||
def register(status, at_time = Time.now.utc)
|
def register(status, at_time = Time.now.utc)
|
||||||
return unless !status.reblog? && %i(public public_unlisted login).include?(status.visibility.to_sym) && !status.account.silenced?
|
return unless !status.reblog? && %i(public public_unlisted login).include?(status.visibility.to_sym) && !status.account.silenced?
|
||||||
|
return if !status.account.local? && DomainBlock.block_trends?(status.account.domain)
|
||||||
|
|
||||||
status.tags.each do |tag|
|
status.tags.each do |tag|
|
||||||
add(tag, status.account_id, at_time) if tag.usable?
|
add(tag, status.account_id, at_time) if tag.usable?
|
||||||
|
|
|
@ -56,14 +56,14 @@ class ApproveAppealService < BaseService
|
||||||
def undo_mark_statuses_as_sensitive!
|
def undo_mark_statuses_as_sensitive!
|
||||||
representative_account = Account.representative
|
representative_account = Account.representative
|
||||||
@strike.statuses.includes(:media_attachments).find_each do |status|
|
@strike.statuses.includes(:media_attachments).find_each do |status|
|
||||||
UpdateStatusService.new.call(status, representative_account.id, sensitive: false) if status.with_media?
|
UpdateStatusService.new.call(status, representative_account.id, sensitive: false, bypass_validation: true) if status.with_media?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def undo_force_cw!
|
def undo_force_cw!
|
||||||
representative_account = Account.representative
|
representative_account = Account.representative
|
||||||
@strike.statuses.includes(:media_attachments).find_each do |status|
|
@strike.statuses.includes(:media_attachments).find_each do |status|
|
||||||
UpdateStatusService.new.call(status, representative_account.id, spoiler_text: '')
|
UpdateStatusService.new.call(status, representative_account.id, spoiler_text: '', bypass_validation: true) if status.spoiler_text.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -248,12 +248,12 @@ class PostStatusService < BaseService
|
||||||
def mention_to_stranger?
|
def mention_to_stranger?
|
||||||
return @mention_to_stranger if defined?(@mention_to_stranger)
|
return @mention_to_stranger if defined?(@mention_to_stranger)
|
||||||
|
|
||||||
@mention_to_stranger = @status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @account.id && !mentioned_account.following?(@account) } ||
|
@mention_to_stranger = @status.mentions.map(&:account).to_a.any? { |mentioned_account| !mentioned_account.following_or_self?(@account) } ||
|
||||||
(@in_reply_to && @in_reply_to.account.id != @account.id && !@in_reply_to.account.following?(@account))
|
(@in_reply_to && !@in_reply_to.account.following_or_self?(@account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def reference_to_stranger?
|
def reference_to_stranger?
|
||||||
referred_statuses.any? { |status| !status.account.following?(@account) }
|
referred_statuses.any? { |status| !status.account.following_or_self?(@account) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def referred_statuses
|
def referred_statuses
|
||||||
|
|
|
@ -84,6 +84,7 @@ class UpdateStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_status!
|
def validate_status!
|
||||||
|
return if @options[:bypass_validation]
|
||||||
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
|
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if Admin::NgWord.reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
|
||||||
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text] || '')
|
raise Mastodon::ValidationError, I18n.t('statuses.too_many_hashtags') if Admin::NgWord.hashtag_reject_with_extractor?(@options[:text] || '')
|
||||||
raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@options[:text] || '')
|
raise Mastodon::ValidationError, I18n.t('statuses.too_many_mentions') if Admin::NgWord.mention_reject_with_extractor?(@options[:text] || '')
|
||||||
|
@ -91,10 +92,13 @@ class UpdateStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_status_mentions!
|
def validate_status_mentions!
|
||||||
|
return if @options[:bypass_validation]
|
||||||
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if (mention_to_stranger? || reference_to_stranger?) && Setting.stranger_mention_from_local_ng && Admin::NgWord.stranger_mention_reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
|
raise Mastodon::ValidationError, I18n.t('statuses.contains_ng_words') if (mention_to_stranger? || reference_to_stranger?) && Setting.stranger_mention_from_local_ng && Admin::NgWord.stranger_mention_reject?("#{@options[:spoiler_text]}\n#{@options[:text]}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_status_ng_rules!
|
def validate_status_ng_rules!
|
||||||
|
return if @options[:bypass_validation]
|
||||||
|
|
||||||
result = check_invalid_status_for_ng_rule! @status.account,
|
result = check_invalid_status_for_ng_rule! @status.account,
|
||||||
reaction_type: 'edit',
|
reaction_type: 'edit',
|
||||||
spoiler_text: @options.key?(:spoiler_text) ? (@options[:spoiler_text] || '') : @status.spoiler_text,
|
spoiler_text: @options.key?(:spoiler_text) ? (@options[:spoiler_text] || '') : @status.spoiler_text,
|
||||||
|
@ -119,12 +123,12 @@ class UpdateStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def mention_to_stranger?
|
def mention_to_stranger?
|
||||||
@status.mentions.map(&:account).to_a.any? { |mentioned_account| mentioned_account.id != @status.account.id && !mentioned_account.following?(@status.account) } ||
|
@status.mentions.map(&:account).to_a.any? { |mentioned_account| !mentioned_account.following_or_self?(@status.account) } ||
|
||||||
(@status.thread.present? && @status.thread.account.id != @status.account.id && !@status.thread.account.following?(@status.account))
|
(@status.thread.present? && !@status.thread.account.following_or_self?(@status.account))
|
||||||
end
|
end
|
||||||
|
|
||||||
def reference_to_stranger?
|
def reference_to_stranger?
|
||||||
referred_statuses.any? { |status| !status.account.following?(@status.account) }
|
referred_statuses.any? { |status| !status.account.following_or_self?(@status.account) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def referred_statuses
|
def referred_statuses
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ActivityPub::FetchInstanceInfoWorker
|
||||||
update_info!(link)
|
update_info!(link)
|
||||||
|
|
||||||
true
|
true
|
||||||
rescue Mastodon::UnexpectedResponseError
|
rescue
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,13 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def kmyblue_minor
|
def kmyblue_minor
|
||||||
0
|
4
|
||||||
end
|
end
|
||||||
|
|
||||||
def kmyblue_flag
|
def kmyblue_flag
|
||||||
# 'LTS'
|
# 'LTS'
|
||||||
'dev'
|
# 'dev'
|
||||||
# nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def major
|
def major
|
||||||
|
|
|
@ -23,6 +23,33 @@ RSpec.describe Trends::Tags do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#register' do
|
||||||
|
let(:tag) { Fabricate(:tag, usable: true) }
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
let(:status) { Fabricate(:status, account: account, tags: [tag], created_at: at_time, updated_at: at_time) }
|
||||||
|
|
||||||
|
it 'records history' do
|
||||||
|
subject.register(status, at_time)
|
||||||
|
expect(tag.history.get(at_time).accounts).to eq 1
|
||||||
|
expect(tag.history.get(at_time).uses).to eq 1
|
||||||
|
expect(subject.send(:recently_used_ids, at_time)).to eq [tag.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is rejected appending trends' do
|
||||||
|
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Fabricate(:domain_block, domain: 'example.com', block_trends: true, severity: :noop)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not record history' do
|
||||||
|
subject.register(status, at_time)
|
||||||
|
expect(tag.history.get(at_time).accounts).to eq 0
|
||||||
|
expect(tag.history.get(at_time).uses).to eq 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#query' do
|
describe '#query' do
|
||||||
it 'returns a composable query scope' do
|
it 'returns a composable query scope' do
|
||||||
expect(subject.query).to be_a Trends::Query
|
expect(subject.query).to be_a Trends::Query
|
||||||
|
|
|
@ -663,6 +663,17 @@ RSpec.describe PostStatusService, type: :service do
|
||||||
expect(status.text).to eq text
|
expect(status.text).to eq text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not hit ng words for mention to self' do
|
||||||
|
account = Fabricate(:account, username: 'cool', domain: nil)
|
||||||
|
text = 'ng word test @cool'
|
||||||
|
Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save
|
||||||
|
|
||||||
|
status = subject.call(account, text: text)
|
||||||
|
|
||||||
|
expect(status).to be_persisted
|
||||||
|
expect(status.text).to eq text
|
||||||
|
end
|
||||||
|
|
||||||
it 'hit ng words for reply' do
|
it 'hit ng words for reply' do
|
||||||
account = Fabricate(:account)
|
account = Fabricate(:account)
|
||||||
text = 'ng word test'
|
text = 'ng word test'
|
||||||
|
@ -721,6 +732,18 @@ RSpec.describe PostStatusService, type: :service do
|
||||||
expect(status.text).to eq text
|
expect(status.text).to eq text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not hit ng words for reference to self' do
|
||||||
|
target_status = Fabricate(:status)
|
||||||
|
account = target_status.account
|
||||||
|
text = "ng word test BT: #{ActivityPub::TagManager.instance.uri_for(target_status)}"
|
||||||
|
Form::AdminSettings.new(ng_words_for_stranger_mention: 'test', stranger_mention_from_local_ng: '1').save
|
||||||
|
|
||||||
|
status = subject.call(account, text: text)
|
||||||
|
|
||||||
|
expect(status).to be_persisted
|
||||||
|
expect(status.text).to eq text
|
||||||
|
end
|
||||||
|
|
||||||
it 'using hashtag under limit' do
|
it 'using hashtag under limit' do
|
||||||
account = Fabricate(:account)
|
account = Fabricate(:account)
|
||||||
text = '#a #b'
|
text = '#a #b'
|
||||||
|
|
|
@ -277,6 +277,13 @@ RSpec.describe UpdateStatusService, type: :service do
|
||||||
expect { subject.call(status, status.account_id, text: text) }.to raise_error(Mastodon::ValidationError)
|
expect { subject.call(status, status.account_id, text: text) }.to raise_error(Mastodon::ValidationError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'bypass ng words' do
|
||||||
|
text = 'ng word test'
|
||||||
|
Form::AdminSettings.new(ng_words: 'test').save
|
||||||
|
|
||||||
|
expect { subject.call(status, status.account_id, text: text, bypass_validation: true) }.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
it 'not hit ng words' do
|
it 'not hit ng words' do
|
||||||
text = 'ng word aiueo'
|
text = 'ng word aiueo'
|
||||||
Form::AdminSettings.new(ng_words: 'test').save
|
Form::AdminSettings.new(ng_words: 'test').save
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue