Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `app/controllers/activitypub/collections_controller.rb`: Conflict caused because we have additional code to make sure pinned local-only toots don't get rendered on the ActivityPub endpoints. Ported upstream changes.main
commit
e5f934ddf0
|
@ -12,7 +12,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
|
|
||||||
def show
|
def show
|
||||||
expires_in 3.minutes, public: public_fetch_mode?
|
expires_in 3.minutes, public: public_fetch_mode?
|
||||||
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter, skip_activities: true
|
render_with_cache json: collection_presenter, content_type: 'application/activity+json', serializer: ActivityPub::CollectionSerializer, adapter: ActivityPub::Adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -20,17 +20,9 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
def set_items
|
def set_items
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured'
|
when 'featured'
|
||||||
@items = begin
|
@items = for_signed_account { cache_collection(@account.pinned_statuses.not_local_only, Status) }
|
||||||
# Because in public fetch mode we cache the response, there would be no
|
when 'tags'
|
||||||
# benefit from performing the check below, since a blocked account or domain
|
@items = for_signed_account { @account.featured_tags }
|
||||||
# would likely be served the cache from the reverse proxy anyway
|
|
||||||
|
|
||||||
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
cache_collection(@account.pinned_statuses.not_local_only, Status)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
when 'devices'
|
when 'devices'
|
||||||
@items = @account.devices
|
@items = @account.devices
|
||||||
else
|
else
|
||||||
|
@ -40,7 +32,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
|
|
||||||
def set_size
|
def set_size
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured', 'devices'
|
when 'featured', 'devices', 'tags'
|
||||||
@size = @items.size
|
@size = @items.size
|
||||||
else
|
else
|
||||||
not_found
|
not_found
|
||||||
|
@ -51,7 +43,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'featured'
|
when 'featured'
|
||||||
@type = :ordered
|
@type = :ordered
|
||||||
when 'devices'
|
when 'devices', 'tags'
|
||||||
@type = :unordered
|
@type = :unordered
|
||||||
else
|
else
|
||||||
not_found
|
not_found
|
||||||
|
@ -66,4 +58,16 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
||||||
items: @items
|
items: @items
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def for_signed_account
|
||||||
|
# Because in public fetch mode we cache the response, there would be no
|
||||||
|
# benefit from performing the check below, since a blocked account or domain
|
||||||
|
# would likely be served the cache from the reverse proxy anyway
|
||||||
|
|
||||||
|
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,9 +20,9 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
def outbox_presenter
|
def outbox_presenter
|
||||||
if page_requested?
|
if page_requested?
|
||||||
ActivityPub::CollectionPresenter.new(
|
ActivityPub::CollectionPresenter.new(
|
||||||
id: account_outbox_url(@account, page_params),
|
id: outbox_url(page_params),
|
||||||
type: :ordered,
|
type: :ordered,
|
||||||
part_of: account_outbox_url(@account),
|
part_of: outbox_url,
|
||||||
prev: prev_page,
|
prev: prev_page,
|
||||||
next: next_page,
|
next: next_page,
|
||||||
items: @statuses
|
items: @statuses
|
||||||
|
@ -32,12 +32,20 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
id: account_outbox_url(@account),
|
id: account_outbox_url(@account),
|
||||||
type: :ordered,
|
type: :ordered,
|
||||||
size: @account.statuses_count,
|
size: @account.statuses_count,
|
||||||
first: account_outbox_url(@account, page: true),
|
first: outbox_url(page: true),
|
||||||
last: account_outbox_url(@account, page: true, min_id: 0)
|
last: outbox_url(page: true, min_id: 0)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def outbox_url(**kwargs)
|
||||||
|
if params[:account_username].present?
|
||||||
|
account_outbox_url(@account, **kwargs)
|
||||||
|
else
|
||||||
|
instance_actor_outbox_url(**kwargs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def next_page
|
def next_page
|
||||||
account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT
|
account_outbox_url(@account, page: true, max_id: @statuses.last.id) if @statuses.size == LIMIT
|
||||||
end
|
end
|
||||||
|
@ -65,4 +73,8 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
def page_params
|
def page_params
|
||||||
{ page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact
|
{ page: true, max_id: params[:max_id], min_id: params[:min_id] }.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = params[:account_username].present? ? Account.find_local!(username_param) : Account.representative
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Api::V1::Accounts::FeaturedTagsController < Api::BaseController
|
||||||
|
before_action :set_account
|
||||||
|
before_action :set_featured_tags
|
||||||
|
|
||||||
|
respond_to :json
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @featured_tags, each_serializer: REST::AccountFeaturedTagSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Account.find(params[:account_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_featured_tags
|
||||||
|
@featured_tags = @account.featured_tags
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,6 +17,6 @@ class InstanceActorsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def restrict_fields_to
|
def restrict_fields_to
|
||||||
%i(id type preferred_username inbox public_key endpoints url manually_approves_followers)
|
%i(id type preferred_username inbox outbox public_key endpoints url manually_approves_followers)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import api, { getLinks } from '../api';
|
import api, { getLinks } from '../api';
|
||||||
import openDB from '../storage/db';
|
import { importFetchedAccount, importFetchedAccounts } from './importer';
|
||||||
import { importAccount, importFetchedAccount, importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
||||||
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
|
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
|
||||||
|
@ -74,45 +73,13 @@ export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST';
|
||||||
export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';
|
export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS';
|
||||||
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
|
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL';
|
||||||
|
|
||||||
function getFromDB(dispatch, getState, index, id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const request = index.get(id);
|
|
||||||
|
|
||||||
request.onerror = reject;
|
|
||||||
|
|
||||||
request.onsuccess = () => {
|
|
||||||
if (!request.result) {
|
|
||||||
reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(importAccount(request.result));
|
|
||||||
resolve(request.result.moved && getFromDB(dispatch, getState, index, request.result.moved));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchAccount(id) {
|
export function fetchAccount(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchRelationships([id]));
|
dispatch(fetchRelationships([id]));
|
||||||
|
|
||||||
if (getState().getIn(['accounts', id], null) !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchAccountRequest(id));
|
dispatch(fetchAccountRequest(id));
|
||||||
|
|
||||||
openDB().then(db => getFromDB(
|
api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
||||||
dispatch,
|
|
||||||
getState,
|
|
||||||
db.transaction('accounts', 'read').objectStore('accounts').index('id'),
|
|
||||||
id,
|
|
||||||
).then(() => db.close(), error => {
|
|
||||||
db.close();
|
|
||||||
throw error;
|
|
||||||
})).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => {
|
|
||||||
dispatch(importFetchedAccount(response.data));
|
dispatch(importFetchedAccount(response.data));
|
||||||
})).then(() => {
|
|
||||||
dispatch(fetchAccountSuccess());
|
dispatch(fetchAccountSuccess());
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchAccountFail(id, error));
|
dispatch(fetchAccountFail(id, error));
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
import openDB from '../storage/db';
|
|
||||||
import { evictStatus } from '../storage/modifier';
|
|
||||||
|
|
||||||
import { deleteFromTimelines } from './timelines';
|
import { deleteFromTimelines } from './timelines';
|
||||||
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus, importFetchedAccount } from './importer';
|
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from './importer';
|
||||||
import { ensureComposeIsVisible } from './compose';
|
import { ensureComposeIsVisible } from './compose';
|
||||||
|
|
||||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
|
||||||
|
@ -40,48 +38,6 @@ export function fetchStatusRequest(id, skipLoading) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function getFromDB(dispatch, getState, accountIndex, index, id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const request = index.get(id);
|
|
||||||
|
|
||||||
request.onerror = reject;
|
|
||||||
|
|
||||||
request.onsuccess = () => {
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
if (!request.result) {
|
|
||||||
reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(importStatus(request.result));
|
|
||||||
|
|
||||||
if (getState().getIn(['accounts', request.result.account], null) === null) {
|
|
||||||
promises.push(new Promise((accountResolve, accountReject) => {
|
|
||||||
const accountRequest = accountIndex.get(request.result.account);
|
|
||||||
|
|
||||||
accountRequest.onerror = accountReject;
|
|
||||||
accountRequest.onsuccess = () => {
|
|
||||||
if (!request.result) {
|
|
||||||
accountReject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(importAccount(accountRequest.result));
|
|
||||||
accountResolve();
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) {
|
|
||||||
promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog));
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(Promise.all(promises));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchStatus(id) {
|
export function fetchStatus(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const skipLoading = getState().getIn(['statuses', id], null) !== null;
|
const skipLoading = getState().getIn(['statuses', id], null) !== null;
|
||||||
|
@ -94,23 +50,10 @@ export function fetchStatus(id) {
|
||||||
|
|
||||||
dispatch(fetchStatusRequest(id, skipLoading));
|
dispatch(fetchStatusRequest(id, skipLoading));
|
||||||
|
|
||||||
openDB().then(db => {
|
api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
||||||
const transaction = db.transaction(['accounts', 'statuses'], 'read');
|
|
||||||
const accountIndex = transaction.objectStore('accounts').index('id');
|
|
||||||
const index = transaction.objectStore('statuses').index('id');
|
|
||||||
|
|
||||||
return getFromDB(dispatch, getState, accountIndex, index, id).then(() => {
|
|
||||||
db.close();
|
|
||||||
}, error => {
|
|
||||||
db.close();
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}).then(() => {
|
|
||||||
dispatch(fetchStatusSuccess(skipLoading));
|
|
||||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => {
|
|
||||||
dispatch(importFetchedStatus(response.data));
|
dispatch(importFetchedStatus(response.data));
|
||||||
dispatch(fetchStatusSuccess(skipLoading));
|
dispatch(fetchStatusSuccess(skipLoading));
|
||||||
})).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchStatusFail(id, error, skipLoading));
|
dispatch(fetchStatusFail(id, error, skipLoading));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -152,7 +95,6 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
|
||||||
dispatch(deleteStatusRequest(id));
|
dispatch(deleteStatusRequest(id));
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
|
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
|
||||||
evictStatus(id);
|
|
||||||
dispatch(deleteStatusSuccess(id));
|
dispatch(deleteStatusSuccess(id));
|
||||||
dispatch(deleteFromTimelines(id));
|
dispatch(deleteFromTimelines(id));
|
||||||
dispatch(importFetchedAccount(response.data.account));
|
dispatch(importFetchedAccount(response.data.account));
|
||||||
|
|
|
@ -256,14 +256,6 @@ html {
|
||||||
background: $ui-base-color;
|
background: $ui-base-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.status-direct {
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.focusable:focus .status.status-direct {
|
|
||||||
background: lighten($ui-base-color, 8%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailed-status,
|
.detailed-status,
|
||||||
.detailed-status__action-bar {
|
.detailed-status__action-bar {
|
||||||
background: $white;
|
background: $white;
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
|
||||||
moved_to: { 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' } },
|
moved_to: { 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' } },
|
||||||
also_known_as: { 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' } },
|
also_known_as: { 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' } },
|
||||||
emoji: { 'toot' => 'http://joinmastodon.org/ns#', 'Emoji' => 'toot:Emoji' },
|
emoji: { 'toot' => 'http://joinmastodon.org/ns#', 'Emoji' => 'toot:Emoji' },
|
||||||
featured: { 'toot' => 'http://joinmastodon.org/ns#', 'featured' => { '@id' => 'toot:featured', '@type' => '@id' } },
|
featured: { 'toot' => 'http://joinmastodon.org/ns#', 'featured' => { '@id' => 'toot:featured', '@type' => '@id' }, 'featuredTags' => { '@id' => 'toot:featuredTags', '@type' => '@id' } },
|
||||||
property_value: { 'schema' => 'http://schema.org#', 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value' },
|
property_value: { 'schema' => 'http://schema.org#', 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value' },
|
||||||
atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },
|
atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },
|
||||||
conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },
|
conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },
|
||||||
|
|
|
@ -10,7 +10,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
:discoverable, :olm
|
:discoverable, :olm
|
||||||
|
|
||||||
attributes :id, :type, :following, :followers,
|
attributes :id, :type, :following, :followers,
|
||||||
:inbox, :outbox, :featured,
|
:inbox, :outbox, :featured, :featured_tags,
|
||||||
:preferred_username, :name, :summary,
|
:preferred_username, :name, :summary,
|
||||||
:url, :manually_approves_followers,
|
:url, :manually_approves_followers,
|
||||||
:discoverable
|
:discoverable
|
||||||
|
@ -74,13 +74,17 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def outbox
|
def outbox
|
||||||
account_outbox_url(object)
|
object.instance_actor? ? instance_actor_outbox_url : account_outbox_url(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def featured
|
def featured
|
||||||
account_collection_url(object, :featured)
|
account_collection_url(object, :featured)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def featured_tags
|
||||||
|
account_collection_url(object, :tags)
|
||||||
|
end
|
||||||
|
|
||||||
def endpoints
|
def endpoints
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,8 @@ class ActivityPub::CollectionSerializer < ActivityPub::Serializer
|
||||||
ActivityPub::NoteSerializer
|
ActivityPub::NoteSerializer
|
||||||
when 'Device'
|
when 'Device'
|
||||||
ActivityPub::DeviceSerializer
|
ActivityPub::DeviceSerializer
|
||||||
|
when 'FeaturedTag'
|
||||||
|
ActivityPub::HashtagSerializer
|
||||||
when 'ActivityPub::CollectionPresenter'
|
when 'ActivityPub::CollectionPresenter'
|
||||||
ActivityPub::CollectionSerializer
|
ActivityPub::CollectionSerializer
|
||||||
when 'String'
|
when 'String'
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::HashtagSerializer < ActivityPub::Serializer
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
|
attributes :type, :href, :name
|
||||||
|
|
||||||
|
def type
|
||||||
|
'Hashtag'
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
"##{object.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def href
|
||||||
|
if object.class.name == 'FeaturedTag'
|
||||||
|
short_account_tag_url(object.account, object.tag)
|
||||||
|
else
|
||||||
|
tag_url(object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class REST::AccountFeaturedTagSerializer < ActiveModel::Serializer
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
|
attributes :id, :name, :url
|
||||||
|
|
||||||
|
def id
|
||||||
|
object.tag.id.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
"##{object.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def url
|
||||||
|
short_account_tag_url(object.account, object.tag)
|
||||||
|
end
|
||||||
|
end
|
|
@ -37,6 +37,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resource :instance_actor, path: 'actor', only: [:show] do
|
resource :instance_actor, path: 'actor', only: [:show] do
|
||||||
resource :inbox, only: [:create], module: :activitypub
|
resource :inbox, only: [:create], module: :activitypub
|
||||||
|
resource :outbox, only: [:show], module: :activitypub
|
||||||
end
|
end
|
||||||
|
|
||||||
devise_scope :user do
|
devise_scope :user do
|
||||||
|
@ -438,6 +439,7 @@ Rails.application.routes.draw do
|
||||||
resources :following, only: :index, controller: 'accounts/following_accounts'
|
resources :following, only: :index, controller: 'accounts/following_accounts'
|
||||||
resources :lists, only: :index, controller: 'accounts/lists'
|
resources :lists, only: :index, controller: 'accounts/lists'
|
||||||
resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'
|
resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'
|
||||||
|
resources :featured_tags, only: :index, controller: 'accounts/featured_tags'
|
||||||
|
|
||||||
member do
|
member do
|
||||||
post :follow
|
post :follow
|
||||||
|
|
|
@ -67,6 +67,7 @@ module Mastodon
|
||||||
when :s3
|
when :s3
|
||||||
paperclip_instance = MediaAttachment.new.file
|
paperclip_instance = MediaAttachment.new.file
|
||||||
s3_interface = paperclip_instance.s3_interface
|
s3_interface = paperclip_instance.s3_interface
|
||||||
|
s3_permissions = Paperclip::Attachment.default_options[:s3_permissions]
|
||||||
bucket = s3_interface.bucket(Paperclip::Attachment.default_options[:s3_credentials][:bucket])
|
bucket = s3_interface.bucket(Paperclip::Attachment.default_options[:s3_credentials][:bucket])
|
||||||
last_key = options[:start_after]
|
last_key = options[:start_after]
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ module Mastodon
|
||||||
record_map = preload_records_from_mixed_objects(objects)
|
record_map = preload_records_from_mixed_objects(objects)
|
||||||
|
|
||||||
objects.each do |object|
|
objects.each do |object|
|
||||||
object.acl.put(acl: 'public-read') if options[:fix_permissions] && !options[:dry_run]
|
object.acl.put(acl: s3_permissions) if options[:fix_permissions] && !options[:dry_run]
|
||||||
|
|
||||||
path_segments = object.key.split('/')
|
path_segments = object.key.split('/')
|
||||||
path_segments.delete('cache')
|
path_segments.delete('cache')
|
||||||
|
|
|
@ -448,7 +448,7 @@ RSpec.describe FeedManager do
|
||||||
FeedManager.instance.push_to_home(receiver, another_status)
|
FeedManager.instance.push_to_home(receiver, another_status)
|
||||||
|
|
||||||
# We should have a tracking set and an entry in reblogs.
|
# We should have a tracking set and an entry in reblogs.
|
||||||
expect(Redis.current.exists(reblog_set_key)).to be true
|
expect(Redis.current.exists?(reblog_set_key)).to be true
|
||||||
expect(Redis.current.zrange(reblogs_key, 0, -1)).to eq [reblogged.id.to_s]
|
expect(Redis.current.zrange(reblogs_key, 0, -1)).to eq [reblogged.id.to_s]
|
||||||
|
|
||||||
# Push everything off the end of the feed.
|
# Push everything off the end of the feed.
|
||||||
|
@ -461,7 +461,7 @@ RSpec.describe FeedManager do
|
||||||
FeedManager.instance.trim('home', receiver.id)
|
FeedManager.instance.trim('home', receiver.id)
|
||||||
|
|
||||||
# We should not have any reblog tracking data.
|
# We should not have any reblog tracking data.
|
||||||
expect(Redis.current.exists(reblog_set_key)).to be false
|
expect(Redis.current.exists?(reblog_set_key)).to be false
|
||||||
expect(Redis.current.zrange(reblogs_key, 0, -1)).to be_empty
|
expect(Redis.current.zrange(reblogs_key, 0, -1)).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -150,9 +150,9 @@ RSpec.describe SpamCheck do
|
||||||
let(:redis_key) { spam_check.send(:redis_key) }
|
let(:redis_key) { spam_check.send(:redis_key) }
|
||||||
|
|
||||||
it 'remembers' do
|
it 'remembers' do
|
||||||
expect(Redis.current.exists(redis_key)).to be true
|
expect(Redis.current.exists?(redis_key)).to be true
|
||||||
spam_check.remember!
|
spam_check.remember!
|
||||||
expect(Redis.current.exists(redis_key)).to be true
|
expect(Redis.current.exists?(redis_key)).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,9 +166,9 @@ RSpec.describe SpamCheck do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'resets' do
|
it 'resets' do
|
||||||
expect(Redis.current.exists(redis_key)).to be true
|
expect(Redis.current.exists?(redis_key)).to be true
|
||||||
spam_check.reset!
|
spam_check.reset!
|
||||||
expect(Redis.current.exists(redis_key)).to be false
|
expect(Redis.current.exists?(redis_key)).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ RSpec.describe UnallowDomainService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'removes the remote accounts\'s statuses and media attachments' do
|
it 'removes the remote accounts\'s statuses and media attachments' do
|
||||||
expect { bad_status1.reload }.to_not raise_exception ActiveRecord::RecordNotFound
|
expect { bad_status1.reload }.to_not raise_error
|
||||||
expect { bad_status2.reload }.to_not raise_exception ActiveRecord::RecordNotFound
|
expect { bad_status2.reload }.to_not raise_error
|
||||||
expect { bad_attachment.reload }.to_not raise_exception ActiveRecord::RecordNotFound
|
expect { bad_attachment.reload }.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,8 +16,8 @@ describe Scheduler::FeedCleanupScheduler do
|
||||||
|
|
||||||
expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0
|
expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0
|
||||||
expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1
|
expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1
|
||||||
expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs'))).to be false
|
expect(Redis.current.exists?(feed_key_for(inactive_user, 'reblogs'))).to be false
|
||||||
expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs:2'))).to be false
|
expect(Redis.current.exists?(feed_key_for(inactive_user, 'reblogs:2'))).to be false
|
||||||
end
|
end
|
||||||
|
|
||||||
def feed_key_for(user, subtype = nil)
|
def feed_key_for(user, subtype = nil)
|
||||||
|
|
Loading…
Reference in New Issue