diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx
index 1044b729b3..e3c0065c95 100644
--- a/app/javascript/mastodon/components/media_gallery.jsx
+++ b/app/javascript/mastodon/components/media_gallery.jsx
@@ -321,7 +321,10 @@ class MediaGallery extends PureComponent {
if (uncached) {
spoilerButton = (
);
} else if (visible) {
@@ -329,7 +332,10 @@ class MediaGallery extends PureComponent {
} else {
spoilerButton = (
);
}
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 8705e6cd68..edecaf60f3 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -618,6 +618,8 @@
"status.history.created": "{name} created {date}",
"status.history.edited": "{name} edited {date}",
"status.load_more": "Load more",
+ "status.media.open": "Click to open",
+ "status.media.show": "Click to show",
"status.media_hidden": "Media hidden",
"status.mention": "Mention @{name}",
"status.more": "More",
@@ -648,7 +650,7 @@
"status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}",
"status.translate": "Translate",
"status.translated_from_with": "Translated from {lang} using {provider}",
- "status.uncached_media_warning": "Not available",
+ "status.uncached_media_warning": "Preview not available",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Unpin from profile",
"subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.",
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 959dc2f715..e1af246a81 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -4213,34 +4213,31 @@ a.status-card.compact:hover {
}
&__overlay {
- display: block;
- background: transparent;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba($black, 0.5);
width: 100%;
height: 100%;
+ padding: 0;
+ margin: 0;
border: 0;
+ border-radius: 4px;
&__label {
- display: inline-block;
- background: rgba($base-overlay-background, 0.5);
- border-radius: 8px;
- padding: 8px 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ flex-direction: column;
color: $primary-text-color;
font-weight: 500;
font-size: 14px;
}
- &:hover,
- &:focus,
- &:active {
- .spoiler-button__overlay__label {
- background: rgba($base-overlay-background, 0.8);
- }
- }
-
- &:disabled {
- .spoiler-button__overlay__label {
- background: rgba($base-overlay-background, 0.5);
- }
+ &__action {
+ font-weight: 400;
+ font-size: 13px;
}
}
}
diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb
index bc6d87ae6f..5baf9b38a5 100644
--- a/app/mailers/admin_mailer.rb
+++ b/app/mailers/admin_mailer.rb
@@ -6,45 +6,52 @@ class AdminMailer < ApplicationMailer
helper :accounts
helper :languages
- def new_report(recipient, report)
- @report = report
- @me = recipient
- @instance = Rails.configuration.x.local_domain
+ before_action :process_params
+ before_action :set_instance
+
+ default to: -> { @me.user_email }
+
+ def new_report(report)
+ @report = report
locale_for_account(@me) do
- mail to: @me.user_email, subject: I18n.t('admin_mailer.new_report.subject', instance: @instance, id: @report.id)
+ mail subject: default_i18n_subject(instance: @instance, id: @report.id)
end
end
- def new_appeal(recipient, appeal)
- @appeal = appeal
- @me = recipient
- @instance = Rails.configuration.x.local_domain
+ def new_appeal(appeal)
+ @appeal = appeal
locale_for_account(@me) do
- mail to: @me.user_email, subject: I18n.t('admin_mailer.new_appeal.subject', instance: @instance, username: @appeal.account.username)
+ mail subject: default_i18n_subject(instance: @instance, username: @appeal.account.username)
end
end
- def new_pending_account(recipient, user)
- @account = user.account
- @me = recipient
- @instance = Rails.configuration.x.local_domain
+ def new_pending_account(user)
+ @account = user.account
locale_for_account(@me) do
- mail to: @me.user_email, subject: I18n.t('admin_mailer.new_pending_account.subject', instance: @instance, username: @account.username)
+ mail subject: default_i18n_subject(instance: @instance, username: @account.username)
end
end
- def new_trends(recipient, links, tags, statuses)
+ def new_trends(links, tags, statuses)
@links = links
@tags = tags
@statuses = statuses
- @me = recipient
- @instance = Rails.configuration.x.local_domain
locale_for_account(@me) do
- mail to: @me.user_email, subject: I18n.t('admin_mailer.new_trends.subject', instance: @instance)
+ mail subject: default_i18n_subject(instance: @instance)
end
end
+
+ private
+
+ def process_params
+ @me = params[:recipient]
+ end
+
+ def set_instance
+ @instance = Rails.configuration.x.local_domain
+ end
end
diff --git a/app/models/trends.rb b/app/models/trends.rb
index b09db940eb..4db2cddbfc 100644
--- a/app/models/trends.rb
+++ b/app/models/trends.rb
@@ -38,7 +38,7 @@ module Trends
statuses = user.allows_trending_statuses_review_emails? ? statuses_requiring_review : []
next if links.empty? && tags.empty? && statuses.empty?
- AdminMailer.new_trends(user.account, links, tags, statuses).deliver_later!
+ AdminMailer.with(recipient: user.account).new_trends(links, tags, statuses).deliver_later! if user.allows_trends_review_emails?
end
end
diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb
index c94f7c0237..fcbdb1a5f5 100644
--- a/app/models/trends/links.rb
+++ b/app/models/trends/links.rb
@@ -3,6 +3,8 @@
class Trends::Links < Trends::Base
PREFIX = 'trending_links'
+ BATCH_SIZE = 100
+
self.default_options = {
threshold: 5,
review_threshold: 3,
@@ -67,8 +69,21 @@ class Trends::Links < Trends::Base
end
def refresh(at_time = Time.now.utc)
- preview_cards = PreviewCard.where(id: (recently_used_ids(at_time) + PreviewCardTrend.pluck(:preview_card_id)).uniq)
- calculate_scores(preview_cards, at_time)
+ # First, recalculate scores for links that were trending previously. We split the queries
+ # to avoid having to load all of the IDs into Ruby just to send them back into Postgres
+ PreviewCard.where(id: PreviewCardTrend.select(:preview_card_id)).find_in_batches(batch_size: BATCH_SIZE) do |preview_cards|
+ calculate_scores(preview_cards, at_time)
+ end
+
+ # Then, calculate scores for links that were used today. There are potentially some
+ # duplicate items here that we might process one more time, but that should be fine
+ PreviewCard.where(id: recently_used_ids(at_time)).find_in_batches(batch_size: BATCH_SIZE) do |preview_cards|
+ calculate_scores(preview_cards, at_time)
+ end
+
+ # Now that all trends have up-to-date scores, and all the ones below the threshold have
+ # been removed, we can recalculate their positions
+ PreviewCardTrend.connection.exec_update('UPDATE preview_card_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM preview_card_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE preview_card_trends.id = t0.id')
end
def request_review
@@ -139,10 +154,7 @@ class Trends::Links < Trends::Base
to_insert = items.filter { |(score, _)| score >= options[:decay_threshold] }
to_delete = items.filter { |(score, _)| score < options[:decay_threshold] }
- PreviewCardTrend.transaction do
- PreviewCardTrend.upsert_all(to_insert.map { |(score, preview_card)| { preview_card_id: preview_card.id, score: score, language: preview_card.language, allowed: preview_card.trendable? || false } }, unique_by: :preview_card_id) if to_insert.any?
- PreviewCardTrend.where(preview_card_id: to_delete.map { |(_, preview_card)| preview_card.id }).delete_all if to_delete.any?
- PreviewCardTrend.connection.exec_update('UPDATE preview_card_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM preview_card_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE preview_card_trends.id = t0.id')
- end
+ PreviewCardTrend.upsert_all(to_insert.map { |(score, preview_card)| { preview_card_id: preview_card.id, score: score, language: preview_card.language, allowed: preview_card.trendable? || false } }, unique_by: :preview_card_id) if to_insert.any?
+ PreviewCardTrend.where(preview_card_id: to_delete.map { |(_, preview_card)| preview_card.id }).delete_all if to_delete.any?
end
end
diff --git a/app/models/trends/statuses.rb b/app/models/trends/statuses.rb
index d4d5b1c249..52625005e8 100644
--- a/app/models/trends/statuses.rb
+++ b/app/models/trends/statuses.rb
@@ -3,6 +3,8 @@
class Trends::Statuses < Trends::Base
PREFIX = 'trending_statuses'
+ BATCH_SIZE = 100
+
self.default_options = {
threshold: 5,
review_threshold: 3,
@@ -58,8 +60,21 @@ class Trends::Statuses < Trends::Base
end
def refresh(at_time = Time.now.utc)
- statuses = Status.where(id: (recently_used_ids(at_time) + StatusTrend.pluck(:status_id)).uniq).includes(:status_stat, :account)
- calculate_scores(statuses, at_time)
+ # First, recalculate scores for statuses that were trending previously. We split the queries
+ # to avoid having to load all of the IDs into Ruby just to send them back into Postgres
+ Status.where(id: StatusTrend.select(:status_id)).includes(:status_stat, :account).find_in_batches(batch_size: BATCH_SIZE) do |statuses|
+ calculate_scores(statuses, at_time)
+ end
+
+ # Then, calculate scores for statuses that were used today. There are potentially some
+ # duplicate items here that we might process one more time, but that should be fine
+ Status.where(id: recently_used_ids(at_time)).includes(:status_stat, :account).find_in_batches(batch_size: BATCH_SIZE) do |statuses|
+ calculate_scores(statuses, at_time)
+ end
+
+ # Now that all trends have up-to-date scores, and all the ones below the threshold have
+ # been removed, we can recalculate their positions
+ StatusTrend.connection.exec_update('UPDATE status_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM status_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE status_trends.id = t0.id')
end
def request_review
@@ -117,10 +132,7 @@ class Trends::Statuses < Trends::Base
to_insert = items.filter { |(score, _)| score >= options[:decay_threshold] }
to_delete = items.filter { |(score, _)| score < options[:decay_threshold] }
- StatusTrend.transaction do
- StatusTrend.upsert_all(to_insert.map { |(score, status)| { status_id: status.id, account_id: status.account_id, score: score, language: status.language, allowed: status.trendable? || false } }, unique_by: :status_id) if to_insert.any?
- StatusTrend.where(status_id: to_delete.map { |(_, status)| status.id }).delete_all if to_delete.any?
- StatusTrend.connection.exec_update('UPDATE status_trends SET rank = t0.calculated_rank FROM (SELECT id, row_number() OVER w AS calculated_rank FROM status_trends WINDOW w AS (PARTITION BY language ORDER BY score DESC)) t0 WHERE status_trends.id = t0.id')
- end
+ StatusTrend.upsert_all(to_insert.map { |(score, status)| { status_id: status.id, account_id: status.account_id, score: score, language: status.language, allowed: status.trendable? || false } }, unique_by: :status_id) if to_insert.any?
+ StatusTrend.where(status_id: to_delete.map { |(_, status)| status.id }).delete_all if to_delete.any?
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index e5ec2447c1..674135eea2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -475,7 +475,7 @@ class User < ApplicationRecord
User.those_who_can(:manage_users).includes(:account).find_each do |u|
next unless u.allows_pending_account_emails?
- AdminMailer.new_pending_account(u.account, self).deliver_later
+ AdminMailer.with(recipient: u.account).new_pending_account(self).deliver_later
end
end
diff --git a/app/services/appeal_service.rb b/app/services/appeal_service.rb
index 399a053d6a..ef052e3547 100644
--- a/app/services/appeal_service.rb
+++ b/app/services/appeal_service.rb
@@ -23,7 +23,7 @@ class AppealService < BaseService
def notify_staff!
User.those_who_can(:manage_appeals).includes(:account).each do |u|
- AdminMailer.new_appeal(u.account, @appeal).deliver_later if u.allows_appeal_emails?
+ AdminMailer.with(recipient: u.account).new_appeal(@appeal).deliver_later if u.allows_appeal_emails?
end
end
end
diff --git a/app/services/report_service.rb b/app/services/report_service.rb
index 3444e1dfaf..39ebd5cd8a 100644
--- a/app/services/report_service.rb
+++ b/app/services/report_service.rb
@@ -40,7 +40,7 @@ class ReportService < BaseService
User.those_who_can(:manage_reports).includes(:account).each do |u|
LocalNotificationWorker.perform_async(u.account_id, @report.id, 'Report', 'admin.report')
- AdminMailer.new_report(u.account, @report).deliver_later if u.allows_report_emails?
+ AdminMailer.with(recipient: u.account).new_report(@report).deliver_later if u.allows_report_emails?
end
end
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index fabb108019..e5001833d0 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -71,6 +71,7 @@ ignore_unused:
- 'statuses.attached.*'
- 'themes.*'
- 'move_handler.carry_{mutes,blocks}_over_text'
+ - 'admin_mailer.*.subject'
- 'notification_mailer.*'
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb
index 01b7e4a71c..f923ff0794 100644
--- a/spec/controllers/api/v1/reports_controller_spec.rb
+++ b/spec/controllers/api/v1/reports_controller_spec.rb
@@ -23,8 +23,6 @@ RSpec.describe Api::V1::ReportsController do
let(:rule_ids) { nil }
before do
- allow(AdminMailer).to receive(:new_report)
- .and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward }
end
@@ -41,7 +39,7 @@ RSpec.describe Api::V1::ReportsController do
end
it 'sends e-mails to admins' do
- expect(AdminMailer).to have_received(:new_report).with(admin.account, Report)
+ expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
end
context 'when a status does not belong to the reported account' do
diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb
index a0f9c7b910..c8444a2a96 100644
--- a/spec/controllers/disputes/appeals_controller_spec.rb
+++ b/spec/controllers/disputes/appeals_controller_spec.rb
@@ -14,13 +14,11 @@ RSpec.describe Disputes::AppealsController do
let(:strike) { Fabricate(:account_warning, target_account: current_user.account) }
before do
- allow(AdminMailer).to receive(:new_appeal)
- .and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
post :create, params: { strike_id: strike.id, appeal: { text: 'Foo' } }
end
it 'notifies staff about new appeal' do
- expect(AdminMailer).to have_received(:new_appeal).with(admin.account, Appeal.last)
+ expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
end
it 'redirects back to the strike page' do
diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb
index 8e2eec40fd..9123804a48 100644
--- a/spec/mailers/admin_mailer_spec.rb
+++ b/spec/mailers/admin_mailer_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe AdminMailer do
let(:sender) { Fabricate(:account, username: 'John') }
let(:recipient) { Fabricate(:account, username: 'Mike') }
let(:report) { Fabricate(:report, account: sender, target_account: recipient) }
- let(:mail) { described_class.new_report(recipient, report) }
+ let(:mail) { described_class.with(recipient: recipient).new_report(report) }
before do
recipient.user.update(locale: :en)
@@ -27,7 +27,7 @@ RSpec.describe AdminMailer do
describe '.new_appeal' do
let(:appeal) { Fabricate(:appeal) }
let(:recipient) { Fabricate(:account, username: 'Kurt') }
- let(:mail) { described_class.new_appeal(recipient, appeal) }
+ let(:mail) { described_class.with(recipient: recipient).new_appeal(appeal) }
before do
recipient.user.update(locale: :en)
@@ -47,7 +47,7 @@ RSpec.describe AdminMailer do
describe '.new_pending_account' do
let(:recipient) { Fabricate(:account, username: 'Barklums') }
let(:user) { Fabricate(:user) }
- let(:mail) { described_class.new_pending_account(recipient, user) }
+ let(:mail) { described_class.with(recipient: recipient).new_pending_account(user) }
before do
recipient.user.update(locale: :en)
@@ -69,7 +69,7 @@ RSpec.describe AdminMailer do
let(:links) { [] }
let(:statuses) { [] }
let(:tags) { [] }
- let(:mail) { described_class.new_trends(recipient, links, tags, statuses) }
+ let(:mail) { described_class.with(recipient: recipient).new_trends(links, tags, statuses) }
before do
recipient.user.update(locale: :en)
diff --git a/spec/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb
index 9572768cd7..bc8f0193b9 100644
--- a/spec/mailers/previews/admin_mailer_preview.rb
+++ b/spec/mailers/previews/admin_mailer_preview.rb
@@ -5,16 +5,16 @@
class AdminMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_pending_account
def new_pending_account
- AdminMailer.new_pending_account(Account.first, User.pending.first)
+ AdminMailer.with(recipient: Account.first).new_pending_account(User.pending.first)
end
# Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_trends
def new_trends
- AdminMailer.new_trends(Account.first, PreviewCard.joins(:trend).limit(3), Tag.limit(3), Status.joins(:trend).where(reblog_of_id: nil).limit(3))
+ AdminMailer.with(recipient: Account.first).new_trends(PreviewCard.joins(:trend).limit(3), Tag.limit(3), Status.joins(:trend).where(reblog_of_id: nil).limit(3))
end
# Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal
def new_appeal
- AdminMailer.new_appeal(Account.first, Appeal.first)
+ AdminMailer.with(recipient: Account.first).new_appeal(Appeal.first)
end
end
diff --git a/spec/mailers/previews/notification_mailer_preview.rb b/spec/mailers/previews/notification_mailer_preview.rb
index bc41662a16..214161881b 100644
--- a/spec/mailers/previews/notification_mailer_preview.rb
+++ b/spec/mailers/previews/notification_mailer_preview.rb
@@ -32,9 +32,4 @@ class NotificationMailerPreview < ActionMailer::Preview
r = Status.where.not(reblog_of_id: nil).first
NotificationMailer.reblog(r.reblog.account, Notification.find_by(activity: r))
end
-
- # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/digest
- def digest
- NotificationMailer.digest(Account.first, since: 90.days.ago)
- end
end