Merge branch 'scalybiz-3.3' into HEAD

This commit is contained in:
khr 2021-06-10 06:46:34 +02:00
commit 8a8a6b559b
10 changed files with 81 additions and 14 deletions

View File

@ -86,7 +86,7 @@ class ComposeForm extends ImmutablePureComponent {
const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 4096 || (isOnlyWhitespace && !anyMedia));
}
handleSubmit = () => {
@ -196,6 +196,11 @@ class ComposeForm extends ImmutablePureComponent {
render () {
const { intl, onPaste, showSearch } = this.props;
const disabled = this.props.isSubmitting;
<<<<<<< HEAD
=======
const text = [this.props.spoilerText, countableText(this.props.text)].join('');
const disabledButton = disabled || this.props.isUploading || this.props.isChangingUpload || length(text) > 4096 || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
>>>>>>> scalybiz-3.2rc
let publishText = '';
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
@ -257,7 +262,7 @@ class ComposeForm extends ImmutablePureComponent {
<PrivacyDropdownContainer />
<SpoilerButtonContainer />
</div>
<div className='character-counter__wrapper'><CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} /></div>
<div className='character-counter__wrapper'><CharacterCounter max={4096} text={this.getFulltextForCharacterCounting()} /></div>
</div>
<div className='compose-form__publish'>

View File

@ -102,7 +102,7 @@ class Option extends React.PureComponent {
</label>
<div className='poll__cancel'>
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
<IconButton disabled={index < 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
</div>
</li>
);
@ -157,7 +157,7 @@ class PollForm extends ImmutablePureComponent {
</ul>
<div className='poll__footer'>
<button disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
<button disabled={options.size >= 12} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
<select value={expiresIn} onChange={this.handleSelectDuration}>

View File

@ -132,7 +132,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
# If there is at least one silent mention, then the status can be considered
# as a limited-audience status, and not strictly a direct message, but only
# if we considered a direct message in the first place
next unless @params[:visibility] == :direct
next unless @params[:visibility] == :direct && direct_message.nil?
@params[:visibility] = :limited
end
@ -143,7 +143,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
@mentions << Mention.new(account_id: @options[:delivered_to_account_id], silent: true)
return unless @params[:visibility] == :direct
return unless @params[:visibility] == :direct && direct_message.nil?
@params[:visibility] = :limited
end
@ -154,7 +154,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
delivered_to_account = Account.find(@options[:delivered_to_account_id])
@status.mentions.create(account: delivered_to_account, silent: true)
@status.update(visibility: :limited) if @status.direct_visibility?
@status.update(visibility: :limited) if @status.direct_visibility? && direct_message.nil?
return unless delivered_to_account.following?(@account)
@ -353,6 +353,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
:unlisted
elsif audience_to.include?(@account.followers_url)
:private
elsif direct_message == false
:limited
else
:direct
end
@ -363,6 +365,10 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
audience_to.include?(uri) || audience_cc.include?(uri)
end
def direct_message
@object['directMessage']
end
def replied_to_status
return @replied_to_status if defined?(@replied_to_status)

View File

@ -7,6 +7,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
}.freeze
CONTEXT_EXTENSION_MAP = {
direct_message: { 'litepub': 'http://litepub.social/ns#', 'directMessage': 'litepub:directMessage' },
manually_approves_followers: { 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers' },
sensitive: { 'sensitive' => 'as:sensitive' },
hashtag: { 'Hashtag' => 'as:Hashtag' },

View File

@ -88,9 +88,9 @@ class Account < ApplicationRecord
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
# Local user validations
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 100 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validates :display_name, length: { maximum: 100 }, if: -> { local? && will_save_change_to_display_name? }
validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class ActivityPub::NoteSerializer < ActivityPub::Serializer
context_extensions :atom_uri, :conversation, :sensitive, :voters_count
context_extensions :atom_uri, :conversation, :sensitive, :voters_count, :direct_message
attributes :id, :type, :summary,
:in_reply_to, :published, :url,
@ -12,6 +12,8 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
attribute :content
attribute :content_map, if: :language?
attribute :direct_message, if: :non_public?
has_many :media_attachments, key: :attachment
has_many :virtual_tags, key: :tag
@ -37,6 +39,14 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
object.spoiler_text.presence
end
def direct_message
object.direct_visibility?
end
def non_public?
!object.distributable?
end
def content
Formatter.instance.format(object)
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class PollValidator < ActiveModel::Validator
MAX_OPTIONS = 4
MAX_OPTIONS = 20
MAX_OPTION_CHARS = 50
MAX_EXPIRATION = 1.month.freeze
MIN_EXPIRATION = 5.minutes.freeze
@ -9,7 +9,6 @@ class PollValidator < ActiveModel::Validator
def validate(poll)
current_time = Time.now.utc
poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1
poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS
poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }
poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class StatusLengthValidator < ActiveModel::Validator
MAX_CHARS = 500
MAX_CHARS = 4096
URL_PLACEHOLDER = "\1#{'x' * 23}"
def validate(status)

View File

@ -9,7 +9,7 @@
.fields-row
.fields-row__column.fields-group.fields-row__column-6
= f.input :display_name, wrapper: :with_label, input_html: { maxlength: 30, data: { default: @account.username } }, hint: false
= f.input :display_name, wrapper: :with_label, input_html: { maxlength: 100, data: { default: @account.username } }, hint: false
= f.input :note, wrapper: :with_label, input_html: { maxlength: 500 }, hint: false
.fields-row

View File

@ -240,6 +240,31 @@ RSpec.describe ActivityPub::Activity::Create do
end
end
context 'limited when direct message assertion is false' do
let(:recipient) { Fabricate(:account) }
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
directMessage: false,
to: ActivityPub::TagManager.instance.uri_for(recipient),
tag: {
type: 'Mention',
href: ActivityPub::TagManager.instance.uri_for(recipient),
},
}
end
it 'creates status' do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.visibility).to eq 'limited'
end
end
context 'direct' do
let(:recipient) { Fabricate(:account) }
@ -264,6 +289,27 @@ RSpec.describe ActivityPub::Activity::Create do
end
end
context 'direct when direct message assertion is true' do
let(:recipient) { Fabricate(:account) }
let(:object_json) do
{
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
type: 'Note',
content: 'Lorem ipsum',
to: ActivityPub::TagManager.instance.uri_for(recipient),
directMessage: true,
}
end
it 'creates status' do
status = sender.statuses.first
expect(status).to_not be_nil
expect(status.visibility).to eq 'direct'
end
end
context 'as a reply' do
let(:original_status) { Fabricate(:status) }