mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-13 07:49:29 +00:00
Compare commits
26 Commits
list-filte
...
local-only
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
920d25f8c9 | ||
|
|
578438b360 | ||
|
|
358fd2121a | ||
|
|
cb11b0ee5a | ||
|
|
bdaaddeff9 | ||
|
|
e202efdf8a | ||
|
|
5325c2ab3e | ||
|
|
9e8fa3caee | ||
|
|
e677dda07c | ||
|
|
82b2e224a2 | ||
|
|
6abb0950c6 | ||
|
|
e35a350119 | ||
|
|
2efffe77dc | ||
|
|
c5a4eda694 | ||
|
|
3ec47e732b | ||
|
|
1138d0c321 | ||
|
|
288f1293ef | ||
|
|
0c46058a43 | ||
|
|
c1410af368 | ||
|
|
24f36ca912 | ||
|
|
f080a9fac7 | ||
|
|
6bd18e43ba | ||
|
|
5ef65aab8f | ||
|
|
cfbb95605b | ||
|
|
08519cd4f4 | ||
|
|
434c70fd98 |
@@ -49,7 +49,7 @@ class AccountsController < ApplicationController
|
||||
end
|
||||
|
||||
def default_statuses
|
||||
@account.statuses.where(visibility: [:public, :unlisted])
|
||||
@account.statuses.not_local_only.where(visibility: [:public, :unlisted])
|
||||
end
|
||||
|
||||
def only_media_scope
|
||||
|
||||
@@ -42,6 +42,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||
@status = PostStatusService.new.call(current_user.account,
|
||||
status_params[:status],
|
||||
status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
|
||||
local_only: status_params[:local_only],
|
||||
media_ids: status_params[:media_ids],
|
||||
sensitive: status_params[:sensitive],
|
||||
spoiler_text: status_params[:spoiler_text],
|
||||
@@ -72,7 +73,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||
end
|
||||
|
||||
def status_params
|
||||
params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, media_ids: [])
|
||||
params.permit(:status, :in_reply_to_id, :local_only, :sensitive, :spoiler_text, :visibility, media_ids: [])
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
|
||||
@@ -112,7 +112,7 @@ export default class Compose extends React.PureComponent {
|
||||
|
||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
{({ x }) =>
|
||||
<div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
<div className='drawer__inner darker scrollable optionally-scrollable' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
<SearchResultsContainer />
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import SettingToggle from 'flavours/glitch/features/notifications/components/setting_toggle';
|
||||
import SettingText from 'flavours/glitch/components/setting_text';
|
||||
|
||||
const messages = defineMessages({
|
||||
filter_regex: { id: 'list_timeline.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' },
|
||||
settings: { id: 'list_timeline.settings', defaultMessage: 'Column settings' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className='column-settings__section'><FormattedMessage id='list_timeline.column_settings.basic' defaultMessage='Basic' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='list_timeline' settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='list_timeline.column_settings.show_reblogs' defaultMessage='Show boosts' />} />
|
||||
</div>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='list_timeline' settings={settings} settingKey={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='list_timeline.column_settings.show_replies' defaultMessage='Show replies' />} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='list_timeline.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingText prefix='list_timeline' settings={settings} settingKey={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting, saveSettings } from 'flavours/glitch/actions/settings';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'list_timeline']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (key, checked) {
|
||||
dispatch(changeSetting(['list_timeline', ...key], checked));
|
||||
},
|
||||
|
||||
onSave () {
|
||||
dispatch(saveSettings());
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
||||
@@ -13,7 +13,6 @@ import { fetchList, deleteList } from 'flavours/glitch/actions/lists';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import MissingIndicator from 'flavours/glitch/components/missing_indicator';
|
||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },
|
||||
@@ -144,7 +143,6 @@ export default class ListTimeline extends React.PureComponent {
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
<div className='column-header__links'>
|
||||
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
|
||||
<i className='fa fa-pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
|
||||
|
||||
@@ -14,17 +14,6 @@ const initialState = ImmutableMap({
|
||||
|
||||
skinTone: 1,
|
||||
|
||||
list_timeline: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
reblog: true,
|
||||
reply: true,
|
||||
}),
|
||||
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
}),
|
||||
}),
|
||||
|
||||
home: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
reblog: true,
|
||||
|
||||
@@ -363,3 +363,120 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
margin-bottom: 8px;
|
||||
line-height: 20px;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: $ui-base-color;
|
||||
color: $ui-primary-color;
|
||||
border-radius: 4px 4px 0 0;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
margin-right: 10px;
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__timestamp {
|
||||
color: lighten($ui-base-color, 34%);
|
||||
}
|
||||
|
||||
&__extras {
|
||||
background: lighten($ui-base-color, 6%);
|
||||
border-radius: 0 0 4px 4px;
|
||||
padding: 10px;
|
||||
color: $ui-primary-color;
|
||||
font-family: 'mastodon-font-monospace', monospace;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 28px;
|
||||
margin-right: 10px;
|
||||
color: lighten($ui-base-color, 34%);
|
||||
}
|
||||
|
||||
&__icon__overlay {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
|
||||
&.positive {
|
||||
background: $success-green;
|
||||
}
|
||||
|
||||
&.negative {
|
||||
background: $error-red;
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
background: $ui-highlight-color;
|
||||
}
|
||||
}
|
||||
|
||||
a,
|
||||
.username,
|
||||
.target {
|
||||
color: $ui-secondary-color;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.diff-old {
|
||||
color: $error-red;
|
||||
}
|
||||
|
||||
.diff-neutral {
|
||||
color: $ui-secondary-color;
|
||||
}
|
||||
|
||||
.diff-new {
|
||||
color: $success-green;
|
||||
}
|
||||
}
|
||||
|
||||
.name-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-right: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# account_id :integer not null
|
||||
# application_id :integer
|
||||
# in_reply_to_account_id :integer
|
||||
# local_only :boolean
|
||||
#
|
||||
|
||||
class Status < ApplicationRecord
|
||||
@@ -74,6 +75,8 @@ class Status < ApplicationRecord
|
||||
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
||||
scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) }
|
||||
|
||||
scope :not_local_only, -> { where(local_only: [false, nil]) }
|
||||
|
||||
cache_associated :account, :application, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account
|
||||
|
||||
delegate :domain, to: :account, prefix: true
|
||||
@@ -138,6 +141,8 @@ class Status < ApplicationRecord
|
||||
|
||||
around_create Mastodon::Snowflake::Callbacks
|
||||
|
||||
before_create :set_locality
|
||||
|
||||
before_validation :prepare_contents, if: :local?
|
||||
before_validation :set_reblog
|
||||
before_validation :set_visibility
|
||||
@@ -218,7 +223,7 @@ class Status < ApplicationRecord
|
||||
visibility = [:public, :unlisted]
|
||||
|
||||
if account.nil?
|
||||
where(visibility: visibility)
|
||||
where(visibility: visibility).not_local_only
|
||||
elsif target_account.blocking?(account) # get rid of blocked peeps
|
||||
none
|
||||
elsif account.id == target_account.id # author can see own stuff
|
||||
@@ -257,7 +262,7 @@ class Status < ApplicationRecord
|
||||
end
|
||||
|
||||
def filter_timeline_default(query)
|
||||
query.excluding_silenced_accounts
|
||||
query.not_local_only.excluding_silenced_accounts
|
||||
end
|
||||
|
||||
def account_silencing_filter(account)
|
||||
@@ -269,9 +274,13 @@ class Status < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def local_only?
|
||||
def marked_local_only?
|
||||
# match both with and without U+FE0F (the emoji variation selector)
|
||||
/👁\ufe0f?\z/.match?(content)
|
||||
/#{local_only_emoji}\ufe0f?\z/.match?(content)
|
||||
end
|
||||
|
||||
def local_only_emoji
|
||||
'👁'
|
||||
end
|
||||
|
||||
private
|
||||
@@ -299,6 +308,12 @@ class Status < ApplicationRecord
|
||||
self.sensitive = sensitive || spoiler_text.present?
|
||||
end
|
||||
|
||||
def set_locality
|
||||
if account.domain.nil? && !attribute_changed?(:local_only)
|
||||
self.local_only = marked_local_only?
|
||||
end
|
||||
end
|
||||
|
||||
def set_conversation
|
||||
self.reply = !(in_reply_to_id.nil? && thread.nil?) unless reply
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
class REST::StatusSerializer < ActiveModel::Serializer
|
||||
attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
|
||||
:sensitive, :spoiler_text, :visibility, :language,
|
||||
:uri, :content, :url, :reblogs_count, :favourites_count
|
||||
:uri, :content, :url, :reblogs_count, :favourites_count,
|
||||
:local_only
|
||||
|
||||
attribute :favourited, if: :current_user?
|
||||
attribute :reblogged, if: :current_user?
|
||||
|
||||
@@ -6,6 +6,7 @@ class PostStatusService < BaseService
|
||||
# @param [String] text Message
|
||||
# @param [Status] in_reply_to Optional status to reply to
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :local_only
|
||||
# @option [Boolean] :sensitive
|
||||
# @option [String] :visibility
|
||||
# @option [String] :spoiler_text
|
||||
@@ -25,6 +26,7 @@ class PostStatusService < BaseService
|
||||
ApplicationRecord.transaction do
|
||||
status = account.statuses.create!(text: text,
|
||||
thread: in_reply_to,
|
||||
local_only: options[:local_only],
|
||||
sensitive: options[:sensitive],
|
||||
spoiler_text: options[:spoiler_text] || '',
|
||||
visibility: options[:visibility] || account.user&.setting_default_privacy,
|
||||
@@ -40,8 +42,7 @@ class PostStatusService < BaseService
|
||||
LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
|
||||
DistributionWorker.perform_async(status.id)
|
||||
|
||||
# match both with and without U+FE0F (the emoji variation selector)
|
||||
unless /👁\ufe0f?\z/.match?(status.content)
|
||||
unless status.local_only?
|
||||
Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id)
|
||||
ActivityPub::DistributionWorker.perform_async(status.id)
|
||||
ActivityPub::ReplyDistributionWorker.perform_async(status.id) if status.reply? && status.thread.account.local?
|
||||
|
||||
@@ -21,7 +21,7 @@ class ReblogService < BaseService
|
||||
|
||||
DistributionWorker.perform_async(reblog.id)
|
||||
|
||||
unless /👁$/.match?(reblogged_status.content)
|
||||
unless reblogged_status.local_only?
|
||||
Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
|
||||
ActivityPub::DistributionWorker.perform_async(reblog.id)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :statuses, :local_only, :boolean
|
||||
end
|
||||
end
|
||||
@@ -418,6 +418,7 @@ ActiveRecord::Schema.define(version: 20171212195226) do
|
||||
t.bigint "account_id", null: false
|
||||
t.bigint "application_id"
|
||||
t.bigint "in_reply_to_account_id"
|
||||
t.boolean "local_only"
|
||||
t.index ["account_id", "id"], name: "index_statuses_on_account_id_id"
|
||||
t.index ["conversation_id"], name: "index_statuses_on_conversation_id"
|
||||
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id"
|
||||
|
||||
8
lib/tasks/glitchsoc.rake
Normal file
8
lib/tasks/glitchsoc.rake
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace :glitchsoc do
|
||||
desc 'Backfill local-only flag on statuses table'
|
||||
task backfill_local_only: :environment do
|
||||
Status.local.where(local_only: nil).find_each do |st|
|
||||
ActiveRecord::Base.logger.silence { st.update_attribute(:local_only, st.marked_local_only?) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -35,13 +35,71 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world' }
|
||||
context 'with local_only unspecified and no eyeball' do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'creates a non-local-only status' do
|
||||
expect(status_response["local_only"]).to be false
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
context 'with local_only unspecified and an eyeball' do
|
||||
before do
|
||||
post :create, params: { status: "Hello world #{Status.new.local_only_emoji}" }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'creates a local-only status' do
|
||||
expect(status_response["local_only"]).to be true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'with local_only set to true' do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world', local_only: true }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'creates a local-only status' do
|
||||
expect(status_response["local_only"]).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'with local_only set to false' do
|
||||
before do
|
||||
post :create, params: { status: 'Hello world', local_only: false }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'creates a non-local-only status' do
|
||||
expect(status_response["local_only"]).to be false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
@@ -59,6 +117,36 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
|
||||
expect(Status.find_by(id: status.id)).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'the "local_only" property' do
|
||||
context 'for a local-only status' do
|
||||
let(:status) { Fabricate(:status, account: user.account, local_only: true) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: status.id }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'is true' do
|
||||
expect(status_response["local_only"]).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a non-local-only status' do
|
||||
let(:status) { Fabricate(:status, account: user.account, local_only: false) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: status.id }
|
||||
end
|
||||
|
||||
let(:status_response) { JSON.parse(response.body) }
|
||||
|
||||
it 'is false' do
|
||||
expect(status_response["local_only"]).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an oauth token' do
|
||||
@@ -123,5 +211,34 @@ RSpec.describe Api::V1::StatusesController, type: :controller do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a local-only status' do
|
||||
let(:status) { Fabricate(:status, account: user.account, visibility: :public, local_only: true) }
|
||||
|
||||
describe 'GET #show' do
|
||||
it 'returns http unautharized' do
|
||||
get :show, params: { id: status.id }
|
||||
expect(response).to have_http_status(:missing)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #context' do
|
||||
before do
|
||||
Fabricate(:status, account: user.account, thread: status)
|
||||
end
|
||||
|
||||
it 'returns http unautharized' do
|
||||
get :context, params: { id: status.id }
|
||||
expect(response).to have_http_status(:missing)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #card' do
|
||||
it 'returns http unautharized' do
|
||||
get :card, params: { id: status.id }
|
||||
expect(response).to have_http_status(:missing)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -197,6 +197,43 @@ RSpec.describe Status, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'on create' do
|
||||
let(:local_account) { Fabricate(:account, username: 'local', domain: nil) }
|
||||
let(:remote_account) { Fabricate(:account, username: 'remote', domain: 'example.com') }
|
||||
|
||||
subject { Status.new }
|
||||
|
||||
describe 'on a status that ends with the local-only emoji' do
|
||||
before do
|
||||
subject.text = 'A toot ' + subject.local_only_emoji
|
||||
end
|
||||
|
||||
context 'if the status originates from this instance' do
|
||||
before do
|
||||
subject.account = local_account
|
||||
end
|
||||
|
||||
it 'is marked local-only' do
|
||||
subject.save!
|
||||
|
||||
expect(subject).to be_local_only
|
||||
end
|
||||
end
|
||||
|
||||
context 'if the status is remote' do
|
||||
before do
|
||||
subject.account = remote_account
|
||||
end
|
||||
|
||||
it 'is not marked local-only' do
|
||||
subject.save!
|
||||
|
||||
expect(subject).to_not be_local_only
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.mutes_map' do
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
@@ -549,6 +586,32 @@ RSpec.describe Status, type: :model do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with local-only statuses' do
|
||||
let(:status) { Fabricate(:status, local_only: true) }
|
||||
|
||||
subject { Status.as_public_timeline(viewer) }
|
||||
|
||||
context 'without a viewer' do
|
||||
let(:viewer) { nil }
|
||||
|
||||
it 'excludes local-only statuses' do
|
||||
expect(subject).to_not include(status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a viewer' do
|
||||
let(:viewer) { Fabricate(:account, username: 'viewer') }
|
||||
|
||||
it 'includes local-only statuses' do
|
||||
expect(subject).to include(status)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: What happens if the viewer is remote?
|
||||
# Can the viewer be remote?
|
||||
# What prevents the viewer from being remote?
|
||||
end
|
||||
end
|
||||
|
||||
describe '.as_tag_timeline' do
|
||||
@@ -570,6 +633,27 @@ RSpec.describe Status, type: :model do
|
||||
results = Status.as_tag_timeline(tag)
|
||||
expect(results).to include(status)
|
||||
end
|
||||
|
||||
context 'on a local-only status' do
|
||||
let(:tag) { Fabricate(:tag) }
|
||||
let(:status) { Fabricate(:status, local_only: true, tags: [tag]) }
|
||||
|
||||
context 'without a viewer' do
|
||||
let(:viewer) { nil }
|
||||
|
||||
it 'filters the local-only status out of the result set' do
|
||||
expect(Status.as_tag_timeline(tag, viewer)).not_to include(status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a viewer' do
|
||||
let(:viewer) { Fabricate(:account, username: 'viewer', domain: nil) }
|
||||
|
||||
it 'keeps the local-only status in the result set' do
|
||||
expect(Status.as_tag_timeline(tag, viewer)).to include(status)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.permitted_for' do
|
||||
|
||||
Reference in New Issue
Block a user