Skip to content

Commit

Permalink
Merge commit 'df6086d4027910fb160d531b4fe7ffdec26b0cd7' into glitch-s…
Browse files Browse the repository at this point in the history
…oc/merge-upstream
  • Loading branch information
ClearlyClaire committed Mar 14, 2024
2 parents 31b93a5 + df6086d commit e91ede5
Show file tree
Hide file tree
Showing 40 changed files with 351 additions and 244 deletions.
46 changes: 1 addition & 45 deletions app/controllers/api/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Api::BaseController < ApplicationController
include Api::AccessTokenTrackingConcern
include Api::CachingConcern
include Api::ContentSecurityPolicy
include Api::ErrorHandling

skip_before_action :require_functional!, unless: :limited_federation_mode?

Expand All @@ -18,51 +19,6 @@ class Api::BaseController < ApplicationController

protect_from_forgery with: :null_session

rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422
end

rescue_from ActiveRecord::RecordNotUnique do
render json: { error: 'Duplicate record' }, status: 422
end

rescue_from Date::Error do
render json: { error: 'Invalid date supplied' }, status: 422
end

rescue_from ActiveRecord::RecordNotFound do
render json: { error: 'Record not found' }, status: 404
end

rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
render json: { error: 'Remote data could not be fetched' }, status: 503
end

rescue_from OpenSSL::SSL::SSLError do
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
end

rescue_from Mastodon::NotPermittedError do
render json: { error: 'This action is not allowed' }, status: 403
end

rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end

rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end

rescue_from Mastodon::RateLimitExceededError do
render json: { error: I18n.t('errors.429') }, status: 429
end

rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
render json: { error: e.to_s }, status: 400
end

def doorkeeper_unauthorized_render_options(error: nil)
{ json: { error: error.try(:description) || 'Not authorized' } }
end
Expand Down
52 changes: 52 additions & 0 deletions app/controllers/concerns/api/error_handling.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

module Api::ErrorHandling
extend ActiveSupport::Concern

included do
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422
end

rescue_from ActiveRecord::RecordNotUnique do
render json: { error: 'Duplicate record' }, status: 422
end

rescue_from Date::Error do
render json: { error: 'Invalid date supplied' }, status: 422
end

rescue_from ActiveRecord::RecordNotFound do
render json: { error: 'Record not found' }, status: 404
end

rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
render json: { error: 'Remote data could not be fetched' }, status: 503
end

rescue_from OpenSSL::SSL::SSLError do
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
end

rescue_from Mastodon::NotPermittedError do
render json: { error: 'This action is not allowed' }, status: 403
end

rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end

rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end

rescue_from Mastodon::RateLimitExceededError do
render json: { error: I18n.t('errors.429') }, status: 429
end

rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
render json: { error: e.to_s }, status: 400
end
end
end
6 changes: 6 additions & 0 deletions app/javascript/mastodon/actions/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,10 @@ export const fetchNotificationsForRequest = accountId => (dispatch, getState) =>

api(getState).get('/api/v1/notifications', { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));

dispatch(fetchNotificationsForRequestSuccess(response.data, next?.uri));
}).catch(err => {
dispatch(fetchNotificationsForRequestFail(err));
Expand Down Expand Up @@ -585,7 +588,10 @@ export const expandNotificationsForRequest = () => (dispatch, getState) => {

api(getState).get(url).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account)));

dispatch(expandNotificationsForRequestSuccess(response.data, next?.uri));
}).catch(err => {
dispatch(expandNotificationsForRequestFail(err));
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/mastodon/components/column_header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class ColumnHeader extends PureComponent {
<h1 className={buttonClassName}>
{hasTitle && (
<>
{backButton}
{showBackButton && backButton}

<button onClick={this.handleTitleClick} className='column-header__title'>
{!showBackButton && <Icon id={icon} icon={iconComponent} className='column-header__icon' />}
Expand All @@ -208,7 +208,7 @@ class ColumnHeader extends PureComponent {
</>
)}

{!hasTitle && backButton}
{!hasTitle && showBackButton && backButton}

<div className='column-header__buttons'>
{extraButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { FormattedMessage, injectIntl } from 'react-intl';

import { connect } from 'react-redux';

import ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react';
import { openModal } from 'mastodon/actions/modal';
import { Icon } from 'mastodon/components/icon';
import InlineAccount from 'mastodon/components/inline_account';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';

Expand Down Expand Up @@ -67,7 +65,7 @@ class EditedTimestamp extends PureComponent {
return (
<DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
<button className='dropdown-menu__text-button'>
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' icon={ArrowDropDownIcon} />
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: <span className='animated-number'>{intl.formatDate(timestamp, { month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' })}</span> }} />
</button>
</DropdownMenu>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';

import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react';
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import TagIcon from '@/material-icons/400-24px/tag.svg?react';
import { Icon } from 'mastodon/components/icon';
import { LoadMore } from 'mastodon/components/load_more';
Expand Down Expand Up @@ -76,11 +75,6 @@ class SearchResults extends ImmutablePureComponent {

return (
<div className='search-results'>
<div className='search-results__header'>
<Icon id='search' icon={SearchIcon} />
<FormattedMessage id='explore.search_results' defaultMessage='Search results' />
</div>

{accounts}
{hashtags}
{statuses}
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/mastodon/features/notifications/request.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
}
}, [dispatch, accountId]);

const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') });
const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') || account?.get('username') });

return (
<Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';

import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import EditedTimestamp from 'mastodon/components/edited_timestamp';
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
Expand Down Expand Up @@ -143,10 +141,7 @@ class DetailedStatus extends ImmutablePureComponent {
let media = '';
let applicationLink = '';
let reblogLink = '';
const reblogIcon = 'retweet';
const reblogIconComponent = RepeatIcon;
let favouriteLink = '';
let edited = '';

if (this.props.measureHeight) {
outerStyle.height = `${this.state.height}px`;
Expand Down Expand Up @@ -218,68 +213,53 @@ class DetailedStatus extends ImmutablePureComponent {
}

if (status.get('application')) {
applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
applicationLink = <>·<a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
}

const visibilityLink = <> · <VisibilityIcon visibility={status.get('visibility')} /></>;
const visibilityLink = <>·<VisibilityIcon visibility={status.get('visibility')} /></>;

if (['private', 'direct'].includes(status.get('visibility'))) {
reblogLink = '';
} else if (this.props.history) {
reblogLink = (
<>
{' · '}
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
<Icon id={reblogIcon} icon={reblogIconComponent} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
</Link>
</>
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
<FormattedMessage id='status.reblogs' defaultMessage='{count, plural, one {boost} other {boosts}}' values={{ count: status.get('reblogs_count') }} />
</Link>
);
} else {
reblogLink = (
<>
{' · '}
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id={reblogIcon} icon={reblogIconComponent} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
</a>
</>
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
<FormattedMessage id='status.reblogs' defaultMessage='{count, plural, one {boost} other {boosts}}' values={{ count: status.get('reblogs_count') }} />
</a>
);
}

if (this.props.history) {
favouriteLink = (
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
<Icon id='star' icon={StarIcon} />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
</span>
<FormattedMessage id='status.favourites' defaultMessage='{count, plural, one {favorite} other {favorites}}' values={{ count: status.get('favourites_count') }} />
</Link>
);
} else {
favouriteLink = (
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id='star' icon={StarIcon} />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
</span>
<FormattedMessage id='status.favourites' defaultMessage='{count, plural, one {favorite} other {favorites}}' values={{ count: status.get('favourites_count') }} />
</a>
);
}

if (status.get('edited_at')) {
edited = (
<>
{' · '}
<EditedTimestamp statusId={status.get('id')} timestamp={status.get('edited_at')} />
</>
);
}

const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;

Expand Down Expand Up @@ -310,9 +290,23 @@ class DetailedStatus extends ImmutablePureComponent {
{expanded && hashtagBar}

<div className='detailed-status__meta'>
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
<FormattedDate value={new Date(status.get('created_at'))} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
</a>{edited}{visibilityLink}{applicationLink}{reblogLink} · {favouriteLink}
<div className='detailed-status__meta__line'>
<a className='detailed-status__datetime' href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} target='_blank' rel='noopener noreferrer'>
<FormattedDate value={new Date(status.get('created_at'))} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
</a>

{visibilityLink}

{applicationLink}
</div>

{status.get('edited_at') && <div className='detailed-status__meta__line'><EditedTimestamp statusId={status.get('id')} timestamp={status.get('edited_at')} /></div>}

<div className='detailed-status__meta__line'>
{reblogLink}
·
{favouriteLink}
</div>
</div>
</div>
</div>
Expand Down
7 changes: 4 additions & 3 deletions app/javascript/mastodon/locales/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@
"filter_modal.select_filter.subtitle": "Usa una categoria existent o crea'n una de nova",
"filter_modal.select_filter.title": "Filtra aquest tut",
"filter_modal.title.status": "Filtra un tut",
"filtered_notifications_banner.pending_requests": "Notificacions {count, plural, =0 {de ningú} one {d'una persona} other {de # persones}} que potser coneixes",
"filtered_notifications_banner.title": "Notificacions filtrades",
"firehose.all": "Tots",
"firehose.local": "Aquest servidor",
Expand Down Expand Up @@ -476,13 +477,13 @@
"notifications.permission_denied": "Les notificacions d’escriptori no estan disponibles perquè prèviament s’ha denegat el permís al navegador",
"notifications.permission_denied_alert": "No es poden activar les notificacions de l'escriptori perquè abans s'ha denegat el permís del navegador",
"notifications.permission_required": "Les notificacions d'escriptori no estan disponibles perquè el permís requerit no ha estat concedit.",
"notifications.policy.filter_new_accounts.hint": "Creat durant els passats {days, plural, one {un dia} other {# dies}}",
"notifications.policy.filter_new_accounts.hint": "Creat {days, plural, one {ahir} other {durant els # dies passats}}",
"notifications.policy.filter_new_accounts_title": "Comptes nous",
"notifications.policy.filter_not_followers_hint": "Incloent les persones que us segueixen fa menys de {days, plural, one {un dia} other {# dies}}",
"notifications.policy.filter_not_followers_hint": "Incloent les persones que us segueixen fa menys {days, plural, one {d'un dia} other {de # dies}}",
"notifications.policy.filter_not_followers_title": "Persones que no us segueixen",
"notifications.policy.filter_not_following_hint": "Fins que no ho aproveu de forma manual",
"notifications.policy.filter_not_following_title": "Persones que no seguiu",
"notifications.policy.filter_private_mentions_hint": "Filtra-ho excepte si és en resposta a una menció vostra o si seguiu el remitent",
"notifications.policy.filter_private_mentions_hint": "Filtrat si no és que és en resposta a una menció vostra o si seguiu el remitent",
"notifications.policy.filter_private_mentions_title": "Mencions privades no sol·licitades",
"notifications.policy.title": "Filtra les notificacions de…",
"notifications_permission_banner.enable": "Activa les notificacions d’escriptori",
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/mastodon/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -662,10 +662,11 @@
"status.direct": "Privately mention @{name}",
"status.direct_indicator": "Private mention",
"status.edit": "Edit",
"status.edited": "Edited {date}",
"status.edited": "Last edited {date}",
"status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
"status.embed": "Embed",
"status.favourite": "Favorite",
"status.favourites": "{count, plural, one {favorite} other {favorites}}",
"status.filter": "Filter this post",
"status.filtered": "Filtered",
"status.hide": "Hide post",
Expand All @@ -686,6 +687,7 @@
"status.reblog": "Boost",
"status.reblog_private": "Boost with original visibility",
"status.reblogged_by": "{name} boosted",
"status.reblogs": "{count, plural, one {boost} other {boosts}}",
"status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.",
"status.redraft": "Delete & re-draft",
"status.remove_bookmark": "Remove bookmark",
Expand Down
Loading

0 comments on commit e91ede5

Please sign in to comment.