From 92c2bbcc0af4ac46d22e2e449d1f174eb85f8647 Mon Sep 17 00:00:00 2001
From: noellabo <noel.yoshiba@gmail.com>
Date: Sat, 26 Nov 2022 06:16:44 +0900
Subject: [PATCH] Add MAX_TOOT_CHARS

---
 .../mastodon/features/compose/components/compose_form.js    | 6 +++---
 app/javascript/mastodon/initial_state.js                    | 2 ++
 app/serializers/initial_state_serializer.rb                 | 6 +++++-
 app/serializers/rest/instance_serializer.rb                 | 6 +++++-
 app/validators/status_length_validator.rb                   | 2 +-
 5 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index d33ce6d0b..123fc117a 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -27,7 +27,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 import { length } from 'stringz';
 import { countableText } from '../util/counter';
 import Icon from 'mastodon/components/icon';
-import { disablePost } from '../../../initial_state';
+import { disablePost, maxChars } from '../../../initial_state';
 
 const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
 
@@ -99,7 +99,7 @@ class ComposeForm extends ImmutablePureComponent {
     const noVisibility = prohibitedVisibilities?.includes(privacy);
     const ngWords = prohibitedWords.some( word => text.includes(word) || spoilerText?.includes(word) );
 
-    return !(isSubmitting || isUploading || isChangingUpload || isCircleUnselected || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia) || noVisibility || ngWords);
+    return !(isSubmitting || isUploading || isChangingUpload || isCircleUnselected || length(fulltext) > maxChars || (isOnlyWhitespace && !anyMedia) || noVisibility || ngWords);
   }
 
   handleSubmit = () => {
@@ -275,7 +275,7 @@ class ComposeForm extends ImmutablePureComponent {
             <DateTimeButtonContainer />
             <SearchabilityDropdownContainer />
           </div>
-          <div className='character-counter__wrapper'><CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} /></div>
+          <div className='character-counter__wrapper'><CharacterCounter max={maxChars} text={this.getFulltextForCharacterCounting()} /></div>
         </div>
 
         <CircleDropdownContainer />
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 2767d4c3d..48d9fe4ae 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -64,4 +64,6 @@ export const disableDomainBlock = getMeta('disable_domain_block');
 export const disableClearAllNotifications = getMeta('disable_clear_all_notifications');
 export const disableAccountDelete = getMeta('disable_account_delete');
 
+export const maxChars = initialState?.max_toot_chars ?? 500;
+
 export default initialState;
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index 1c19192dd..6239e89c3 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -2,7 +2,7 @@
 
 class InitialStateSerializer < ActiveModel::Serializer
   attributes :meta, :compose, :search, :accounts, :lists,
-             :media_attachments, :status_references, :settings
+             :media_attachments, :status_references, :settings, :max_toot_chars
 
   has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer
 
@@ -114,6 +114,10 @@ class InitialStateSerializer < ActiveModel::Serializer
     store
   end
 
+  def max_toot_chars
+    StatusLengthValidator::MAX_CHARS
+  end
+
   def search
     store = {}
     store[:default_searchability] = object.current_account.user.setting_default_search_searchability if object.current_account
diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb
index 2c8834775..331f345ff 100644
--- a/app/serializers/rest/instance_serializer.rb
+++ b/app/serializers/rest/instance_serializer.rb
@@ -4,7 +4,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
   include RoutingHelper
 
   attributes :uri, :title, :short_description, :description, :email,
-             :version, :urls, :stats, :thumbnail,
+             :version, :urls, :stats, :thumbnail, :max_toot_chars,
              :languages, :registrations, :approval_required, :invites_enabled,
              :configuration,
              :feature_quote, :fedibird_capabilities
@@ -19,6 +19,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer
     Rails.configuration.x.local_domain
   end
 
+  def max_toot_chars
+    StatusLengthValidator::MAX_CHARS
+  end
+
   def title
     Setting.site_title
   end
diff --git a/app/validators/status_length_validator.rb b/app/validators/status_length_validator.rb
index e107912b7..f93450ba6 100644
--- a/app/validators/status_length_validator.rb
+++ b/app/validators/status_length_validator.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class StatusLengthValidator < ActiveModel::Validator
-  MAX_CHARS = 500
+  MAX_CHARS = (ENV['MAX_TOOT_CHARS'] || 500).to_i
   URL_PLACEHOLDER_CHARS = 23
   URL_PLACEHOLDER = 'x' * 23