Commit 5c027965 authored by Eugen Rochko's avatar Eugen Rochko

Remove public timelines and private and direct posts

- Remove public timelines from streaming API
- Remove direct timeline from streaming API
- Return nothing from public timelines in REST API
- Return nothing from direct timeline in REST API
- Return nothing from conversations REST API
- Remove non-public visibilities from preferences
- Remove non-public visibilities from compose dropdown
- Discard non-public messages from ActivityPub
- Reject non-public messages in the REST API
- Remove "Direct message @___" action from web UI
- Remove links to local, federated, direct timelines in web UI
- Remove keyboard shortcuts for opening local, federated, direct timelines in web UI
parent 6afab258
......@@ -29,12 +29,11 @@ class Api::V1::ConversationsController < Api::BaseController
private
def set_conversation
@conversation = AccountConversation.where(account: current_account).find(params[:id])
raise ActiveRecord::RecordNotFound
end
def paginated_conversations
AccountConversation.where(account: current_account)
.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
[]
end
def insert_pagination_headers
......
......@@ -15,7 +15,7 @@ class Api::V1::Timelines::DirectController < Api::BaseController
private
def load_statuses
cached_direct_statuses
[]
end
def cached_direct_statuses
......
......@@ -13,7 +13,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
private
def load_statuses
cached_public_statuses
[]
end
def cached_public_statuses
......
......@@ -127,7 +127,6 @@ class Header extends ImmutablePureComponent {
if (account.get('id') !== me) {
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
menu.push(null);
}
......
......@@ -216,8 +216,6 @@ class PrivacyDropdown extends React.PureComponent {
this.options = [
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
{ icon: 'envelope', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
];
}
......
......@@ -85,12 +85,6 @@ class Compose extends React.PureComponent {
{!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
<Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'COMMUNITY') && (
<Link to='/timelines/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'PUBLIC') && (
<Link to='/timelines/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>
)}
<a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a>
<a href='/auth/sign_out' className='drawer__tab' data-method='delete' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)}><Icon id='sign-out' fixedWidth /></a>
</nav>
......
......@@ -85,42 +85,19 @@ class GettingStarted extends ImmutablePureComponent {
let height = (multiColumn) ? 0 : 60;
if (multiColumn) {
navItems.push(
<ColumnSubheading key={i++} text={intl.formatMessage(messages.discover)} />,
<ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/public/local' />,
<ColumnLink key={i++} icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />,
);
height += 34 + 48*2;
if (profile_directory) {
navItems.push(
<ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} href='/explore' />
);
height += 48;
}
navItems.push(
<ColumnSubheading key={i++} text={intl.formatMessage(messages.personal)} />
);
height += 34;
} else if (profile_directory) {
navItems.push(
<ColumnLink key={i++} icon='address-book' text={intl.formatMessage(messages.profile_directory)} href='/explore' />
);
height += 48;
}
navItems.push(
<ColumnLink key={i++} icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />,
<ColumnLink key={i++} icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
<ColumnLink key={i++} icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />
);
height += 48*3;
height += 48*2;
if (myAccount.get('locked')) {
navItems.push(<ColumnLink key={i++} icon='users' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
......
......@@ -100,18 +100,6 @@ class KeyboardShortcuts extends ImmutablePureComponent {
<td><kbd>g</kbd>+<kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.notifications' defaultMessage='to open notifications column' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>l</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.local' defaultMessage='to open local timeline' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>t</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.federated' defaultMessage='to open federated timeline' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>d</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.direct' defaultMessage='to open direct messages column' /></td>
</tr>
<tr>
<td><kbd>g</kbd>+<kbd>s</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.start' defaultMessage='to open "get started" column' /></td>
......
......@@ -31,7 +31,7 @@ const componentMap = {
};
const messages = defineMessages({
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
publish: { id: 'librem.compose_form.publish', defaultMessage: 'Publish' },
});
const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/);
......
......@@ -10,8 +10,6 @@ export const links = [
<NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><Icon id='bell' fixedWidth /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
<NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><Icon id='search' fixedWidth /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>,
<NavLink className='tabs-bar__link primary' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><Icon id='bars' fixedWidth /></NavLink>,
......
......@@ -81,9 +81,6 @@ const keyMap = {
back: 'backspace',
goToHome: 'g h',
goToNotifications: 'g n',
goToLocal: 'g l',
goToFederated: 'g t',
goToDirect: 'g d',
goToStart: 'g s',
goToFavourites: 'g f',
goToPinned: 'g p',
......@@ -149,9 +146,6 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
......@@ -458,9 +452,6 @@ class UI extends React.PureComponent {
back: this.handleHotkeyBack,
goToHome: this.handleHotkeyGoToHome,
goToNotifications: this.handleHotkeyGoToNotifications,
goToLocal: this.handleHotkeyGoToLocal,
goToFederated: this.handleHotkeyGoToFederated,
goToDirect: this.handleHotkeyGoToDirect,
goToStart: this.handleHotkeyGoToStart,
goToFavourites: this.handleHotkeyGoToFavourites,
goToPinned: this.handleHotkeyGoToPinned,
......
......@@ -40,7 +40,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
end
def announceable?(status)
status.account_id == @account.id || status.public_visibility? || status.unlisted_visibility?
status.public_visibility? || status.unlisted_visibility?
end
def related_to_local_activity?
......
......@@ -34,6 +34,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
process_tags
process_audience
return if %i(private direct limited).include?(@params[:visibility])
ApplicationRecord.transaction do
@status = Status.create!(@params)
attach_tags(@status)
......
......@@ -70,7 +70,7 @@ class Status < ApplicationRecord
validates_with StatusLengthValidator
validates_with DisallowedHashtagsValidator
validates :reblog, uniqueness: { scope: :account }, if: :reblog?
validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?
validates :visibility, exclusion: { in: %w(private direct limited), message: I18n.t('librem.only_public_messages_allowed') }
accepts_nested_attributes_for :poll
......@@ -267,7 +267,7 @@ class Status < ApplicationRecord
class << self
def selectable_visibilities
visibilities.keys - %w(direct limited)
%w(public unlisted)
end
def in_chosen_languages(account)
......
......@@ -180,7 +180,7 @@ class User < ApplicationRecord
end
def setting_default_privacy
settings.default_privacy || (account.locked? ? 'private' : 'public')
settings.default_privacy || 'public'
end
def allows_digest_emails?
......
---
en:
librem:
librem_one_address: Librem One address
only_public_messages_allowed: Librem One supports only public posts
passphrase: Passphrase
......@@ -482,22 +482,18 @@ const startWorker = (workerId) => {
});
app.get('/api/v1/streaming/public', (req, res) => {
const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';
const channel = onlyMedia ? 'timeline:public:media' : 'timeline:public';
streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);
httpNotFound(res);
return;
});
app.get('/api/v1/streaming/public/local', (req, res) => {
const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';
const channel = onlyMedia ? 'timeline:public:local:media' : 'timeline:public:local';
streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);
httpNotFound(res);
return;
});
app.get('/api/v1/streaming/direct', (req, res) => {
const channel = `timeline:direct:${req.accountId}`;
streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req, subscriptionHeartbeat(channel)), true);
httpNotFound(res);
return;
});
app.get('/api/v1/streaming/hashtag', (req, res) => {
......@@ -561,21 +557,20 @@ const startWorker = (workerId) => {
streamFrom(`timeline:${req.accountId}`, req, streamToWs(req, ws), streamWsEnd(req, ws), false, true);
break;
case 'public':
streamFrom('timeline:public', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
ws.close();
return;
case 'public:local':
streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
ws.close();
return;
case 'public:media':
streamFrom('timeline:public:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
ws.close();
return;
case 'public:local:media':
streamFrom('timeline:public:local:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
break;
ws.close();
return;
case 'direct':
channel = `timeline:direct:${req.accountId}`;
streamFrom(channel, req, streamToWs(req, ws), streamWsEnd(req, ws, subscriptionHeartbeat(channel)), true);
break;
ws.close();
return;
case 'hashtag':
if (!location.query.tag || location.query.tag.length === 0) {
ws.close();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment