Merge branch 'main' into glitch-soc/merge-upstream
Conflicts: - `.github/workflows/build-image.yml`: Upstream changed how docker images were built, including how they were cached. I don't know much about it, so applied upstream's changes. - `app/controllers/admin/domain_blocks_controller.rb`: The feature, that was in glitch-soc, got backported upstream. It also had a few fixes upstream, so those have been ported! - `app/javascript/packs/admin.js`: Glitch-soc changes have been backported upstream. As a result, some code from `app/javascript/core/admin.js` got added upstream. Kept our version since our shared Javascript already has that feature. - `app/models/user.rb`: Upstream added something to distinguish unusable and unusable-because-moved accounts, while glitch-soc considers moved accounts usable. Took upstream's code for `functional_or_moved?` and made `functional?` call it. - `app/views/statuses/_simple_status.html.haml`: Upstream cleaned up code style a bit, on a line that we had custom changes for. Applied upstream's change while keeping our change. - `config/initializers/content_security_policy.rb`: Upstream adopted one CSP directive we already had. The conflict is because of our files being structurally different, but the change itself was already part of glitch-soc. Kept our version.
This commit is contained in:
@@ -17,6 +17,8 @@ class AccountsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
expires_in 0, public: true unless user_signed_in?
|
||||
|
||||
@rss_url = rss_url
|
||||
end
|
||||
|
||||
format.rss do
|
||||
|
||||
@@ -9,9 +9,9 @@ module Admin
|
||||
@form = Form::DomainBlockBatch.new(form_domain_block_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||
@form.save
|
||||
rescue ActionController::ParameterMissing
|
||||
flash[:alert] = I18n.t('admin.email_domain_blocks.no_domain_block_selected')
|
||||
flash[:alert] = I18n.t('admin.domain_blocks.no_domain_block_selected')
|
||||
rescue Mastodon::NotPermittedError
|
||||
flash[:alert] = I18n.t('admin.domain_blocks.created_msg')
|
||||
flash[:alert] = I18n.t('admin.domain_blocks.not_permitted')
|
||||
else
|
||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ module Admin
|
||||
rescue ActionController::ParameterMissing
|
||||
flash[:alert] = I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
|
||||
rescue Mastodon::NotPermittedError
|
||||
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
||||
flash[:alert] = I18n.t('admin.email_domain_blocks.not_permitted')
|
||||
ensure
|
||||
redirect_to admin_email_domain_blocks_path
|
||||
end
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
class Api::V1::FollowedTagsController < Api::BaseController
|
||||
TAGS_LIMIT = 100
|
||||
|
||||
before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }, except: :show
|
||||
before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }
|
||||
before_action :require_user!
|
||||
before_action :set_results
|
||||
|
||||
after_action :insert_pagination_headers, only: :show
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
def index
|
||||
render json: @results.map(&:tag), each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@results.map(&:tag), current_user&.account_id)
|
||||
@@ -43,7 +43,7 @@ class Api::V1::FollowedTagsController < Api::BaseController
|
||||
end
|
||||
|
||||
def records_continue?
|
||||
@results.size == limit_param(TAG_LIMIT)
|
||||
@results.size == limit_param(TAGS_LIMIT)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
|
||||
@@ -12,7 +12,7 @@ class Api::V1::TagsController < Api::BaseController
|
||||
end
|
||||
|
||||
def follow
|
||||
TagFollow.create!(tag: @tag, account: current_account, rate_limit: true)
|
||||
TagFollow.first_or_create!(tag: @tag, account: current_account, rate_limit: true)
|
||||
render json: @tag, serializer: REST::TagSerializer
|
||||
end
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ class StatusesCleanupController < ApplicationController
|
||||
# Do nothing
|
||||
end
|
||||
|
||||
def require_functional!
|
||||
redirect_to edit_user_registration_path unless current_user.functional_or_moved?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_pack
|
||||
|
||||
@@ -88,5 +88,10 @@ describe('emoji', () => {
|
||||
expect(emojify('💂♀️💂♂️'))
|
||||
.toEqual('<img draggable="false" class="emojione" alt="💂\u200D♀️" title=":female-guard:" src="/emoji/1f482-200d-2640-fe0f_border.svg"><img draggable="false" class="emojione" alt="💂\u200D♂️" title=":male-guard:" src="/emoji/1f482-200d-2642-fe0f_border.svg">');
|
||||
});
|
||||
|
||||
it('keeps ordering as expected (issue fixed by PR 20677)', () => {
|
||||
expect(emojify('<p>💕 <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>'))
|
||||
.toEqual('<p><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"> <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,8 +19,6 @@ const emojiFilename = (filename) => {
|
||||
return borderedEmoji.includes(filename) ? (filename + '_border') : filename;
|
||||
};
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
const emojifyTextNode = (node, customEmojis) => {
|
||||
let str = node.textContent;
|
||||
|
||||
@@ -39,7 +37,7 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
}
|
||||
}
|
||||
|
||||
let rend, replacement = '';
|
||||
let rend, replacement = null;
|
||||
if (i === str.length) {
|
||||
break;
|
||||
} else if (str[i] === ':') {
|
||||
@@ -51,7 +49,14 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
// if you want additional emoji handler, add statements below which set replacement and return true.
|
||||
if (shortname in customEmojis) {
|
||||
const filename = autoPlayGif ? customEmojis[shortname].url : customEmojis[shortname].static_url;
|
||||
replacement = `<img draggable="false" class="emojione custom-emoji" alt="${shortname}" title="${shortname}" src="${filename}" data-original="${customEmojis[shortname].url}" data-static="${customEmojis[shortname].static_url}" />`;
|
||||
replacement = document.createElement('img');
|
||||
replacement.setAttribute('draggable', false);
|
||||
replacement.setAttribute('class', 'emojione custom-emoji');
|
||||
replacement.setAttribute('alt', shortname);
|
||||
replacement.setAttribute('title', shortname);
|
||||
replacement.setAttribute('src', filename);
|
||||
replacement.setAttribute('data-original', customEmojis[shortname].url);
|
||||
replacement.setAttribute('data-static', customEmojis[shortname].static_url);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -59,7 +64,12 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
} else { // matched to unicode emoji
|
||||
const { filename, shortCode } = unicodeMapping[match];
|
||||
const title = shortCode ? `:${shortCode}:` : '';
|
||||
replacement = `<img draggable="false" class="emojione" alt="${match}" title="${title}" src="${assetHost}/emoji/${emojiFilename(filename)}.svg" />`;
|
||||
replacement = document.createElement('img');
|
||||
replacement.setAttribute('draggable', false);
|
||||
replacement.setAttribute('class', 'emojione');
|
||||
replacement.setAttribute('alt', match);
|
||||
replacement.setAttribute('title', title);
|
||||
replacement.setAttribute('src', `${assetHost}/emoji/${emojiFilename(filename)}.svg`);
|
||||
rend = i + match.length;
|
||||
// If the matched character was followed by VS15 (for selecting text presentation), skip it.
|
||||
if (str.codePointAt(rend) === 65038) {
|
||||
@@ -69,9 +79,8 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
|
||||
fragment.append(document.createTextNode(str.slice(0, i)));
|
||||
if (replacement) {
|
||||
fragment.append(domParser.parseFromString(replacement, 'text/html').documentElement.getElementsByTagName('img')[0]);
|
||||
fragment.append(replacement);
|
||||
}
|
||||
node.textContent = str.slice(0, i);
|
||||
str = str.slice(rend);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,16 @@ const mapStateToProps = state => ({
|
||||
isSearching: state.getIn(['search', 'submitted']) || !showTrends,
|
||||
});
|
||||
|
||||
// Fix strange bug on Safari where <span> (rendered by FormattedMessage) disappears
|
||||
// after clicking around Explore top bar (issue #20885).
|
||||
// Removing width=100% from <a> also fixes it, as well as replacing <span> with <div>
|
||||
// We're choosing to wrap span with div to keep the changes local only to this tool bar.
|
||||
const WrapFormattedMessage = ({ children, ...props }) => <div><FormattedMessage {...props}>{children}</FormattedMessage></div>;
|
||||
WrapFormattedMessage.propTypes = {
|
||||
children: PropTypes.any,
|
||||
};
|
||||
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Explore extends React.PureComponent {
|
||||
@@ -47,7 +57,7 @@ class Explore extends React.PureComponent {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { intl, multiColumn, isSearching } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
|
||||
@@ -70,10 +80,10 @@ class Explore extends React.PureComponent {
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<div className='account__section-headline'>
|
||||
<NavLink exact to='/explore'><FormattedMessage id='explore.trending_statuses' defaultMessage='Posts' /></NavLink>
|
||||
<NavLink exact to='/explore/tags'><FormattedMessage id='explore.trending_tags' defaultMessage='Hashtags' /></NavLink>
|
||||
<NavLink exact to='/explore/links'><FormattedMessage id='explore.trending_links' defaultMessage='News' /></NavLink>
|
||||
{signedIn && <NavLink exact to='/explore/suggestions'><FormattedMessage id='explore.suggested_follows' defaultMessage='For you' /></NavLink>}
|
||||
<NavLink exact to='/explore'><WrapFormattedMessage id='explore.trending_statuses' defaultMessage='Posts' /></NavLink>
|
||||
<NavLink exact to='/explore/tags'><WrapFormattedMessage id='explore.trending_tags' defaultMessage='Hashtags' /></NavLink>
|
||||
<NavLink exact to='/explore/links'><WrapFormattedMessage id='explore.trending_links' defaultMessage='News' /></NavLink>
|
||||
{signedIn && <NavLink exact to='/explore/suggestions'><WrapFormattedMessage id='explore.suggested_follows' defaultMessage='For you' /></NavLink>}
|
||||
</div>
|
||||
|
||||
<Switch>
|
||||
|
||||
@@ -35,7 +35,7 @@ class Header extends React.PureComponent {
|
||||
if (signedIn) {
|
||||
content = (
|
||||
<>
|
||||
{location.pathname !== '/publish' && <Link to='/publish' className='button'><FormattedMessage id='compose_form.publish' defaultMessage='Publish' /></Link>}
|
||||
{location.pathname !== '/publish' && <Link to='/publish' className='button'><FormattedMessage id='compose_form.publish_form' defaultMessage='Publish' /></Link>}
|
||||
<Account />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -3989,7 +3989,7 @@
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Publish",
|
||||
"id": "compose_form.publish"
|
||||
"id": "compose_form.publish_form"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Sign in",
|
||||
|
||||
@@ -115,6 +115,10 @@ class Form::AccountBatch
|
||||
authorize(account, :suspend?)
|
||||
log_action(:suspend, account)
|
||||
account.suspend!(origin: :local)
|
||||
account.strikes.create!(
|
||||
account: current_account,
|
||||
action: :suspend
|
||||
)
|
||||
Admin::SuspensionWorker.perform_async(account.id)
|
||||
end
|
||||
|
||||
|
||||
@@ -237,6 +237,11 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def functional?
|
||||
|
||||
functional_or_moved?
|
||||
end
|
||||
|
||||
def functional_or_moved?
|
||||
confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial?
|
||||
end
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@ class EmailDomainBlockPolicy < ApplicationPolicy
|
||||
role.can?(:manage_blocks)
|
||||
end
|
||||
|
||||
def show?
|
||||
role.can?(:manage_blocks)
|
||||
end
|
||||
|
||||
def create?
|
||||
role.can?(:manage_blocks)
|
||||
end
|
||||
|
||||
@@ -35,6 +35,7 @@ class ManifestSerializer < ActiveModel::Serializer
|
||||
src: full_pack_url("media/icons/android-chrome-#{size}x#{size}.png"),
|
||||
sizes: "#{size}x#{size}",
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -28,7 +28,7 @@ class VerifyLinkService < BaseService
|
||||
|
||||
links = Nokogiri::HTML(@body).xpath('//a[contains(concat(" ", normalize-space(@rel), " "), " me ")]|//link[contains(concat(" ", normalize-space(@rel), " "), " me ")]')
|
||||
|
||||
if links.any? { |link| link['href'].downcase == @link_back.downcase }
|
||||
if links.any? { |link| link['href']&.downcase == @link_back.downcase }
|
||||
true
|
||||
elsif links.empty?
|
||||
false
|
||||
@@ -38,6 +38,8 @@ class VerifyLinkService < BaseService
|
||||
end
|
||||
|
||||
def link_redirects_back?(test_url)
|
||||
return false if test_url.blank?
|
||||
|
||||
redirect_to_url = Request.new(:head, test_url, follow: false).perform do |res|
|
||||
res.headers['Location']
|
||||
end
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
%strong.emojify.p-name= display_name(account, custom_emojify: true)
|
||||
%span
|
||||
= acct(account)
|
||||
= fa_icon('lock', { :data => ({hidden: true} unless account.locked?)})
|
||||
= fa_icon('lock', { data: ({hidden: true} unless account.locked?)})
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
= f.input :return_to, as: :hidden
|
||||
|
||||
.field-group
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password', :autofocus => true }, label: t('challenge.prompt'), required: true
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password', autofocus: true }, label: t('challenge.prompt'), required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('challenge.confirm'), type: :submit
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
= render 'shared/error_messages', object: resource
|
||||
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.resend_confirmation'), type: :submit
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
= f.input :reset_password_token, as: :hidden
|
||||
|
||||
.fields-group
|
||||
= f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, required: true
|
||||
= f.input :password, wrapper: :with_label, autofocus: true, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, required: true
|
||||
.fields-group
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'new-password' }, required: true
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.set_new_password'), type: :submit
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
= render 'shared/error_messages', object: resource
|
||||
|
||||
.fields-group
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.reset_password'), type: :submit
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
%tr
|
||||
%td
|
||||
%span{ title: session.user_agent }<
|
||||
= fa_icon "#{session_device_icon(session)} fw", 'aria-label' => session_device_icon(session)
|
||||
= fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
|
||||
= ' '
|
||||
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: "#{session.browser}"), platform: t("sessions.platforms.#{session.platform}", default: "#{session.platform}")
|
||||
%td
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
- if !use_seamless_external_login? || resource.encrypted_password.present?
|
||||
.fields-row
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :email, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
|
||||
= f.input :email, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, required: true, disabled: current_account.suspended?
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :current_password, wrapper: :with_label, input_html: { 'aria-label' => t('simple_form.labels.defaults.current_password'), :autocomplete => 'current-password' }, required: true, disabled: current_account.suspended?, hint: false
|
||||
= f.input :current_password, wrapper: :with_label, input_html: { 'aria-label': t('simple_form.labels.defaults.current_password'), autocomplete: 'current-password' }, required: true, disabled: current_account.suspended?, hint: false
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.new_password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended?
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.new_password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: t('simple_form.hints.defaults.password'), disabled: current_account.suspended?
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_new_password'), :autocomplete => 'new-password' }, disabled: current_account.suspended?
|
||||
= f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_new_password'), input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_new_password'), autocomplete: 'new-password' }, disabled: current_account.suspended?
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit, class: 'button', disabled: current_account.suspended?
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
|
||||
.fields-group
|
||||
= f.simple_fields_for :account do |ff|
|
||||
= ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.display_name'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.display_name') }
|
||||
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
|
||||
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'username' }, hint: false
|
||||
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'new-password', :minlength => User.password_length.first, :maxlength => User.password_length.last }, hint: false
|
||||
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'new-password' }, hint: false
|
||||
= f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), :autocomplete => 'off' }, hint: false
|
||||
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.honeypot', label: 'Website'), :autocomplete => 'off' }
|
||||
= ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') }
|
||||
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
|
||||
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
|
||||
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
|
||||
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
|
||||
= f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false
|
||||
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
|
||||
|
||||
- if approved_registrations? && !@invite.present?
|
||||
.fields-group
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
|
||||
.fields-group
|
||||
- if use_seamless_external_login?
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.username_or_email') }, hint: false
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.username_or_email'), input_html: { 'aria-label': t('simple_form.labels.defaults.username_or_email') }, hint: false
|
||||
- else
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label' => t('simple_form.labels.defaults.email') }, hint: false
|
||||
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, hint: false
|
||||
.fields-group
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'current-password' }, hint: false
|
||||
= f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'current-password' }, hint: false
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.login'), type: :submit
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%p.hint.authentication-hint= t('simple_form.hints.sessions.otp')
|
||||
|
||||
.fields-group
|
||||
= f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt'), :autocomplete => 'one-time-code' }, autofocus: true
|
||||
= f.input :otp_attempt, type: :number, wrapper: :with_label, label: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label': t('simple_form.labels.defaults.otp_attempt'), autocomplete: 'one-time-code' }, autofocus: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('auth.login'), type: :submit
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%p.hint= t('auth.setup.email_below_hint_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :email, required: true, hint: false, input_html: { 'aria-label' => t('simple_form.labels.defaults.email'), :autocomplete => 'off' }
|
||||
= f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
|
||||
|
||||
.actions
|
||||
= f.submit t('admin.accounts.change_email.label'), class: 'button'
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
%hr.spacer/
|
||||
|
||||
- if current_user.encrypted_password.present?
|
||||
= f.input :password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, hint: t('deletes.confirm_password')
|
||||
= f.input :password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, hint: t('deletes.confirm_password')
|
||||
- else
|
||||
= f.input :username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, hint: t('deletes.confirm_username')
|
||||
= f.input :username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, hint: t('deletes.confirm_username')
|
||||
|
||||
.actions
|
||||
= f.button :button, t('deletes.proceed'), type: :submit, class: 'negative'
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
- if current_user.encrypted_password.present?
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, required: true
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, required: true
|
||||
- else
|
||||
= f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
|
||||
= f.input :current_username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('migrations.set_redirect'), type: :submit, class: 'button button--destructive'
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
.fields-row__column.fields-group.fields-row__column-6
|
||||
- if current_user.encrypted_password.present?
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'current-password' }, required: true, disabled: on_cooldown?
|
||||
= f.input :current_password, wrapper: :with_block_label, input_html: { autocomplete: 'current-password' }, required: true, disabled: on_cooldown?
|
||||
- else
|
||||
= f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true, disabled: on_cooldown?
|
||||
= f.input :current_username, wrapper: :with_block_label, input_html: { autocomplete: 'off' }, required: true, disabled: on_cooldown?
|
||||
|
||||
.actions
|
||||
= f.button :button, t('migrations.proceed_with_move'), type: :submit, class: 'button button--destructive', disabled: on_cooldown?
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
%samp.qr-alternative__code= @new_otp_secret.scan(/.{4}/).join(' ')
|
||||
|
||||
.fields-group
|
||||
= f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { :autocomplete => 'off' }, required: true
|
||||
= f.input :otp_attempt, wrapper: :with_label, hint: t('otp_authentication.code_hint'), label: t('simple_form.labels.defaults.otp_attempt'), input_html: { autocomplete: 'off' }, required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('otp_authentication.enable'), type: :submit
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
%p.hint= t('webauthn_credentials.description_html')
|
||||
|
||||
.fields_group
|
||||
= f.input :nickname, wrapper: :with_block_label, hint: t('webauthn_credentials.nickname_hint'), input_html: { :autocomplete => 'off' }, required: true
|
||||
= f.input :nickname, wrapper: :with_block_label, hint: t('webauthn_credentials.nickname_hint'), input_html: { autocomplete: 'off' }, required: true
|
||||
|
||||
.actions
|
||||
= f.button :button, t('webauthn_credentials.add'), class: 'js-webauthn', type: :submit
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
|
||||
= account_action_button(status.account)
|
||||
|
||||
.status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
.status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
- if status.spoiler_text?
|
||||
%p<
|
||||
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
|
||||
%button.status__content__spoiler-link= t('statuses.show_more')
|
||||
.e-content{ :lang => status.language }
|
||||
.e-content{ lang: status.language }
|
||||
= prerender_custom_emojis(status_content_format(status), status.emojis)
|
||||
|
||||
- if status.preloadable_poll
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
%span.display-name__account
|
||||
= acct(status.account)
|
||||
= fa_icon('lock') if status.account.locked?
|
||||
.status__content.emojify{ :data => ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
.status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||
- if status.spoiler_text?
|
||||
%p<
|
||||
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
|
||||
%button.status__content__spoiler-link= t('statuses.show_more')
|
||||
.e-content{ :lang => status.language }<
|
||||
.e-content{ lang: status.language }<
|
||||
= prerender_custom_emojis(status_content_format(status), status.emojis)
|
||||
|
||||
- if status.preloadable_poll
|
||||
|
||||
Reference in New Issue
Block a user