Merge commit '25c66fa640
' into kb_migration
This commit is contained in:
commit
1f64358afb
107 changed files with 2159 additions and 1540 deletions
|
@ -14,15 +14,5 @@ module Admin
|
|||
@pending_tags_count = Tag.pending_review.count
|
||||
@pending_appeals_count = Appeal.pending.count
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redis_info
|
||||
@redis_info ||= if redis.is_a?(Redis::Namespace)
|
||||
redis.redis.info
|
||||
else
|
||||
redis.info
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -90,7 +90,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
end
|
||||
|
||||
def account_params
|
||||
params.permit(:username, :email, :password, :agreement, :locale, :reason)
|
||||
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone)
|
||||
end
|
||||
|
||||
def check_enabled_registrations
|
||||
|
|
41
app/controllers/mail_subscriptions_controller.rb
Normal file
41
app/controllers/mail_subscriptions_controller.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MailSubscriptionsController < ApplicationController
|
||||
layout 'auth'
|
||||
|
||||
skip_before_action :require_functional!
|
||||
|
||||
before_action :set_body_classes
|
||||
before_action :set_user
|
||||
before_action :set_type
|
||||
|
||||
def show; end
|
||||
|
||||
def create
|
||||
@user.settings[email_type_from_param] = false
|
||||
@user.save!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user
|
||||
@user = GlobalID::Locator.locate_signed(params[:token], for: 'unsubscribe')
|
||||
end
|
||||
|
||||
def set_body_classes
|
||||
@body_classes = 'lighter'
|
||||
end
|
||||
|
||||
def set_type
|
||||
@type = email_type_from_param
|
||||
end
|
||||
|
||||
def email_type_from_param
|
||||
case params[:type]
|
||||
when 'follow', 'reblog', 'favourite', 'mention', 'follow_request'
|
||||
"notification_emails.#{params[:type]}"
|
||||
else
|
||||
raise ArgumentError
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,6 +19,6 @@ class Settings::Preferences::BaseController < Settings::BaseController
|
|||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:locale, chosen_languages: [], settings_attributes: UserSettings.keys)
|
||||
params.require(:user).permit(:locale, :time_zone, chosen_languages: [], settings_attributes: UserSettings.keys)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class LoadPending extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
count: PropTypes.number,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { count } = this.props;
|
||||
|
||||
return (
|
||||
<button className='load-more load-gap' onClick={this.props.onClick}>
|
||||
<FormattedMessage id='load_pending' defaultMessage='{count, plural, one {# new item} other {# new items}}' values={{ count }} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
18
app/javascript/mastodon/components/load_pending.tsx
Normal file
18
app/javascript/mastodon/components/load_pending.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
interface Props {
|
||||
onClick: (event: React.MouseEvent) => void;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export const LoadPending: React.FC<Props> = ({ onClick, count }) => {
|
||||
return (
|
||||
<button className='load-more load-gap' onClick={onClick}>
|
||||
<FormattedMessage
|
||||
id='load_pending'
|
||||
defaultMessage='{count, plural, one {# new item} other {# new items}}'
|
||||
values={{ count }}
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
};
|
|
@ -16,7 +16,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
|
|||
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
|
||||
|
||||
import { LoadMore } from './load_more';
|
||||
import LoadPending from './load_pending';
|
||||
import { LoadPending } from './load_pending';
|
||||
import LoadingIndicator from './loading_indicator';
|
||||
|
||||
const MOUSE_IDLE_DELAY = 300;
|
||||
|
|
|
@ -377,7 +377,7 @@ class Header extends ImmutablePureComponent {
|
|||
let badge;
|
||||
|
||||
if (account.get('bot')) {
|
||||
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>);
|
||||
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
|
||||
} else if (account.get('group')) {
|
||||
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"about.rules": "Server rules",
|
||||
"account.account_note_header": "Note",
|
||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||
"account.badges.bot": "Bot",
|
||||
"account.badges.bot": "Automated",
|
||||
"account.badges.group": "Group",
|
||||
"account.block": "Block @{name}",
|
||||
"account.block_domain": "Block domain {domain}",
|
||||
|
|
|
@ -8,61 +8,71 @@ class NotificationMailer < ApplicationMailer
|
|||
|
||||
def mention(recipient, notification)
|
||||
@me = recipient
|
||||
@user = recipient.user
|
||||
@type = 'mention'
|
||||
@status = notification.target_status
|
||||
|
||||
return unless @me.user.functional? && @status.present?
|
||||
return unless @user.functional? && @status.present?
|
||||
|
||||
locale_for_account(@me) do
|
||||
thread_by_conversation(@status.conversation)
|
||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
|
||||
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
def follow(recipient, notification)
|
||||
@me = recipient
|
||||
@user = recipient.user
|
||||
@type = 'follow'
|
||||
@account = notification.from_account
|
||||
|
||||
return unless @me.user.functional?
|
||||
return unless @user.functional?
|
||||
|
||||
locale_for_account(@me) do
|
||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
|
||||
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
def favourite(recipient, notification)
|
||||
@me = recipient
|
||||
@user = recipient.user
|
||||
@type = 'favourite'
|
||||
@account = notification.from_account
|
||||
@status = notification.target_status
|
||||
|
||||
return unless @me.user.functional? && @status.present?
|
||||
return unless @user.functional? && @status.present?
|
||||
|
||||
locale_for_account(@me) do
|
||||
thread_by_conversation(@status.conversation)
|
||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
|
||||
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
def reblog(recipient, notification)
|
||||
@me = recipient
|
||||
@user = recipient.user
|
||||
@type = 'reblog'
|
||||
@account = notification.from_account
|
||||
@status = notification.target_status
|
||||
|
||||
return unless @me.user.functional? && @status.present?
|
||||
return unless @user.functional? && @status.present?
|
||||
|
||||
locale_for_account(@me) do
|
||||
thread_by_conversation(@status.conversation)
|
||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
|
||||
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
def follow_request(recipient, notification)
|
||||
@me = recipient
|
||||
@user = recipient.user
|
||||
@type = 'follow_request'
|
||||
@account = notification.from_account
|
||||
|
||||
return unless @me.user.functional?
|
||||
return unless @user.functional?
|
||||
|
||||
locale_for_account(@me) do
|
||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
|
||||
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ class Account < ApplicationRecord
|
|||
:locale,
|
||||
:shows_application?,
|
||||
:prefers_noindex?,
|
||||
:time_zone,
|
||||
to: :user,
|
||||
prefix: true,
|
||||
allow_nil: true
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
# sign_up_ip :inet
|
||||
# role_id :bigint(8)
|
||||
# settings :text
|
||||
# time_zone :string
|
||||
#
|
||||
|
||||
class User < ApplicationRecord
|
||||
|
@ -101,6 +102,7 @@ class User < ApplicationRecord
|
|||
validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
|
||||
validates_with EmailMxValidator, if: :validate_email_dns?
|
||||
validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
|
||||
validates :time_zone, inclusion: { in: ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name } }, allow_blank: true
|
||||
|
||||
# Honeypot/anti-spam fields
|
||||
attr_accessor :registration_form_time, :website, :confirm_password
|
||||
|
|
|
@ -35,7 +35,7 @@ class AppSignUpService < BaseService
|
|||
end
|
||||
|
||||
def user_params
|
||||
@params.slice(:email, :password, :agreement, :locale)
|
||||
@params.slice(:email, :password, :agreement, :locale, :time_zone)
|
||||
end
|
||||
|
||||
def account_params
|
||||
|
|
|
@ -44,7 +44,11 @@
|
|||
%tbody
|
||||
%td.column-cell
|
||||
%p= t 'about.hosted_on', domain: site_hostname
|
||||
%p= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
|
||||
%p
|
||||
= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
|
||||
- if defined?(@type)
|
||||
·
|
||||
= link_to t('application_mailer.unsubscribe'), unsubscribe_url(token: @user.to_sgid(for: 'unsubscribe').to_s, type: @type)
|
||||
%td.column-cell.text-right
|
||||
= link_to root_url do
|
||||
= image_tag full_pack_url('media/images/mailer/logo.png'), alt: 'Mastodon', height: 24
|
||||
|
|
9
app/views/mail_subscriptions/create.html.haml
Normal file
9
app/views/mail_subscriptions/create.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
|||
- content_for :page_title do
|
||||
= t('mail_subscriptions.unsubscribe.title')
|
||||
|
||||
.simple_form
|
||||
%h1.title= t('mail_subscriptions.unsubscribe.complete')
|
||||
%p.lead
|
||||
= t('mail_subscriptions.unsubscribe.success_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email))
|
||||
%p.lead
|
||||
= t('mail_subscriptions.unsubscribe.resubscribe_html', settings_path: settings_preferences_notifications_path)
|
12
app/views/mail_subscriptions/show.html.haml
Normal file
12
app/views/mail_subscriptions/show.html.haml
Normal file
|
@ -0,0 +1,12 @@
|
|||
- content_for :page_title do
|
||||
= t('mail_subscriptions.unsubscribe.title')
|
||||
|
||||
.simple_form
|
||||
%h1.title= t('mail_subscriptions.unsubscribe.title')
|
||||
%p.lead
|
||||
= t('mail_subscriptions.unsubscribe.confirmation_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email), settings_path: settings_preferences_notifications_path)
|
||||
|
||||
= form_tag unsubscribe_path, method: :post do
|
||||
= hidden_field_tag :token, params[:token]
|
||||
= hidden_field_tag :type, params[:type]
|
||||
= button_tag t('mail_subscriptions.unsubscribe.action'), type: :submit
|
|
@ -42,4 +42,4 @@
|
|||
= link_to a.remote_url, a.remote_url
|
||||
|
||||
%p.status-footer
|
||||
= link_to l(status.created_at), web_url("@#{status.account.pretty_acct}/#{status.id}")
|
||||
= link_to l(status.created_at.in_time_zone(time_zone)), web_url("@#{status.account.pretty_acct}/#{status.id}")
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
%h1= t 'notification_mailer.favourite.title'
|
||||
%p.lead= t('notification_mailer.favourite.body', name: @account.pretty_acct)
|
||||
|
||||
= render 'status', status: @status
|
||||
= render 'status', status: @status, time_zone: @me.user_time_zone
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
%h1= t 'notification_mailer.mention.title'
|
||||
%p.lead= t('notification_mailer.mention.body', name: @status.account.pretty_acct)
|
||||
|
||||
= render 'status', status: @status
|
||||
= render 'status', status: @status, time_zone: @me.user_time_zone
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
%h1= t 'notification_mailer.reblog.title'
|
||||
%p.lead= t('notification_mailer.reblog.body', name: @account.pretty_acct)
|
||||
|
||||
= render 'status', status: @status
|
||||
= render 'status', status: @status, time_zone: @me.user_time_zone
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| native_locale_name(locale) }, selected: I18n.locale, hint: false
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
= ff.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, include_blank: false, hint: false
|
||||
= f.input :time_zone, wrapper: :with_label, collection: ActiveSupport::TimeZone.all.map { |tz| ["(GMT#{tz.formatted_offset}) #{tz.name}", tz.tzinfo.name] }, hint: false
|
||||
|
||||
.fields-group
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
= ff.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_theme'), include_blank: false, hint: false
|
||||
|
||||
- unless I18n.locale == :en
|
||||
.flash-message.translation-prompt
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at)
|
||||
%p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone))
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
===
|
||||
|
||||
<%= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %>
|
||||
<%= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone)) %>
|
||||
|
||||
=> <%= root_url %>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
%tbody
|
||||
%tr
|
||||
%td.column-cell.text-center
|
||||
%p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at)
|
||||
%p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone))
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
===
|
||||
|
||||
<%= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %>
|
||||
<%= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at.in_time_zone(@resource.time_zone)), strike_date: l(@appeal.strike.created_at.in_time_zone(@resource.time_zone)) %>
|
||||
|
||||
=> <%= root_url %>
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
%strong= "#{t('sessions.browser')}:"
|
||||
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
|
||||
%br/
|
||||
= l(@timestamp)
|
||||
= l(@timestamp.in_time_zone(@resource.time_zone))
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<%= t('sessions.ip') %>: <%= @remote_ip %>
|
||||
<%= t('sessions.browser') %>: <%= t('sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: "#{@detection.id}"), platform: t("sessions.platforms.#{@detection.platform.id}", default: "#{@detection.platform.id}")) %>
|
||||
<%= l(@timestamp) %>
|
||||
<%= l(@timestamp.in_time_zone(@resource.time_zone)) %>
|
||||
|
||||
<%= t 'user_mailer.suspicious_sign_in.further_actions_html', action: t('user_mailer.suspicious_sign_in.change_password') %>
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
- unless @statuses.empty?
|
||||
- @statuses.each_with_index do |status, i|
|
||||
= render 'notification_mailer/status', status: status, i: i + 1, highlighted: true
|
||||
= render 'notification_mailer/status', status: status, i: i + 1, highlighted: true, time_zone: @resource.time_zone
|
||||
|
||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
|
||||
%tbody
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue