* Add: #348 新規登録の上限人数 * Fix test * Fix test * Wip * Fix test * Add invite support * Wip * Fix test * Fix test * Fix test
This commit is contained in:
parent
d7cc6b788c
commit
e317edecb8
26 changed files with 362 additions and 6 deletions
|
@ -1,9 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::Settings::RegistrationsController < Admin::SettingsController
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
before_action :set_limitation_counts, only: :show # rubocop:disable Rails/LexicallyScopedActionFilter
|
||||
|
||||
private
|
||||
|
||||
def after_update_redirect_path
|
||||
admin_settings_registrations_path
|
||||
end
|
||||
|
||||
def set_limitation_counts
|
||||
@current_users_count = user_count_for_registration
|
||||
@current_users_count_today = today_increase_user_count
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||
include Auth::CaptchaConcern
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
layout 'auth'
|
||||
|
||||
|
@ -16,6 +17,11 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
|||
skip_before_action :require_functional!
|
||||
|
||||
def show
|
||||
if reach_registrations_limit?
|
||||
render :limitation_error
|
||||
return
|
||||
end
|
||||
|
||||
old_session_values = session.to_hash
|
||||
reset_session
|
||||
session.update old_session_values.except('session_id')
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
module RegistrationHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
def allowed_registration?(remote_ip, invite)
|
||||
!Rails.configuration.x.single_user_mode && !omniauth_only? && (registrations_open? || invite&.valid_for_use?) && !ip_blocked?(remote_ip)
|
||||
!Rails.configuration.x.single_user_mode && !omniauth_only? && ((registrations_open? && !reach_registrations_limit?) || invite&.valid_for_use?) && !ip_blocked?(remote_ip)
|
||||
end
|
||||
|
||||
def registrations_open?
|
||||
|
|
55
app/helpers/registration_limitation_helper.rb
Normal file
55
app/helpers/registration_limitation_helper.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RegistrationLimitationHelper
|
||||
def reach_registrations_limit?
|
||||
return true unless registrations_in_time?
|
||||
|
||||
((Setting.registrations_limit.presence || 0).positive? && Setting.registrations_limit <= user_count_for_registration) ||
|
||||
((Setting.registrations_limit_per_day.presence || 0).positive? && Setting.registrations_limit_per_day <= today_increase_user_count)
|
||||
end
|
||||
|
||||
def user_count_for_registration
|
||||
Rails.cache.fetch('registrations:user_count') { User.confirmed.enabled.joins(:account).merge(Account.without_suspended).count }
|
||||
end
|
||||
|
||||
def today_increase_user_count
|
||||
today_date = Time.now.utc.beginning_of_day.to_i
|
||||
count = 0
|
||||
|
||||
if Rails.cache.fetch('registrations:today_date') { today_date } == today_date
|
||||
count = Rails.cache.fetch('registrations:today_increase_user_count') { today_increase_user_count_value }
|
||||
else
|
||||
count = today_increase_user_count_value
|
||||
Rails.cache.write('registrations:today_date', today_date)
|
||||
Rails.cache.write('registrations:today_increase_user_count', count)
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
def today_increase_user_count_value
|
||||
User.confirmed.enabled.where('users.created_at >= ?', Time.now.utc.beginning_of_day).joins(:account).merge(Account.without_suspended).count
|
||||
end
|
||||
|
||||
def registrations_in_time?
|
||||
start_hour = Setting.registrations_start_hour || 0
|
||||
end_hour = Setting.registrations_end_hour || 24
|
||||
secondary_start_hour = Setting.registrations_secondary_start_hour || 0
|
||||
secondary_end_hour = Setting.registrations_secondary_end_hour || 0
|
||||
|
||||
return true if start_hour >= end_hour && secondary_start_hour >= secondary_end_hour
|
||||
|
||||
current_hour = Time.now.utc.hour
|
||||
primary_permitted = false
|
||||
primary_permitted = start_hour <= current_hour && current_hour < end_hour if start_hour < end_hour && end_hour.positive?
|
||||
secondary_permitted = false
|
||||
secondary_permitted = secondary_start_hour <= current_hour && current_hour < secondary_end_hour if secondary_start_hour < secondary_end_hour && secondary_end_hour.positive?
|
||||
|
||||
primary_permitted || secondary_permitted
|
||||
end
|
||||
|
||||
def reset_registration_limit_caches!
|
||||
Rails.cache.delete('registrations:user_count')
|
||||
Rails.cache.delete('registrations:today_increase_user_count')
|
||||
end
|
||||
end
|
|
@ -4,7 +4,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
|||
import { connect } from 'react-redux';
|
||||
|
||||
import { fetchServer } from 'mastodon/actions/server';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
import { domain, registrationsReachLimit } from 'mastodon/initial_state';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
message: state.getIn(['server', 'server', 'registrations', 'message']),
|
||||
|
@ -27,6 +27,16 @@ class ClosedRegistrationsModal extends ImmutablePureComponent {
|
|||
dangerouslySetInnerHTML={{ __html: this.props.message }}
|
||||
/>
|
||||
);
|
||||
} else if (registrationsReachLimit) {
|
||||
closedRegistrationsMessage = (
|
||||
<p className='prose'>
|
||||
<FormattedMessage
|
||||
id='closed_registrations_modal.description_when_reaching_limit'
|
||||
defaultMessage='New registrations are currently temporarily restricted. Either the maximum number of registrations has been reached or it is outside the time frame available for registration. Please contact the administrator for more information or wait until the restriction is lifted.'
|
||||
values={{ domain: <strong>{domain}</strong> }}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
closedRegistrationsMessage = (
|
||||
<p className='prose'>
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
* @property {string=} owner
|
||||
* @property {boolean} profile_directory
|
||||
* @property {boolean} registrations_open
|
||||
* @property {boolean} registrations_reach_limit
|
||||
* @property {boolean} reduce_motion
|
||||
* @property {string} repository
|
||||
* @property {boolean} search_enabled
|
||||
|
@ -134,6 +135,7 @@ export const owner = getMeta('owner');
|
|||
export const profile_directory = getMeta('profile_directory');
|
||||
export const reduceMotion = getMeta('reduce_motion');
|
||||
export const registrationsOpen = getMeta('registrations_open');
|
||||
export const registrationsReachLimit = getMeta('registrations_reach_limit');
|
||||
export const repository = getMeta('repository');
|
||||
export const searchEnabled = getMeta('search_enabled');
|
||||
export const trendsEnabled = getMeta('trends_enabled');
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
"circles.edit": "Edit circle",
|
||||
"closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.",
|
||||
"closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.",
|
||||
"closed_registrations_modal.description_when_reaching_limit": "New registrations are currently temporarily restricted. Either the maximum number of registrations has been reached or it is outside the time frame available for registration. Please contact the administrator for more information or wait until the restriction is lifted.",
|
||||
"closed_registrations_modal.find_another_server": "Find another server",
|
||||
"closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
||||
"closed_registrations_modal.title": "Signing up on Mastodon",
|
||||
|
|
|
@ -170,6 +170,7 @@
|
|||
"circles.subheading": "あなたのサークル",
|
||||
"closed_registrations.other_server_instructions": "Mastodonは分散型なので他のサーバーにアカウントを作ってもこのサーバーとやり取りできます。",
|
||||
"closed_registrations_modal.description": "現在{domain}でアカウント作成はできませんがMastodonは{domain}のアカウントでなくても利用できます。",
|
||||
"closed_registrations_modal.description_when_reaching_limit": "新規登録は現在一時的に制限されています。登録の上限人数に達したか、または登録可能な時間帯の範囲外です。詳細を管理人に問い合わせるか、制限が解除されるまでお待ち下さい。",
|
||||
"closed_registrations_modal.find_another_server": "別のサーバーを探す",
|
||||
"closed_registrations_modal.preamble": "Mastodonは分散型なのでどのサーバーでアカウントを作成してもこのサーバーのユーザーを誰でもフォローして交流することができます。また自分でホスティングすることもできます!",
|
||||
"closed_registrations_modal.title": "Mastodonでアカウントを作成",
|
||||
|
|
|
@ -15,6 +15,12 @@ class Form::AdminSettings
|
|||
registrations_mode
|
||||
closed_registrations_message
|
||||
registration_button_message
|
||||
registrations_limit
|
||||
registrations_limit_per_day
|
||||
registrations_start_hour
|
||||
registrations_end_hour
|
||||
registrations_secondary_start_hour
|
||||
registrations_secondary_end_hour
|
||||
timeline_preview
|
||||
bootstrap_timeline_accounts
|
||||
theme
|
||||
|
@ -61,6 +67,12 @@ class Form::AdminSettings
|
|||
content_cache_retention_period
|
||||
backups_retention_period
|
||||
post_hash_tags_max
|
||||
registrations_limit
|
||||
registrations_limit_per_day
|
||||
registrations_start_hour
|
||||
registrations_end_hour
|
||||
registrations_secondary_start_hour
|
||||
registrations_secondary_end_hour
|
||||
).freeze
|
||||
|
||||
BOOLEAN_KEYS = %i(
|
||||
|
|
|
@ -55,6 +55,7 @@ class User < ApplicationRecord
|
|||
|
||||
include LanguagesHelper
|
||||
include Redisable
|
||||
include RegistrationLimitationHelper
|
||||
include User::HasSettings
|
||||
include User::LdapAuthenticable
|
||||
include User::Omniauthable
|
||||
|
@ -192,6 +193,8 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def confirm
|
||||
raise Mastodon::ValidationError, I18n.t('devise.registrations.sign_up_failed_because_reach_limit') if !invited? && reach_registrations_limit?
|
||||
|
||||
wrap_email_confirmation do
|
||||
super
|
||||
end
|
||||
|
@ -482,6 +485,7 @@ class User < ApplicationRecord
|
|||
ActivityTracker.record('activity:logins', id)
|
||||
UserMailer.welcome(self).deliver_later
|
||||
TriggerWebhookWorker.perform_async('account.approved', 'Account', account_id)
|
||||
reset_registration_limit_caches!
|
||||
end
|
||||
|
||||
def prepare_returning_user!
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
class InitialStateSerializer < ActiveModel::Serializer
|
||||
include RoutingHelper
|
||||
include DtlHelper
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
attributes :meta, :compose, :accounts,
|
||||
:media_attachments, :settings,
|
||||
|
@ -122,7 +123,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
locale: I18n.locale,
|
||||
mascot: instance_presenter.mascot&.file&.url,
|
||||
profile_directory: Setting.profile_directory,
|
||||
registrations_open: Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode,
|
||||
registrations_open: Setting.registrations_mode != 'none' && !reach_registrations_limit? && !Rails.configuration.x.single_user_mode,
|
||||
registrations_reach_limit: Setting.registrations_mode != 'none' && reach_registrations_limit?,
|
||||
repository: Mastodon::Version.repository,
|
||||
search_enabled: Chewy.enabled?,
|
||||
single_user_mode: Rails.configuration.x.single_user_mode,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
class NodeInfo::Serializer < ActiveModel::Serializer
|
||||
include RoutingHelper
|
||||
include KmyblueCapabilitiesHelper
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
attributes :version, :software, :protocols, :services, :usage, :open_registrations, :metadata
|
||||
|
||||
|
@ -35,7 +36,7 @@ class NodeInfo::Serializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def open_registrations
|
||||
Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode
|
||||
Setting.registrations_mode != 'none' && !reach_registrations_limit? && !Rails.configuration.x.single_user_mode
|
||||
end
|
||||
|
||||
def metadata
|
||||
|
|
|
@ -9,6 +9,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
|
||||
include RoutingHelper
|
||||
include KmyblueCapabilitiesHelper
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
attributes :domain, :title, :version, :source_url, :description,
|
||||
:usage, :thumbnail, :languages, :configuration,
|
||||
|
@ -110,6 +111,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
{
|
||||
enabled: registrations_enabled?,
|
||||
approval_required: Setting.registrations_mode == 'approved',
|
||||
limit_reached: Setting.registrations_mode != 'none' && reach_registrations_limit?,
|
||||
message: registrations_enabled? ? nil : registrations_message,
|
||||
url: ENV.fetch('SSO_ACCOUNT_SIGN_UP', nil),
|
||||
}
|
||||
|
@ -118,7 +120,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
private
|
||||
|
||||
def registrations_enabled?
|
||||
Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode
|
||||
Setting.registrations_mode != 'none' && !reach_registrations_limit? && !Rails.configuration.x.single_user_mode
|
||||
end
|
||||
|
||||
def registrations_message
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
class REST::V1::InstanceSerializer < ActiveModel::Serializer
|
||||
include RoutingHelper
|
||||
include KmyblueCapabilitiesHelper
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
attributes :uri, :title, :short_description, :description, :email,
|
||||
:version, :urls, :stats, :thumbnail,
|
||||
|
@ -109,7 +110,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def registrations
|
||||
Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode
|
||||
Setting.registrations_mode != 'none' && !reach_registrations_limit? && !Rails.configuration.x.single_user_mode
|
||||
end
|
||||
|
||||
def approval_required
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class DeleteAccountService < BaseService
|
||||
include Payloadable
|
||||
include RegistrationLimitationHelper
|
||||
|
||||
ASSOCIATIONS_ON_SUSPEND = %w(
|
||||
account_notes
|
||||
|
@ -143,6 +144,8 @@ class DeleteAccountService < BaseService
|
|||
else
|
||||
@account.user.destroy
|
||||
end
|
||||
|
||||
reset_registration_limit_caches!
|
||||
end
|
||||
|
||||
def purge_content!
|
||||
|
|
|
@ -27,5 +27,19 @@
|
|||
.fields-group
|
||||
= f.input :registration_button_message, as: :text, kmyblue: true, hint: false, wrapper: :with_label, input_html: { rows: 2 }
|
||||
|
||||
.fields-group
|
||||
= f.input :registrations_limit, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }, label: I18n.t('simple_form.labels.form_admin_settings.registrations_limit', count: @current_users_count)
|
||||
|
||||
.fields-group
|
||||
= f.input :registrations_limit_per_day, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }, label: I18n.t('simple_form.labels.form_admin_settings.registrations_limit_per_day', count: @current_users_count_today)
|
||||
|
||||
.fields-group
|
||||
= f.input :registrations_start_hour, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }
|
||||
= f.input :registrations_end_hour, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }
|
||||
|
||||
.fields-group
|
||||
= f.input :registrations_secondary_start_hour, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }
|
||||
= f.input :registrations_secondary_end_hour, kmyblue: true, wrapper: :with_label, input_html: { pattern: '[0-9]+' }
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
||||
|
|
11
app/views/auth/confirmations/limitation_error.html.haml
Normal file
11
app/views/auth/confirmations/limitation_error.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- content_for :page_title do
|
||||
= t('auth.registration_limit.title')
|
||||
|
||||
= form_tag root_url, method: 'GET', class: 'simple_form' do
|
||||
= render 'auth/shared/progress', stage: 'confirm'
|
||||
|
||||
%h1.title= t('auth.registration_limit.title')
|
||||
%p.lead= t('auth.registration_limit.hint_html')
|
||||
|
||||
.actions
|
||||
= button_tag t('challenge.confirm'), class: 'button', type: :submit
|
Loading…
Add table
Add a link
Reference in a new issue