diff --git a/.rubocop.yml b/.rubocop.yml index cf4ee565e0..6da1dc8cbc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,14 +4,9 @@ AllCops: DisplayCopNames: true DisplayStyleGuide: true Exclude: - - db/schema.rb - - bin/* - - node_modules/**/* - Vagrantfile - - vendor/**/* - config/initializers/json_ld* - lib/mastodon/migration_helpers.rb - - lib/templates/**/* ExtraDetails: true NewCops: enable TargetRubyVersion: 3.1 # Oldest supported ruby version diff --git a/Dockerfile b/Dockerfile index 0d7516b108..c3e43dac8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.7 +# syntax=docker/dockerfile:1.8 # This file is designed for production server deployment, not local development work # For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker @@ -24,10 +24,10 @@ FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA -# Example: v4.2.0-nightly.2023.11.09+something -# Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] +# Example: v4.3.0-nightly.2023.11.09+pr-123456 +# Overwrite existence of 'alpha.X' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] ARG MASTODON_VERSION_PRERELEASE="" -# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-12345"] +# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-123456"] ARG MASTODON_VERSION_METADATA="" # Allow Ruby on Rails to serve static files @@ -100,9 +100,7 @@ RUN \ apt-get dist-upgrade -yq; \ # Install jemalloc, curl and other necessary components apt-get install -y --no-install-recommends \ - ca-certificates \ curl \ - ffmpeg \ file \ libjemalloc2 \ patchelf \ @@ -137,7 +135,10 @@ RUN \ --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ # Install build tools and bundler dependencies from APT apt-get install -y --no-install-recommends \ + autoconf \ + automake \ build-essential \ + cmake \ git \ libgdbm-dev \ libglib2.0-dev \ @@ -146,9 +147,12 @@ RUN \ libidn-dev \ libpq-dev \ libssl-dev \ + libtool \ meson \ + nasm \ pkg-config \ shared-mime-info \ + xz-utils \ # libvips components libcgif-dev \ libexif-dev \ @@ -162,6 +166,16 @@ RUN \ libspng-dev \ libtiff-dev \ libwebp-dev \ + # ffmpeg components + libdav1d-dev \ + liblzma-dev \ + libmp3lame-dev \ + libopus-dev \ + libsnappy-dev \ + libvorbis-dev \ + libvpx-dev \ + libx264-dev \ + libx265-dev \ ; RUN \ @@ -190,6 +204,48 @@ RUN \ ninja; \ ninja install; +# Create temporary ffmpeg specific build layer from build layer +FROM build as ffmpeg + +# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"] +# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg +ARG FFMPEG_VERSION=7.0.1 +# ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"] +ARG FFMPEG_URL=https://ffmpeg.org/releases + +WORKDIR /usr/local/ffmpeg/src + +RUN \ + curl -sSL -o ffmpeg-${FFMPEG_VERSION}.tar.xz ${FFMPEG_URL}/ffmpeg-${FFMPEG_VERSION}.tar.xz; \ + tar xf ffmpeg-${FFMPEG_VERSION}.tar.xz; \ + cd ffmpeg-${FFMPEG_VERSION}; \ + ./configure \ + --prefix=/usr/local/ffmpeg \ + --toolchain=hardened \ + --disable-debug \ + --disable-devices \ + --disable-doc \ + --disable-ffplay \ + --disable-network \ + --disable-static \ + --enable-ffmpeg \ + --enable-ffprobe \ + --enable-gpl \ + --enable-libdav1d \ + --enable-libmp3lame \ + --enable-libopus \ + --enable-libsnappy \ + --enable-libvorbis \ + --enable-libvpx \ + --enable-libwebp \ + --enable-libx264 \ + --enable-libx265 \ + --enable-shared \ + --enable-version3 \ + ; \ + make -j$(nproc); \ + make install; + # Create temporary bundler specific build layer from build layer FROM build as bundler @@ -289,6 +345,20 @@ RUN \ libwebp7 \ libwebpdemux2 \ libwebpmux3 \ + # ffmpeg components + libdav1d6 \ + libmp3lame0 \ + libopencore-amrnb0 \ + libopencore-amrwb0 \ + libopus0 \ + libsnappy1v5 \ + libtheora0 \ + libvorbis0a \ + libvorbisenc2 \ + libvorbisfile3 \ + libvpx7 \ + libx264-164 \ + libx265-199 \ ; # Copy Mastodon sources into final layer @@ -302,11 +372,16 @@ COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/ # Copy libvips components to layer COPY --from=libvips /usr/local/libvips/bin /usr/local/bin COPY --from=libvips /usr/local/libvips/lib /usr/local/lib +# Copy ffpmeg components to layer +COPY --from=ffmpeg /usr/local/ffmpeg/bin /usr/local/bin +COPY --from=ffmpeg /usr/local/ffmpeg/lib /usr/local/lib RUN \ ldconfig; \ # Smoketest media processors - vips -v; + vips -v; \ + ffmpeg -version; \ + ffprobe -version; RUN \ # Precompile bootsnap code for faster Rails startup diff --git a/Gemfile b/Gemfile index b00eaecbcf..ecd9088d39 100644 --- a/Gemfile +++ b/Gemfile @@ -9,9 +9,6 @@ gem 'rack', '~> 2.2.7' gem 'rails', '~> 7.1.1' gem 'thor', '~> 1.2' -# For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182 -gem 'irb', '~> 1.8' - gem 'dotenv' gem 'haml-rails', '~>2.0' gem 'pg', '~> 1.5' @@ -61,6 +58,7 @@ gem 'httplog', '~> 1.7.0' gem 'i18n' gem 'idn-ruby', require: 'idn' gem 'inline_svg' +gem 'irb', '~> 1.8' gem 'kaminari', '~> 1.2' gem 'link_header', '~> 0.0' gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' diff --git a/app/javascript/flavours/glitch/actions/notification_policies.ts b/app/javascript/flavours/glitch/actions/notification_policies.ts new file mode 100644 index 0000000000..76452de324 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/notification_policies.ts @@ -0,0 +1,16 @@ +import { + apiGetNotificationPolicy, + apiUpdateNotificationsPolicy, +} from 'flavours/glitch/api/notification_policies'; +import type { NotificationPolicy } from 'flavours/glitch/models/notification_policy'; +import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; + +export const fetchNotificationPolicy = createDataLoadingThunk( + 'notificationPolicy/fetch', + () => apiGetNotificationPolicy(), +); + +export const updateNotificationsPolicy = createDataLoadingThunk( + 'notificationPolicy/update', + (policy: Partial) => apiUpdateNotificationsPolicy(policy), +); diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index a2be31ffeb..3a1af501c8 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -57,10 +57,6 @@ export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ'; export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT'; export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION'; -export const NOTIFICATION_POLICY_FETCH_REQUEST = 'NOTIFICATION_POLICY_FETCH_REQUEST'; -export const NOTIFICATION_POLICY_FETCH_SUCCESS = 'NOTIFICATION_POLICY_FETCH_SUCCESS'; -export const NOTIFICATION_POLICY_FETCH_FAIL = 'NOTIFICATION_POLICY_FETCH_FAIL'; - export const NOTIFICATION_REQUESTS_FETCH_REQUEST = 'NOTIFICATION_REQUESTS_FETCH_REQUEST'; export const NOTIFICATION_REQUESTS_FETCH_SUCCESS = 'NOTIFICATION_REQUESTS_FETCH_SUCCESS'; export const NOTIFICATION_REQUESTS_FETCH_FAIL = 'NOTIFICATION_REQUESTS_FETCH_FAIL'; @@ -434,40 +430,6 @@ export function setBrowserPermission (value) { }; } -export const fetchNotificationPolicy = () => (dispatch) => { - dispatch(fetchNotificationPolicyRequest()); - - api().get('/api/v1/notifications/policy').then(({ data }) => { - dispatch(fetchNotificationPolicySuccess(data)); - }).catch(err => { - dispatch(fetchNotificationPolicyFail(err)); - }); -}; - -export const fetchNotificationPolicyRequest = () => ({ - type: NOTIFICATION_POLICY_FETCH_REQUEST, -}); - -export const fetchNotificationPolicySuccess = policy => ({ - type: NOTIFICATION_POLICY_FETCH_SUCCESS, - policy, -}); - -export const fetchNotificationPolicyFail = error => ({ - type: NOTIFICATION_POLICY_FETCH_FAIL, - error, -}); - -export const updateNotificationsPolicy = params => (dispatch) => { - dispatch(fetchNotificationPolicyRequest()); - - api().put('/api/v1/notifications/policy', params).then(({ data }) => { - dispatch(fetchNotificationPolicySuccess(data)); - }).catch(err => { - dispatch(fetchNotificationPolicyFail(err)); - }); -}; - export const fetchNotificationRequests = () => (dispatch, getState) => { const params = {}; diff --git a/app/javascript/flavours/glitch/api/notification_policies.ts b/app/javascript/flavours/glitch/api/notification_policies.ts new file mode 100644 index 0000000000..2bb5dc37ca --- /dev/null +++ b/app/javascript/flavours/glitch/api/notification_policies.ts @@ -0,0 +1,10 @@ +import { apiRequest } from 'flavours/glitch/api'; +import type { NotificationPolicyJSON } from 'flavours/glitch/api_types/notification_policies'; + +export const apiGetNotificationPolicy = () => + apiRequest('GET', '/v1/notifications/policy'); + +export const apiUpdateNotificationsPolicy = ( + policy: Partial, +) => + apiRequest('PUT', '/v1/notifications/policy', policy); diff --git a/app/javascript/flavours/glitch/api_types/notification_policies.ts b/app/javascript/flavours/glitch/api_types/notification_policies.ts new file mode 100644 index 0000000000..0f4a2d132e --- /dev/null +++ b/app/javascript/flavours/glitch/api_types/notification_policies.ts @@ -0,0 +1,12 @@ +// See app/serializers/rest/notification_policy_serializer.rb + +export interface NotificationPolicyJSON { + filter_not_following: boolean; + filter_not_followers: boolean; + filter_new_accounts: boolean; + filter_private_mentions: boolean; + summary: { + pending_requests_count: number; + pending_notifications_count: number; + }; +} diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx index ee78466b90..1ed7797509 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx @@ -25,7 +25,7 @@ class ColumnSettings extends PureComponent { alertsEnabled: PropTypes.bool, browserSupport: PropTypes.bool, browserPermission: PropTypes.string, - notificationPolicy: ImmutablePropTypes.map, + notificationPolicy: PropTypes.object.isRequired, onChangePolicy: PropTypes.func.isRequired, }; @@ -84,22 +84,22 @@ class ColumnSettings extends PureComponent {

- + - + - + - + diff --git a/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.jsx b/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.jsx deleted file mode 100644 index 8c8b9e4b86..0000000000 --- a/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useEffect } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import { Link } from 'react-router-dom'; - -import { useDispatch, useSelector } from 'react-redux'; - -import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; -import { fetchNotificationPolicy } from 'flavours/glitch/actions/notifications'; -import { Icon } from 'flavours/glitch/components/icon'; -import { toCappedNumber } from 'flavours/glitch/utils/numbers'; - -export const FilteredNotificationsBanner = () => { - const dispatch = useDispatch(); - const policy = useSelector(state => state.get('notificationPolicy')); - - useEffect(() => { - dispatch(fetchNotificationPolicy()); - - const interval = setInterval(() => { - dispatch(fetchNotificationPolicy()); - }, 120000); - - return () => { - clearInterval(interval); - }; - }, [dispatch]); - - if (policy === null || policy.getIn(['summary', 'pending_notifications_count']) === 0) { - return null; - } - - return ( - - - -
- - -
- -
-
{toCappedNumber(policy.getIn(['summary', 'pending_notifications_count']))}
- -
- - ); -}; diff --git a/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.tsx b/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.tsx new file mode 100644 index 0000000000..70762be0e3 --- /dev/null +++ b/app/javascript/flavours/glitch/features/notifications/components/filtered_notifications_banner.tsx @@ -0,0 +1,68 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; +import { fetchNotificationPolicy } from 'flavours/glitch/actions/notification_policies'; +import { Icon } from 'flavours/glitch/components/icon'; +import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; +import { toCappedNumber } from 'flavours/glitch/utils/numbers'; + +export const FilteredNotificationsBanner: React.FC = () => { + const dispatch = useAppDispatch(); + const policy = useAppSelector((state) => state.notificationPolicy); + + useEffect(() => { + void dispatch(fetchNotificationPolicy()); + + const interval = setInterval(() => { + void dispatch(fetchNotificationPolicy()); + }, 120000); + + return () => { + clearInterval(interval); + }; + }, [dispatch]); + + if (policy === null || policy.summary.pending_notifications_count === 0) { + return null; + } + + return ( + + + +
+ + + + + + +
+ +
+
+ {toCappedNumber(policy.summary.pending_notifications_count)} +
+ +
+ + ); +}; diff --git a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js index de266160f8..4547fde042 100644 --- a/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/notifications/containers/column_settings_container.js @@ -4,7 +4,8 @@ import { connect } from 'react-redux'; import { showAlert } from '../../../actions/alerts'; import { openModal } from '../../../actions/modal'; -import { setFilter, clearNotifications, requestBrowserPermission, updateNotificationsPolicy } from '../../../actions/notifications'; +import { updateNotificationsPolicy } from '../../../actions/notification_policies'; +import { setFilter, clearNotifications, requestBrowserPermission } from '../../../actions/notifications'; import { changeAlerts as changePushNotifications } from '../../../actions/push_notifications'; import { changeSetting } from '../../../actions/settings'; import ColumnSettings from '../components/column_settings'; @@ -15,13 +16,16 @@ const messages = defineMessages({ permissionDenied: { id: 'notifications.permission_denied_alert', defaultMessage: 'Desktop notifications can\'t be enabled, as browser permission has been denied before' }, }); +/** + * @param {import('flavours/glitch/store').RootState} state + */ const mapStateToProps = state => ({ settings: state.getIn(['settings', 'notifications']), pushSettings: state.get('push_notifications'), alertsEnabled: state.getIn(['settings', 'notifications', 'alerts']).includes(true), browserSupport: state.getIn(['notifications', 'browserSupport']), browserPermission: state.getIn(['notifications', 'browserPermission']), - notificationPolicy: state.get('notificationPolicy'), + notificationPolicy: state.notificationPolicy, }); const mapDispatchToProps = (dispatch, { intl }) => ({ diff --git a/app/javascript/flavours/glitch/models/notification_policy.ts b/app/javascript/flavours/glitch/models/notification_policy.ts new file mode 100644 index 0000000000..7d97559413 --- /dev/null +++ b/app/javascript/flavours/glitch/models/notification_policy.ts @@ -0,0 +1,3 @@ +import type { NotificationPolicyJSON } from 'flavours/glitch/api_types/notification_policies'; + +export type NotificationPolicy = NotificationPolicyJSON; // No changes from the API type diff --git a/app/javascript/flavours/glitch/reducers/notification_policy.js b/app/javascript/flavours/glitch/reducers/notification_policy.js deleted file mode 100644 index 579f2afdb2..0000000000 --- a/app/javascript/flavours/glitch/reducers/notification_policy.js +++ /dev/null @@ -1,12 +0,0 @@ -import { fromJS } from 'immutable'; - -import { NOTIFICATION_POLICY_FETCH_SUCCESS } from 'flavours/glitch/actions/notifications'; - -export const notificationPolicyReducer = (state = null, action) => { - switch(action.type) { - case NOTIFICATION_POLICY_FETCH_SUCCESS: - return fromJS(action.policy); - default: - return state; - } -}; diff --git a/app/javascript/flavours/glitch/reducers/notification_policy.ts b/app/javascript/flavours/glitch/reducers/notification_policy.ts new file mode 100644 index 0000000000..2d5450ce44 --- /dev/null +++ b/app/javascript/flavours/glitch/reducers/notification_policy.ts @@ -0,0 +1,18 @@ +import { createReducer, isAnyOf } from '@reduxjs/toolkit'; + +import { + fetchNotificationPolicy, + updateNotificationsPolicy, +} from 'flavours/glitch/actions/notification_policies'; +import type { NotificationPolicy } from 'flavours/glitch/models/notification_policy'; + +export const notificationPolicyReducer = + createReducer(null, (builder) => { + builder.addMatcher( + isAnyOf( + fetchNotificationPolicy.fulfilled, + updateNotificationsPolicy.fulfilled, + ), + (_state, action) => action.payload, + ); + }); diff --git a/app/javascript/mastodon/actions/notification_policies.ts b/app/javascript/mastodon/actions/notification_policies.ts new file mode 100644 index 0000000000..fcc9919c49 --- /dev/null +++ b/app/javascript/mastodon/actions/notification_policies.ts @@ -0,0 +1,16 @@ +import { + apiGetNotificationPolicy, + apiUpdateNotificationsPolicy, +} from 'mastodon/api/notification_policies'; +import type { NotificationPolicy } from 'mastodon/models/notification_policy'; +import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; + +export const fetchNotificationPolicy = createDataLoadingThunk( + 'notificationPolicy/fetch', + () => apiGetNotificationPolicy(), +); + +export const updateNotificationsPolicy = createDataLoadingThunk( + 'notificationPolicy/update', + (policy: Partial) => apiUpdateNotificationsPolicy(policy), +); diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index fe728aa26e..6a59d5624e 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -44,10 +44,6 @@ export const NOTIFICATIONS_MARK_AS_READ = 'NOTIFICATIONS_MARK_AS_READ'; export const NOTIFICATIONS_SET_BROWSER_SUPPORT = 'NOTIFICATIONS_SET_BROWSER_SUPPORT'; export const NOTIFICATIONS_SET_BROWSER_PERMISSION = 'NOTIFICATIONS_SET_BROWSER_PERMISSION'; -export const NOTIFICATION_POLICY_FETCH_REQUEST = 'NOTIFICATION_POLICY_FETCH_REQUEST'; -export const NOTIFICATION_POLICY_FETCH_SUCCESS = 'NOTIFICATION_POLICY_FETCH_SUCCESS'; -export const NOTIFICATION_POLICY_FETCH_FAIL = 'NOTIFICATION_POLICY_FETCH_FAIL'; - export const NOTIFICATION_REQUESTS_FETCH_REQUEST = 'NOTIFICATION_REQUESTS_FETCH_REQUEST'; export const NOTIFICATION_REQUESTS_FETCH_SUCCESS = 'NOTIFICATION_REQUESTS_FETCH_SUCCESS'; export const NOTIFICATION_REQUESTS_FETCH_FAIL = 'NOTIFICATION_REQUESTS_FETCH_FAIL'; @@ -346,40 +342,6 @@ export function setBrowserPermission (value) { }; } -export const fetchNotificationPolicy = () => (dispatch) => { - dispatch(fetchNotificationPolicyRequest()); - - api().get('/api/v1/notifications/policy').then(({ data }) => { - dispatch(fetchNotificationPolicySuccess(data)); - }).catch(err => { - dispatch(fetchNotificationPolicyFail(err)); - }); -}; - -export const fetchNotificationPolicyRequest = () => ({ - type: NOTIFICATION_POLICY_FETCH_REQUEST, -}); - -export const fetchNotificationPolicySuccess = policy => ({ - type: NOTIFICATION_POLICY_FETCH_SUCCESS, - policy, -}); - -export const fetchNotificationPolicyFail = error => ({ - type: NOTIFICATION_POLICY_FETCH_FAIL, - error, -}); - -export const updateNotificationsPolicy = params => (dispatch) => { - dispatch(fetchNotificationPolicyRequest()); - - api().put('/api/v1/notifications/policy', params).then(({ data }) => { - dispatch(fetchNotificationPolicySuccess(data)); - }).catch(err => { - dispatch(fetchNotificationPolicyFail(err)); - }); -}; - export const fetchNotificationRequests = () => (dispatch, getState) => { const params = {}; diff --git a/app/javascript/mastodon/api/notification_policies.ts b/app/javascript/mastodon/api/notification_policies.ts new file mode 100644 index 0000000000..b2a1e5ac31 --- /dev/null +++ b/app/javascript/mastodon/api/notification_policies.ts @@ -0,0 +1,10 @@ +import { apiRequest } from 'mastodon/api'; +import type { NotificationPolicyJSON } from 'mastodon/api_types/notification_policies'; + +export const apiGetNotificationPolicy = () => + apiRequest('GET', '/v1/notifications/policy'); + +export const apiUpdateNotificationsPolicy = ( + policy: Partial, +) => + apiRequest('PUT', '/v1/notifications/policy', policy); diff --git a/app/javascript/mastodon/api_types/notification_policies.ts b/app/javascript/mastodon/api_types/notification_policies.ts new file mode 100644 index 0000000000..0f4a2d132e --- /dev/null +++ b/app/javascript/mastodon/api_types/notification_policies.ts @@ -0,0 +1,12 @@ +// See app/serializers/rest/notification_policy_serializer.rb + +export interface NotificationPolicyJSON { + filter_not_following: boolean; + filter_not_followers: boolean; + filter_new_accounts: boolean; + filter_private_mentions: boolean; + summary: { + pending_requests_count: number; + pending_notifications_count: number; + }; +} diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx index e375b856c9..39e394e449 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx +++ b/app/javascript/mastodon/features/notifications/components/column_settings.jsx @@ -24,7 +24,7 @@ class ColumnSettings extends PureComponent { alertsEnabled: PropTypes.bool, browserSupport: PropTypes.bool, browserPermission: PropTypes.string, - notificationPolicy: ImmutablePropTypes.map, + notificationPolicy: PropTypes.object.isRequired, onChangePolicy: PropTypes.func.isRequired, }; @@ -82,22 +82,22 @@ class ColumnSettings extends PureComponent {

- + - + - + - + diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx deleted file mode 100644 index 56da7ba626..0000000000 --- a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useEffect } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import { Link } from 'react-router-dom'; - -import { useDispatch, useSelector } from 'react-redux'; - -import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; -import { fetchNotificationPolicy } from 'mastodon/actions/notifications'; -import { Icon } from 'mastodon/components/icon'; -import { toCappedNumber } from 'mastodon/utils/numbers'; - -export const FilteredNotificationsBanner = () => { - const dispatch = useDispatch(); - const policy = useSelector(state => state.get('notificationPolicy')); - - useEffect(() => { - dispatch(fetchNotificationPolicy()); - - const interval = setInterval(() => { - dispatch(fetchNotificationPolicy()); - }, 120000); - - return () => { - clearInterval(interval); - }; - }, [dispatch]); - - if (policy === null || policy.getIn(['summary', 'pending_notifications_count']) === 0) { - return null; - } - - return ( - - - -
- - -
- -
-
{toCappedNumber(policy.getIn(['summary', 'pending_notifications_count']))}
- -
- - ); -}; diff --git a/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx new file mode 100644 index 0000000000..2c4b3b9717 --- /dev/null +++ b/app/javascript/mastodon/features/notifications/components/filtered_notifications_banner.tsx @@ -0,0 +1,68 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import InventoryIcon from '@/material-icons/400-24px/inventory_2.svg?react'; +import { fetchNotificationPolicy } from 'mastodon/actions/notification_policies'; +import { Icon } from 'mastodon/components/icon'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; +import { toCappedNumber } from 'mastodon/utils/numbers'; + +export const FilteredNotificationsBanner: React.FC = () => { + const dispatch = useAppDispatch(); + const policy = useAppSelector((state) => state.notificationPolicy); + + useEffect(() => { + void dispatch(fetchNotificationPolicy()); + + const interval = setInterval(() => { + void dispatch(fetchNotificationPolicy()); + }, 120000); + + return () => { + clearInterval(interval); + }; + }, [dispatch]); + + if (policy === null || policy.summary.pending_notifications_count === 0) { + return null; + } + + return ( + + + +
+ + + + + + +
+ +
+
+ {toCappedNumber(policy.summary.pending_notifications_count)} +
+ +
+ + ); +}; diff --git a/app/javascript/mastodon/features/notifications/containers/column_settings_container.js b/app/javascript/mastodon/features/notifications/containers/column_settings_container.js index de266160f8..94383d0bb5 100644 --- a/app/javascript/mastodon/features/notifications/containers/column_settings_container.js +++ b/app/javascript/mastodon/features/notifications/containers/column_settings_container.js @@ -4,7 +4,8 @@ import { connect } from 'react-redux'; import { showAlert } from '../../../actions/alerts'; import { openModal } from '../../../actions/modal'; -import { setFilter, clearNotifications, requestBrowserPermission, updateNotificationsPolicy } from '../../../actions/notifications'; +import { updateNotificationsPolicy } from '../../../actions/notification_policies'; +import { setFilter, clearNotifications, requestBrowserPermission } from '../../../actions/notifications'; import { changeAlerts as changePushNotifications } from '../../../actions/push_notifications'; import { changeSetting } from '../../../actions/settings'; import ColumnSettings from '../components/column_settings'; @@ -15,13 +16,16 @@ const messages = defineMessages({ permissionDenied: { id: 'notifications.permission_denied_alert', defaultMessage: 'Desktop notifications can\'t be enabled, as browser permission has been denied before' }, }); +/** + * @param {import('mastodon/store').RootState} state + */ const mapStateToProps = state => ({ settings: state.getIn(['settings', 'notifications']), pushSettings: state.get('push_notifications'), alertsEnabled: state.getIn(['settings', 'notifications', 'alerts']).includes(true), browserSupport: state.getIn(['notifications', 'browserSupport']), browserPermission: state.getIn(['notifications', 'browserPermission']), - notificationPolicy: state.get('notificationPolicy'), + notificationPolicy: state.notificationPolicy, }); const mapDispatchToProps = (dispatch, { intl }) => ({ diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 46e28b999b..547a0fe61f 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -147,14 +147,14 @@ "compose.published.body": "Postitus avaldatud.", "compose.published.open": "Ava", "compose.saved.body": "Postitus salvestatud.", - "compose_form.direct_message_warning_learn_more": "Vaata täpsemalt", + "compose_form.direct_message_warning_learn_more": "Vaata lisa", "compose_form.encryption_warning": "Postitused Mastodonis ei ole otsast-otsani krüpteeritud. Ära jaga mingeid delikaatseid andmeid Mastodoni kaudu.", "compose_form.hashtag_warning": "See postitus ei ilmu ühegi märksõna all, kuna pole avalik. Vaid avalikud postitused on märksõnade kaudu leitavad.", "compose_form.lock_disclaimer": "Su konto ei ole {locked}. Igaüks saab sind jälgida, et näha su ainult-jälgijatele postitusi.", "compose_form.lock_disclaimer.lock": "lukus", "compose_form.placeholder": "Millest mõtled?", "compose_form.poll.duration": "Küsitluse kestus", - "compose_form.poll.multiple": "Valikvastustega", + "compose_form.poll.multiple": "Mitu vastust", "compose_form.poll.option_placeholder": "Valik {number}", "compose_form.poll.single": "Vali üks", "compose_form.poll.switch_to_multiple": "Muuda küsitlust mitmikvaliku lubamiseks", @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Kasuta olemasolevat kategooriat või loo uus", "filter_modal.select_filter.title": "Filtreeri seda postitust", "filter_modal.title.status": "Postituse filtreerimine", + "filtered_notifications_banner.mentions": "{count, plural, one {mainimine} other {mainimist}}", "filtered_notifications_banner.pending_requests": "Teateid {count, plural, =0 {mitte üheltki} one {ühelt} other {#}} inimeselt, keda võid teada", "filtered_notifications_banner.title": "Filtreeritud teavitused", "firehose.all": "Kõik", @@ -305,15 +306,19 @@ "follow_request.authorize": "Autoriseeri", "follow_request.reject": "Hülga", "follow_requests.unlocked_explanation": "Kuigi su konto pole lukustatud, soovitab {domain} personal siiski nende kontode jälgimistaotlused käsitsi üle vaadata.", - "follow_suggestions.curated_suggestion": "Teiste valitud", + "follow_suggestions.curated_suggestion": "Meeskonna valitud", "follow_suggestions.dismiss": "Ära enam näita", - "follow_suggestions.hints.featured": "Selle kasutajaprofiili on soovitanud {domain} kasutajad.", - "follow_suggestions.hints.friends_of_friends": "See kasutajaprofiil on jälgitavate seas populaarne.", + "follow_suggestions.featured_longer": "Käsitsi valitud {domain} meeskonna poolt", + "follow_suggestions.friends_of_friends_longer": "Populaarne inimeste hulgas, keda jälgid", + "follow_suggestions.hints.featured": "Selle kasutajaprofiili on soovitanud {domain} meeskond.", + "follow_suggestions.hints.friends_of_friends": "See kasutajaprofiil on sinu jälgitavate seas populaarne.", "follow_suggestions.hints.most_followed": "See on {domain} enim jälgitud kasutajaprofiil.", - "follow_suggestions.hints.most_interactions": "See on {domain} viimasel ajal enim tähelepanu saanud kasutajaprofiil.", + "follow_suggestions.hints.most_interactions": "See kasutajaprofiil on viimasel ajal {domain} saanud palju tähelepanu.", "follow_suggestions.hints.similar_to_recently_followed": "See kasutajaprofiil sarnaneb neile, mida oled hiljuti jälgima asunud.", "follow_suggestions.personalized_suggestion": "Isikupärastatud soovitus", "follow_suggestions.popular_suggestion": "Popuplaarne soovitus", + "follow_suggestions.popular_suggestion_longer": "Populaarne kohas {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Sarnane profiilile, mida hiljuti jälgima hakkasid", "follow_suggestions.view_all": "Vaata kõiki", "follow_suggestions.who_to_follow": "Keda jälgida", "followed_tags": "Jälgitavad märksõnad", @@ -409,6 +414,8 @@ "limited_account_hint.action": "Näita profilli sellegipoolest", "limited_account_hint.title": "See profiil on peidetud {domain} moderaatorite poolt.", "link_preview.author": "{name} poolt", + "link_preview.more_from_author": "Veel kasutajalt {name}", + "link_preview.shares": "{count, plural, one {{counter} postitus} other {{counter} postitust}}", "lists.account.add": "Lisa nimekirja", "lists.account.remove": "Eemalda nimekirjast", "lists.delete": "Kustuta nimekiri", @@ -468,13 +475,22 @@ "notification.follow": "{name} alustas su jälgimist", "notification.follow_request": "{name} soovib sind jälgida", "notification.mention": "{name} mainis sind", + "notification.moderation-warning.learn_more": "Vaata lisa", + "notification.moderation_warning": "Said modereerimise hoiatuse", + "notification.moderation_warning.action_delete_statuses": "Mõni su postitus on eemaldatud.", + "notification.moderation_warning.action_disable": "Su konto on keelatud.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Mõni su postitustest on märgitud kui tundlik.", + "notification.moderation_warning.action_none": "Su konto on saanud modereerimise hoiatuse.", + "notification.moderation_warning.action_sensitive": "Su postitused märgitakse nüüdsest tundlikuks.", + "notification.moderation_warning.action_silence": "Su kontole pandi piirang.", + "notification.moderation_warning.action_suspend": "Su konto on peatatud.", "notification.own_poll": "Su küsitlus on lõppenud", "notification.poll": "Küsitlus, milles osalesid, on lõppenud", "notification.reblog": "{name} jagas edasi postitust", "notification.relationships_severance_event": "Kadunud ühendus kasutajaga {name}", "notification.relationships_severance_event.account_suspension": "{from} admin on kustutanud {target}, mis tähendab, et sa ei saa enam neilt uuendusi või suhelda nendega.", "notification.relationships_severance_event.domain_block": "{from} admin on blokeerinud {target}, sealhulgas {followersCount} sinu jälgijat ja {followingCount, plural, one {# konto} other {# kontot}}, mida jälgid.", - "notification.relationships_severance_event.learn_more": "Saa rohkem teada", + "notification.relationships_severance_event.learn_more": "Vaata lisa", "notification.relationships_severance_event.user_domain_block": "Blokeerisid {target}, eemaldades oma jälgijate hulgast {followersCount} ja jälgitavate hulgast {followingCount, plural, one {# konto} other {# kontot}}.", "notification.status": "{name} just postitas", "notification.update": "{name} muutis postitust", @@ -680,8 +696,11 @@ "server_banner.about_active_users": "Inimesed, kes kasutavad seda serverit viimase 30 päeva jooksul (kuu aktiivsed kasutajad)", "server_banner.active_users": "aktiivsed kasutajad", "server_banner.administered_by": "Administraator:", + "server_banner.is_one_of_many": "{domain} on üks paljudest sõltumatutest Mastodoni serveritest, mida saab fediversumis osalemiseks kasutada.", "server_banner.server_stats": "Serveri statistika:", "sign_in_banner.create_account": "Loo konto", + "sign_in_banner.follow_anyone": "Jälgi ükskõik keda kogu fediversumist ja näe kõike ajalises järjestuses. Ei mingeid algoritme, reklaame või klikipüüdjaid segamas.", + "sign_in_banner.mastodon_is": "Mastodon on parim viis olemaks kursis sellega, mis toimub.", "sign_in_banner.sign_in": "Logi sisse", "sign_in_banner.sso_redirect": "Sisene või registreeru", "status.admin_account": "Ava @{name} moderaatorivaates", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 72bbe606fa..53cc938592 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -696,8 +696,10 @@ "server_banner.about_active_users": "Personas que ha usate iste servitor in le ultime 30 dies (usatores active per mense)", "server_banner.active_users": "usatores active", "server_banner.administered_by": "Administrate per:", + "server_banner.is_one_of_many": "{domain} es un de multe servitores independente de Mastodon que tu pote usar pro participar in le fediverso.", "server_banner.server_stats": "Statos del servitor:", "sign_in_banner.create_account": "Crear un conto", + "sign_in_banner.mastodon_is": "Mastodon es le melior maniera de sequer lo que passa.", "sign_in_banner.sign_in": "Aperir session", "sign_in_banner.sso_redirect": "Aperir session o crear conto", "status.admin_account": "Aperir le interfacie de moderation pro @{name}", diff --git a/app/javascript/mastodon/models/notification_policy.ts b/app/javascript/mastodon/models/notification_policy.ts new file mode 100644 index 0000000000..eb65403292 --- /dev/null +++ b/app/javascript/mastodon/models/notification_policy.ts @@ -0,0 +1,3 @@ +import type { NotificationPolicyJSON } from 'mastodon/api_types/notification_policies'; + +export type NotificationPolicy = NotificationPolicyJSON; // No changes from the API type diff --git a/app/javascript/mastodon/reducers/notification_policy.js b/app/javascript/mastodon/reducers/notification_policy.js deleted file mode 100644 index 8edb4d12a1..0000000000 --- a/app/javascript/mastodon/reducers/notification_policy.js +++ /dev/null @@ -1,12 +0,0 @@ -import { fromJS } from 'immutable'; - -import { NOTIFICATION_POLICY_FETCH_SUCCESS } from 'mastodon/actions/notifications'; - -export const notificationPolicyReducer = (state = null, action) => { - switch(action.type) { - case NOTIFICATION_POLICY_FETCH_SUCCESS: - return fromJS(action.policy); - default: - return state; - } -}; diff --git a/app/javascript/mastodon/reducers/notification_policy.ts b/app/javascript/mastodon/reducers/notification_policy.ts new file mode 100644 index 0000000000..ab111066cc --- /dev/null +++ b/app/javascript/mastodon/reducers/notification_policy.ts @@ -0,0 +1,18 @@ +import { createReducer, isAnyOf } from '@reduxjs/toolkit'; + +import { + fetchNotificationPolicy, + updateNotificationsPolicy, +} from 'mastodon/actions/notification_policies'; +import type { NotificationPolicy } from 'mastodon/models/notification_policy'; + +export const notificationPolicyReducer = + createReducer(null, (builder) => { + builder.addMatcher( + isAnyOf( + fetchNotificationPolicy.fulfilled, + updateNotificationsPolicy.fulfilled, + ), + (_state, action) => action.payload, + ); + }); diff --git a/app/lib/admin/metrics/measure/query_helper.rb b/app/lib/admin/metrics/measure/query_helper.rb index 5969a96ba9..47cfc63e5c 100644 --- a/app/lib/admin/metrics/measure/query_helper.rb +++ b/app/lib/admin/metrics/measure/query_helper.rb @@ -18,7 +18,7 @@ module Admin::Metrics::Measure::QueryHelper def generated_series_days Arel.sql( <<~SQL.squish - SELECT generate_series(timestamp :start_at, :end_at, '1 day')::date AS period + SELECT generate_series(:start_at::timestamp, :end_at::timestamp, '1 day')::date AS period SQL ) end diff --git a/app/lib/extractor.rb b/app/lib/extractor.rb index 9090773ae9..7e647a7587 100644 --- a/app/lib/extractor.rb +++ b/app/lib/extractor.rb @@ -86,10 +86,6 @@ module Extractor possible_entries end - def extract_cashtags_with_indices(_text) - [] - end - def extract_extra_uris_with_indices(text) return [] unless text&.index(':') diff --git a/app/serializers/rest/notification_policy_serializer.rb b/app/serializers/rest/notification_policy_serializer.rb index a50ba9e66b..8bf85250fa 100644 --- a/app/serializers/rest/notification_policy_serializer.rb +++ b/app/serializers/rest/notification_policy_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class REST::NotificationPolicySerializer < ActiveModel::Serializer + # Please update `app/javascript/mastodon/api_types/notification_policies.ts` when making changes to the attributes + attributes :filter_not_following, :filter_not_followers, :filter_new_accounts, diff --git a/config/locales/doorkeeper.et.yml b/config/locales/doorkeeper.et.yml index 1843031706..13d3f40fea 100644 --- a/config/locales/doorkeeper.et.yml +++ b/config/locales/doorkeeper.et.yml @@ -135,6 +135,7 @@ et: media: Lisatud meedia mutes: Vaigistused notifications: Teavitused + profile: Sinu Mastodoni profiil push: Tõuketeated reports: Teavitused search: Otsing @@ -165,6 +166,7 @@ et: admin:write:reports: teostada moderaatori tegevusi teavitustel crypto: kasuta otspunktkrüpeerimist follow: muuta kontode suhteid + profile: loe vaid oma konto profiili infot push: saab tõuketeateid read: lugeda konto kõiki andmeid read:accounts: näha konto informatsiooni diff --git a/config/locales/et.yml b/config/locales/et.yml index 172aad25b9..30d75d25ee 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -285,6 +285,7 @@ et: update_custom_emoji_html: "%{name} uuendas emotikoni %{target}" update_domain_block_html: "%{name} uuendas domeeni %{target} keeldu" update_ip_block_html: "%{name} muutis IP-aadressi %{target} reeglit" + update_report_html: "%{name} uuendas raportit %{target}" update_status_html: "%{name} muutis %{target} postitust" update_user_role_html: "%{name} muutis %{target} rolli" deleted_account: kustutatud konto @@ -292,6 +293,7 @@ et: filter_by_action: Filtreeri tegevuse järgi filter_by_user: Filtreeri kasutaja järgi title: Auditilogi + unavailable_instance: "(domeeni nimi pole saadaval)" announcements: destroyed_msg: Teadaande kustutamine õnnestus! edit: @@ -751,6 +753,7 @@ et: desc_html: See tugineb välistele hCaptcha skriptidele, mis võib olla turvalisuse ja privaatsuse probleem. Lisaks võib see muuta registreerimisprotsessi mõnede inimeste (eriti puudega inimeste) jaoks, oluliselt vähem ligipääsetavaks. Neil põhjustel kaalu palun teisi võimalusi, näiteks kinnitamis- või kutsepõhiseid registreerimislahendusi. title: Nõua uutelt kasutajatelt konto kinnitamiseks CAPTCHA lahendamist content_retention: + danger_zone: Ohutsoon preamble: Määra, kuidas kasutajate loodud sisu Mastodonis talletatakse. title: Sisu talletamine default_noindex: @@ -770,7 +773,7 @@ et: disabled: Mitte kellelegi users: Sisseloginud kohalikele kasutajatele registrations: - moderation_recommandation: Enne registreeringute avamist kõigile veendu, et oleks olemas adekvaatne ja reageerimisvalmis modereerijaskond! + moderation_recommandation: Enne kõigi jaoks registreerimise avamist veendu, et oleks olemas adekvaatne ja reageerimisvalmis modereerijaskond! preamble: Kes saab serveril konto luua. title: Registreerimised registrations_mode: @@ -791,7 +794,7 @@ et: software_updates: critical_update: Kriitiline — uuenda kiiresti description: On soovitav hoida oma Mastodoni paigaldus kõige uuemal kujul, et saada kasu kõige värskematest parandustest ja oskustest. Lisaks, vahel on Mastodoni kiire uuendamine kriitiline, et vältida turvaprobleeme. Neil põhjustel kontrollib Mastodon uuendusi iga 30 minuti tagant ja teavitab sind vastavalt su e-posti teavituste eelistustele. - documentation_link: Saa rohkem teada + documentation_link: Vaata lisa release_notes: Väljalaskemärkused title: Saadaval uuendused type: Tüüp @@ -949,6 +952,7 @@ et: delete: Kustuta edit_preset: Hoiatuse eelseadistuse muutmine empty: Hoiatuste eelseadeid pole defineeritud. + title: Hoiatuste eelhäälestused webhooks: add_new: Lisa lõpp-punkt delete: Kustuta @@ -1814,8 +1818,8 @@ et: title: Arhiivi väljavõte failed_2fa: details: 'Sisenemise üksikasjad:' - explanation: Keegi püüdis Su kontole siseneda, ent sisestas vale teisese autentimisfaktori. - further_actions_html: Kui see polnud Sina, siis soovitame viivitamata %{action}, kuna see võib olla lekkinud. + explanation: Keegi püüdis Su kontole siseneda, ent sisestas vale kaheastmelise autentimise faktori. + further_actions_html: Kui see polnud Sina, siis soovitame viivitamata %{action}, kuna see võib olla ohus. subject: Kaheastmelise autentimise nurjumine title: Kaheastmeline autentimine nurjus suspicious_sign_in: @@ -1857,9 +1861,9 @@ et: silence: Konto limiteeritud suspend: Konto kustutatud welcome: - apps_android_action: Google Play poest + apps_android_action: Laadi see Google Playst apps_ios_action: Allalaadimine App Store'ist - apps_step: Meie ametlikud rakendused. + apps_step: Laadi meie ametlikud rakendused. apps_title: Mastodoni rakendused checklist_subtitle: 'Kuidas sel uudsel sotsiaalmeediarindel pihta hakata:' checklist_title: Millest alustada @@ -1872,7 +1876,7 @@ et: feature_audience_title: Kogu enesekindlalt jälgijaid feature_control: Tead ise kõige paremini, mida soovid oma koduvoos näha. Ei aega raiskavaid algoritme ega reklaame. Jälgi ühe kasutajakonto kaudu keda iganes mistahes Mastodoni serveris ja näe postitusi ajalises järjestuses, muutes oma nurgakese Internetist rohkem endale meelepärasemaks. feature_control_title: Säilita oma ajajoone üle kontroll - feature_creativity: Mastodon toetab audiot, video- ja pildipostitusi, liigipääsetavuse kirjeldusi, küsitlusi, sisuhoiatusi, animeeritud avatare, kohandatud emotikone, pisipiltide lõikeeelistusi ja enamatki, et end võrgus väljendada. Kas avaldad kunsti, muusikat või taskuhäälingusaadet, Mastodon on mõeldud Sinu jaoks. + feature_creativity: Mastodon toetab audiot, video- ja pildipostitusi, ligipääsetavuse kirjeldusi, küsitlusi, sisuhoiatusi, animeeritud avatare, kohandatud emotikone, pisipiltide lõikeeelistusi ja enamatki, et end võrgus väljendada. Kas avaldad kunsti, muusikat või taskuhäälingut, Mastodon on mõeldud Sinu jaoks. feature_creativity_title: Võrreldamatu loovus feature_moderation: Mastodon annab otsustusõiguse tagasi Sinu kätte. Igal serveril on oma reeglid ja regulatsioonid, mida hallatakse kohapeal, mitte nagu ülalt-alla korporatiivses sotsiaalmeedias, võimaldades enim paindlikku vastavust erinevate vajadustega gruppide ja inimeste eelistustele. Liitu sobivate reeglitega serveriga, või käivita oma server. feature_moderation_title: Modereerimine, nagu see olema peab diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml index b2ad4c51cf..4dd74e68a3 100644 --- a/config/locales/simple_form.et.yml +++ b/config/locales/simple_form.et.yml @@ -77,10 +77,15 @@ et: warn: Varja filtreeritud sisu hoiatusega, nimetades filtri pealkirja form_admin_settings: activity_api_enabled: Kohalike postituste, aktiivsete kasutajate ja uute registreerumistr arv nädala kaupa grupeeritult + app_icon: WEBP, PNG, GIF või JPG. Asendab mobiilsel seadmel äpi vaikeikooni kohandatud ikooniga. + backups_retention_period: Kasutajatel on võimalus genereerida oma postitustest hiljem allalaaditav arhiiv. Kui määrata positiivne arv, kustutatakse serveri talletusruumist need arhiivid määratud arvu päevade järel automaatselt. bootstrap_timeline_accounts: Need kasutajad kinnitatakse uute kasutajate jälgimissoovituste esiritta. closed_registrations_message: Kuvatakse, kui liitumised pole võimalikud - custom_css: Kohandatud stiile on võimalik kasutada Mastodoni veebiliideses. + content_cache_retention_period: Kõik teiste serverite postitused (sealhulgas jagamised ja vastused) kustutatakse pärast määratud arvu päevade möödumist, sõltumata, kuidas kohalik kasutaja on nende postitustega interakteerunud. Hõlmatud on ka postitused, mille kohalik kasutaja on märkinud järjehoidjaks või lemmikuks. Ka eri instantside kasutajate vahelised privaatsed mainimised kaovad ja neid on võimatu taastada. See seadistus on mõeldud eriotstarbeliste instantside jaoks ja rikub paljude kasutajate ootusi, kui seda rakendatakse üldotstarbelise kasutuse puhul. + custom_css: Mastodoni veebiliideses on võimalik kasutada kohandatud stiile. + favicon: WEBP, PNG, GIF või JPG. Asendab Mastodoni vaike- favicon ikooni kohandatud ikooniga. mascot: Asendab kohandatud veebiliidese illustratsiooni. + media_cache_retention_period: Kaugkasutajate tehtud postituste meediafailid salvestatakse teie serveri vahemällu. Kui see seadistus on seatud positiivsele väärtusele, kustutatakse meediumifailid määratud päevade möödumisel. Kui meediaandmeid küsitakse pärast nende kustutamist, laaditakse need uuesti alla, kui lähtesisu on veel saadaval. Kuna on olemas piirangud, kui tihti tohivad lingikaardid kolmandatelt saitidelt andmeid pärida, on soovitatav määrata väärtuseks vähemalt 14. Vastasel juhul ei uuendata linkide eelvaatekaarte nõudmise korral enne seda aega. peers_api_enabled: Domeeninimede loetelu, mida see server on Fediversumis kohanud. Mitte mingeid andmeid selle serveri födereerumise kohta antud serverite pole, vaid üksnes info, et sellest serverist ollakse teadlik. Seda kasutavad teenused, mis koguvad üldist födereerumise statistikat. profile_directory: Kasutajate kataloog kuvab nimekirja kasutajatest, kes on seda lubanud. require_invite_text: Kui liitumisi on tarvis kinnitada, oleks "Miks soovid liituda?" vastus vajalik @@ -240,6 +245,7 @@ et: backups_retention_period: Kasutajate arhiivi talletusperiood bootstrap_timeline_accounts: Alati soovita neid kontosid uutele kasutajatele closed_registrations_message: Kohandatud teade, kui liitumine pole võimalik + content_cache_retention_period: Kaugsisu säilitamise aeg custom_css: Kohandatud CSS mascot: Kohandatud maskott (kunagine) media_cache_retention_period: Meediapuhvri talletusperiood diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 8b24a267c1..467356d65a 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -1791,8 +1791,8 @@ vi: suspicious_sign_in: change_password: đổi mật khẩu của bạn details: 'Chi tiết thông tin đăng nhập:' - explanation: Chúng tôi phát hiện lần đăng nhập bất thường tài khoản của bạn từ một địa chỉ IP mới. - further_actions_html: Nếu đó không phải là bạn, chúng tôi khuyến nghị %{action} lập tức và bật xác minh hai bước để giữ tài khoản được an toàn. + explanation: Chúng tôi phát hiện tài khoản của bạn đăng nhập bất thường từ một địa chỉ IP mới. + further_actions_html: Nếu đây không phải là bạn, hãy %{action} lập tức và bật xác minh hai bước để giữ tài khoản được an toàn. subject: Đăng nhập tài khoản từ địa chỉ IP mới title: Lần đăng nhập mới warning: diff --git a/spec/lib/extractor_spec.rb b/spec/lib/extractor_spec.rb index b6c910171d..af5c62d4c8 100644 --- a/spec/lib/extractor_spec.rb +++ b/spec/lib/extractor_spec.rb @@ -69,10 +69,10 @@ describe Extractor do end end - describe 'extract_cashtags_with_indices' do - it 'returns []' do + describe 'extract_entities_with_indices' do + it 'returns empty array when cashtag present' do text = '$cashtag' - extracted = described_class.extract_cashtags_with_indices(text) + extracted = described_class.extract_entities_with_indices(text) expect(extracted).to eq [] end end diff --git a/spec/requests/api/v1/admin/measures_spec.rb b/spec/requests/api/v1/admin/measures_spec.rb index 15f2df84c6..80fed79d9a 100644 --- a/spec/requests/api/v1/admin/measures_spec.rb +++ b/spec/requests/api/v1/admin/measures_spec.rb @@ -7,11 +7,28 @@ describe 'Admin Measures' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:account) { Fabricate(:account) } + let(:params) do + { + keys: %w(instance_accounts instance_follows instance_followers), + instance_accounts: { + domain: 'mastodon.social', + include_subdomains: true, + }, + instance_follows: { + domain: 'mastodon.social', + include_subdomains: true, + }, + instance_followers: { + domain: 'mastodon.social', + include_subdomains: true, + }, + } + end describe 'GET /api/v1/admin/measures' do context 'when not authorized' do it 'returns http forbidden' do - post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 } + post '/api/v1/admin/measures', params: params expect(response) .to have_http_status(403) @@ -22,7 +39,7 @@ describe 'Admin Measures' do let(:scopes) { 'admin:read' } it 'returns http success and status json' do - post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 }, headers: headers + post '/api/v1/admin/measures', params: params, headers: headers expect(response) .to have_http_status(200) diff --git a/streaming/Dockerfile b/streaming/Dockerfile index 564e717a40..aee1f76ad3 100644 --- a/streaming/Dockerfile +++ b/streaming/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.7 +# syntax=docker/dockerfile:1.8 # Please see https://docs.docker.com/engine/reference/builder for information about # the extended buildx capabilities used in this file. diff --git a/yarn.lock b/yarn.lock index 38146e21ad..9864da0fd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15379,15 +15379,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.5 - resolution: "sass@npm:1.77.5" + version: 1.77.6 + resolution: "sass@npm:1.77.6" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/9da049b0a3fadab419084d6becdf471e107cf6e3c8ac87cabea2feb845afac75e86c99e06ee721a5aa4f6a2d833ec5380137c4e540ab2f760edf1e4eb6139e69 + checksum: 10c0/fe5a393c0aa29eda9f83c06be9b94788b61fe8bad0616ee6e3a25d21ab504f430d40c0064fdca89b02b8e426411ae6dcd906c91f2e48c263575c3d392b6daeb1 languageName: node linkType: hard