Merge pull request #2392 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes into glitch-socth-downstream
commit
2514c0efa1
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "Mastodon on GitHub Codespaces",
|
||||||
|
"dockerComposeFile": "../docker-compose.yml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/sshd:1": {}
|
||||||
|
},
|
||||||
|
|
||||||
|
"runServices": ["app", "db", "redis"],
|
||||||
|
|
||||||
|
"forwardPorts": [3000, 4000],
|
||||||
|
|
||||||
|
"portsAttributes": {
|
||||||
|
"3000": {
|
||||||
|
"label": "web",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
},
|
||||||
|
"4000": {
|
||||||
|
"label": "stream",
|
||||||
|
"onAutoForward": "silent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"otherPortsAttributes": {
|
||||||
|
"onAutoForward": "silent"
|
||||||
|
},
|
||||||
|
|
||||||
|
"remoteEnv": {
|
||||||
|
"LOCAL_DOMAIN": "${localEnv:CODESPACE_NAME}-3000.app.github.dev",
|
||||||
|
"LOCAL_HTTPS": "true",
|
||||||
|
"STREAMING_API_BASE_URL": "https://${localEnv:CODESPACE_NAME}-4000.app.github.dev",
|
||||||
|
"DISABLE_FORGERY_REQUEST_PROTECTION": "true",
|
||||||
|
"ES_ENABLED": "",
|
||||||
|
"LIBRE_TRANSLATE_ENDPOINT": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
||||||
|
"postCreateCommand": ".devcontainer/post-create.sh",
|
||||||
|
"waitFor": "postCreateCommand",
|
||||||
|
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"settings": {},
|
||||||
|
"extensions": ["EditorConfig.EditorConfig", "webben.browserslist"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
||||||
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
||||||
stream: env PORT=4000 yarn run start
|
stream: env PORT=4000 yarn run start
|
||||||
webpack: ./bin/webpack-dev-server --listen-host 0.0.0.0
|
webpack: bin/webpack-dev-server
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class PublicStatusesIndex < Chewy::Index
|
||||||
|
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: {
|
||||||
|
filter: {
|
||||||
|
english_stop: {
|
||||||
|
type: 'stop',
|
||||||
|
stopwords: '_english_',
|
||||||
|
},
|
||||||
|
|
||||||
|
english_stemmer: {
|
||||||
|
type: 'stemmer',
|
||||||
|
language: 'english',
|
||||||
|
},
|
||||||
|
|
||||||
|
english_possessive_stemmer: {
|
||||||
|
type: 'stemmer',
|
||||||
|
language: 'possessive_english',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
analyzer: {
|
||||||
|
verbatim: {
|
||||||
|
tokenizer: 'uax_url_email',
|
||||||
|
filter: %w(lowercase),
|
||||||
|
},
|
||||||
|
|
||||||
|
content: {
|
||||||
|
tokenizer: 'standard',
|
||||||
|
filter: %w(
|
||||||
|
lowercase
|
||||||
|
asciifolding
|
||||||
|
cjk_width
|
||||||
|
elision
|
||||||
|
english_possessive_stemmer
|
||||||
|
english_stop
|
||||||
|
english_stemmer
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
index_scope ::Status.unscoped
|
||||||
|
.kept
|
||||||
|
.indexable
|
||||||
|
.includes(:media_attachments, :preloadable_poll, :preview_cards)
|
||||||
|
|
||||||
|
root date_detection: false do
|
||||||
|
field(:id, type: 'long')
|
||||||
|
field(:account_id, type: 'long')
|
||||||
|
field(:text, type: 'text', analyzer: 'verbatim', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'content') }
|
||||||
|
field(:language, type: 'keyword')
|
||||||
|
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
|
||||||
|
field(:created_at, type: 'date')
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class SoftwareUpdatesController < BaseController
|
||||||
|
before_action :check_enabled!
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize :software_update, :index?
|
||||||
|
@software_updates = SoftwareUpdate.all.sort_by(&:gem_version)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_enabled!
|
||||||
|
not_found unless SoftwareUpdate.check_enabled?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AuthorizedFetchHelper
|
||||||
|
def authorized_fetch_mode?
|
||||||
|
ENV.fetch('AUTHORIZED_FETCH') { Setting.authorized_fetch } == 'true' || Rails.configuration.x.limited_federation_mode
|
||||||
|
end
|
||||||
|
|
||||||
|
def authorized_fetch_overridden?
|
||||||
|
ENV.key?('AUTHORIZED_FETCH') || Rails.configuration.x.limited_federation_mode
|
||||||
|
end
|
||||||
|
end
|
@ -1,28 +0,0 @@
|
|||||||
// This file will be loaded on public pages, regardless of theme.
|
|
||||||
|
|
||||||
import 'packs/public-path';
|
|
||||||
|
|
||||||
import { delegate } from '@rails/ujs';
|
|
||||||
|
|
||||||
const getProfileAvatarAnimationHandler = (swapTo) => {
|
|
||||||
//animate avatar gifs on the profile page when moused over
|
|
||||||
return ({ target }) => {
|
|
||||||
const swapSrc = target.getAttribute(swapTo);
|
|
||||||
//only change the img source if autoplay is off and the image src is actually different
|
|
||||||
if(target.getAttribute('data-autoplay') !== 'true' && target.src !== swapSrc) {
|
|
||||||
target.src = swapSrc;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
delegate(document, 'img#profile_page_avatar', 'mouseover', getProfileAvatarAnimationHandler('data-original'));
|
|
||||||
|
|
||||||
delegate(document, 'img#profile_page_avatar', 'mouseout', getProfileAvatarAnimationHandler('data-static'));
|
|
||||||
|
|
||||||
delegate(document, '#account_header', 'change', ({ target }) => {
|
|
||||||
const header = document.querySelector('.card .card__img img');
|
|
||||||
const [file] = target.files || [];
|
|
||||||
const url = file ? URL.createObjectURL(file) : header.dataset.originalSrc;
|
|
||||||
|
|
||||||
header.src = url;
|
|
||||||
});
|
|
@ -0,0 +1,26 @@
|
|||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
export const CriticalUpdateBanner = () => (
|
||||||
|
<div className='warning-banner'>
|
||||||
|
<div className='warning-banner__message'>
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.title'
|
||||||
|
defaultMessage='Critical security update available!'
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.body'
|
||||||
|
defaultMessage='Please update your Mastodon server as soon as possible!'
|
||||||
|
/>{' '}
|
||||||
|
<a href='/admin/software_updates'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.link'
|
||||||
|
defaultMessage='See updates'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,26 @@
|
|||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
export const CriticalUpdateBanner = () => (
|
||||||
|
<div className='warning-banner'>
|
||||||
|
<div className='warning-banner__message'>
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.title'
|
||||||
|
defaultMessage='Critical security update available!'
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.body'
|
||||||
|
defaultMessage='Please update your Mastodon server as soon as possible!'
|
||||||
|
/>{' '}
|
||||||
|
<a href='/admin/software_updates'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='home.pending_critical_update.link'
|
||||||
|
defaultMessage='See updates'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
@ -1 +1 @@
|
|||||||
import '@testing-library/jest-dom/extend-expect';
|
import '@testing-library/jest-dom';
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Admin::SystemCheck::SoftwareVersionCheck < Admin::SystemCheck::BaseCheck
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
|
def skip?
|
||||||
|
!current_user.can?(:view_devops) || !SoftwareUpdate.check_enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def pass?
|
||||||
|
software_updates.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def message
|
||||||
|
if software_updates.any?(&:urgent?)
|
||||||
|
Admin::SystemCheck::Message.new(:software_version_critical_check, nil, admin_software_updates_path, true)
|
||||||
|
else
|
||||||
|
Admin::SystemCheck::Message.new(:software_version_patch_check, nil, admin_software_updates_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def software_updates
|
||||||
|
@software_updates ||= SoftwareUpdate.pending_to_a.filter { |update| update.urgent? || update.patch_type? }
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,32 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Importer::PublicStatusesIndexImporter < Importer::BaseImporter
|
||||||
|
def import!
|
||||||
|
scope.select(:id).find_in_batches(batch_size: @batch_size) do |batch|
|
||||||
|
in_work_unit(batch.pluck(:id)) do |status_ids|
|
||||||
|
bulk = ActiveRecord::Base.connection_pool.with_connection do
|
||||||
|
build_bulk_body(index.adapter.default_scope.where(id: status_ids))
|
||||||
|
end
|
||||||
|
|
||||||
|
indexed = bulk.size
|
||||||
|
deleted = 0
|
||||||
|
|
||||||
|
Chewy::Index::Import::BulkRequest.new(index).perform(bulk)
|
||||||
|
|
||||||
|
[indexed, deleted]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wait!
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def index
|
||||||
|
PublicStatusesIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
def scope
|
||||||
|
Status.indexable
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,44 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AccountStatusesSearch
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
after_update_commit :enqueue_update_public_statuses_index, if: :saved_change_to_indexable?
|
||||||
|
after_destroy_commit :enqueue_remove_from_public_statuses_index, if: :indexable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def enqueue_update_public_statuses_index
|
||||||
|
if indexable?
|
||||||
|
enqueue_add_to_public_statuses_index
|
||||||
|
else
|
||||||
|
enqueue_remove_from_public_statuses_index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def enqueue_add_to_public_statuses_index
|
||||||
|
return unless Chewy.enabled?
|
||||||
|
|
||||||
|
AddToPublicStatusesIndexWorker.perform_async(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def enqueue_remove_from_public_statuses_index
|
||||||
|
return unless Chewy.enabled?
|
||||||
|
|
||||||
|
RemoveFromPublicStatusesIndexWorker.perform_async(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_to_public_statuses_index!
|
||||||
|
return unless Chewy.enabled?
|
||||||
|
|
||||||
|
statuses.without_reblogs.where(visibility: :public).find_in_batches do |batch|
|
||||||
|
PublicStatusesIndex.import(batch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_from_public_statuses_index!
|
||||||
|
return unless Chewy.enabled?
|
||||||
|
|
||||||
|
PublicStatusesIndex.filter(term: { account_id: id }).delete_all
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,48 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module StatusSearchConcern
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :indexable, -> { without_reblogs.where(visibility: :public).joins(:account).where(account: { indexable: true }) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_by
|
||||||
|
@searchable_by ||= begin
|
||||||
|
ids = []
|
||||||
|
|
||||||
|
ids << account_id if local?
|
||||||
|
|
||||||
|
ids += local_mentioned.pluck(:id)
|
||||||
|
ids += local_favorited.pluck(:id)
|
||||||
|
ids += local_reblogged.pluck(:id)
|
||||||
|
ids += local_bookmarked.pluck(:id)
|
||||||
|
ids += preloadable_poll.local_voters.pluck(:id) if preloadable_poll.present?
|
||||||
|
|
||||||
|
ids.uniq
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_text
|
||||||
|
[
|
||||||
|
spoiler_text,
|
||||||
|
FormattingHelper.extract_status_plain_text(self),
|
||||||
|
preloadable_poll&.options&.join("\n\n"),
|
||||||
|
ordered_media_attachments.map(&:description).join("\n\n"),
|
||||||
|
].compact.join("\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def searchable_properties
|
||||||
|
[].tap do |properties|
|
||||||
|
properties << 'image' if ordered_media_attachments.any?(&:image?)
|
||||||
|
properties << 'video' if ordered_media_attachments.any?(&:video?)
|
||||||
|
properties << 'audio' if ordered_media_attachments.any?(&:audio?)
|
||||||
|
properties << 'media' if with_media?
|
||||||
|
properties << 'poll' if with_poll?
|
||||||
|
properties << 'link' if with_preview_card?
|
||||||
|
properties << 'embed' if preview_cards.any?(&:video?)
|
||||||
|
properties << 'sensitive' if sensitive?
|
||||||
|
properties << 'reply' if reply?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: software_updates
|
||||||
|
#
|
||||||
|
# id :bigint(8) not null, primary key
|
||||||
|
# version :string not null
|
||||||
|
# urgent :boolean default(FALSE), not null
|
||||||
|
# type :integer default("patch"), not null
|
||||||
|
# release_notes :string default(""), not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
|
||||||
|
class SoftwareUpdate < ApplicationRecord
|
||||||
|
self.inheritance_column = nil
|
||||||
|
|
||||||
|
enum type: { patch: 0, minor: 1, major: 2 }, _suffix: :type
|
||||||
|
|
||||||
|
def gem_version
|
||||||
|
Gem::Version.new(version)
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def check_enabled?
|
||||||
|
ENV['UPDATE_CHECK_URL'] != ''
|
||||||
|
end
|
||||||
|
|
||||||
|
def pending_to_a
|
||||||
|
return [] unless check_enabled?
|
||||||
|
|
||||||
|
all.to_a.filter { |update| update.gem_version > Mastodon::Version.gem_version }
|
||||||
|
end
|
||||||
|
|
||||||
|
def urgent_pending?
|
||||||
|
pending_to_a.any?(&:urgent?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SoftwareUpdatePolicy < ApplicationPolicy
|
||||||
|
def index?
|
||||||
|
role.can?(:view_devops)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,82 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SoftwareUpdateCheckService < BaseService
|
||||||
|
def call
|
||||||
|
clean_outdated_updates!
|
||||||
|
return unless SoftwareUpdate.check_enabled?
|
||||||
|
|
||||||
|
process_update_notices!(fetch_update_notices)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def clean_outdated_updates!
|
||||||
|
SoftwareUpdate.find_each do |software_update|
|
||||||
|
software_update.delete if Mastodon::Version.gem_version >= software_update.gem_version
|
||||||
|
rescue ArgumentError
|
||||||
|
software_update.delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_update_notices
|
||||||
|
Request.new(:get, "#{api_url}?version=#{version}").add_headers('Accept' => 'application/json', 'User-Agent' => 'Mastodon update checker').perform do |res|
|
||||||
|
return Oj.load(res.body_with_limit, mode: :strict) if res.code == 200
|
||||||
|
end
|
||||||
|
rescue HTTP::Error, OpenSSL::SSL::SSLError, Oj::ParseError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_url
|
||||||
|
ENV.fetch('UPDATE_CHECK_URL', 'https://api.joinmastodon.org/update-check')
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
|
@version ||= Mastodon::Version.to_s.split('+')[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_update_notices!(update_notices)
|
||||||
|
return if update_notices.blank? || update_notices['updatesAvailable'].blank?
|
||||||
|
|
||||||
|
# Clear notices that are not listed by the update server anymore
|
||||||
|
SoftwareUpdate.where.not(version: update_notices['updatesAvailable'].pluck('version')).delete_all
|
||||||
|
|
||||||
|
# Check if any of the notices is new, and issue notifications
|
||||||
|
known_versions = SoftwareUpdate.where(version: update_notices['updatesAvailable'].pluck('version')).pluck(:version)
|
||||||
|
new_update_notices = update_notices['updatesAvailable'].filter { |notice| known_versions.exclude?(notice['version']) }
|
||||||
|
return if new_update_notices.blank?
|
||||||
|
|
||||||
|
new_updates = new_update_notices.map do |notice|
|
||||||
|
SoftwareUpdate.create!(version: notice['version'], urgent: notice['urgent'], type: notice['type'], release_notes: notice['releaseNotes'])
|
||||||
|
end
|
||||||
|
|
||||||
|
notify_devops!(new_updates)
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_notify_user?(user, urgent_version, patch_version)
|
||||||
|
case user.settings['notification_emails.software_updates']
|
||||||
|
when 'none'
|
||||||
|
false
|
||||||
|
when 'critical'
|
||||||
|
urgent_version
|
||||||
|
when 'patch'
|
||||||
|
urgent_version || patch_version
|
||||||
|
when 'all'
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def notify_devops!(new_updates)
|
||||||
|
has_new_urgent_version = new_updates.any?(&:urgent?)
|
||||||
|
has_new_patch_version = new_updates.any?(&:patch_type?)
|
||||||
|
|
||||||
|
User.those_who_can(:view_devops).includes(:account).find_each do |user|
|
||||||
|
next unless should_notify_user?(user, has_new_urgent_version, has_new_patch_version)
|
||||||
|
|
||||||
|
if has_new_urgent_version
|
||||||
|
AdminMailer.with(recipient: user.account).new_critical_software_updates.deliver_later
|
||||||
|
else
|
||||||
|
AdminMailer.with(recipient: user.account).new_software_updates.deliver_later
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,64 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class StatusesSearchService < BaseService
|
||||||
|
def call(query, account = nil, options = {})
|
||||||
|
@query = query&.strip
|
||||||
|
@account = account
|
||||||
|
@options = options
|
||||||
|
@limit = options[:limit].to_i
|
||||||
|
@offset = options[:offset].to_i
|
||||||
|
|
||||||
|
status_search_results
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def status_search_results
|
||||||
|
definition = parsed_query.apply(
|
||||||
|
Chewy::Search::Request.new(StatusesIndex, PublicStatusesIndex).filter(
|
||||||
|
bool: {
|
||||||
|
should: [
|
||||||
|
publicly_searchable,
|
||||||
|
non_publicly_searchable,
|
||||||
|
],
|
||||||
|
|
||||||
|
minimum_should_match: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
results = definition.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact
|
||||||
|
account_ids = results.map(&:account_id)
|
||||||
|
account_domains = results.map(&:account_domain)
|
||||||
|
preloaded_relations = @account.relations_map(account_ids, account_domains)
|
||||||
|
|
||||||
|
results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? }
|
||||||
|
rescue Faraday::ConnectionFailed, Parslet::ParseFailed
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
def publicly_searchable
|
||||||
|
{
|
||||||
|
term: { _index: PublicStatusesIndex.index_name },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def non_publicly_searchable
|
||||||
|
{
|
||||||
|
bool: {
|
||||||
|
must: [
|
||||||
|
{
|
||||||
|
term: { _index: StatusesIndex.index_name },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
term: { searchable_by: @account.id },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def parsed_query
|
||||||
|
SearchQueryTransformer.new.apply(SearchQueryParser.new.parse(@query), current_account: @account)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,29 @@
|
|||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.software_updates.title')
|
||||||
|
|
||||||
|
.simple_form
|
||||||
|
%p.lead
|
||||||
|
= t('admin.software_updates.description')
|
||||||
|
= link_to t('admin.software_updates.documentation_link'), 'https://docs.joinmastodon.org/admin/upgrading/#automated_checks', target: '_new'
|
||||||
|
|
||||||
|
%hr.spacer
|
||||||
|
|
||||||
|
- unless @software_updates.empty?
|
||||||
|
.table-wrapper
|
||||||
|
%table.table
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th= t('admin.software_updates.version')
|
||||||
|
%th= t('admin.software_updates.type')
|
||||||
|
%th
|
||||||
|
%th
|
||||||
|
%tbody
|
||||||
|
- @software_updates.each do |update|
|
||||||
|
%tr
|
||||||
|
%td= update.version
|
||||||
|
%td= t("admin.software_updates.types.#{update.type}")
|
||||||
|
- if update.urgent?
|
||||||
|
%td.critical= t("admin.software_updates.critical_update")
|
||||||
|
- else
|
||||||
|
%td
|
||||||
|
%td= table_link_to 'link', t('admin.software_updates.release_notes'), update.release_notes
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue