diff --git a/app/javascript/flavours/glitch/actions/notification_groups.ts b/app/javascript/flavours/glitch/actions/notification_groups.ts index e034792275..2f0174d117 100644 --- a/app/javascript/flavours/glitch/actions/notification_groups.ts +++ b/app/javascript/flavours/glitch/actions/notification_groups.ts @@ -15,6 +15,7 @@ import type { NotificationGap } from 'flavours/glitch/reducers/notification_grou import { selectSettingsNotificationsExcludedTypes, selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsShows, } from 'flavours/glitch/selectors/settings'; import type { AppDispatch } from 'flavours/glitch/store'; import { @@ -104,7 +105,31 @@ export const fetchNotificationsGap = createDataLoadingThunk( export const processNewNotificationForGroups = createAppAsyncThunk( 'notificationGroups/processNew', - (notification: ApiNotificationJSON, { dispatch }) => { + (notification: ApiNotificationJSON, { dispatch, getState }) => { + const state = getState(); + const activeFilter = selectSettingsNotificationsQuickFilterActive(state); + const notificationShows = selectSettingsNotificationsShows(state); + + const showInColumn = + activeFilter === 'all' + ? notificationShows[notification.type] + : activeFilter === notification.type; + + if (!showInColumn) return; + + if ( + (notification.type === 'mention' || notification.type === 'update') && + notification.status.filtered + ) { + const filters = notification.status.filtered.filter((result) => + result.filter.context.includes('notifications'), + ); + + if (filters.some((result) => result.filter.filter_action === 'hide')) { + return; + } + } + dispatchAssociatedRecords(dispatch, [notification]); return notification; diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index 7b006c1be7..2d69542fc7 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -104,7 +104,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti const notificationJSON = JSON.parse(data.payload); dispatch(updateNotifications(notificationJSON, messages, locale)); // TODO: remove this once the groups feature replaces the previous one - if(getState().notificationGroups.groups.length > 0) { + if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) { dispatch(processNewNotificationForGroups(notificationJSON)); } break; diff --git a/app/javascript/flavours/glitch/api/notification_policies.ts b/app/javascript/flavours/glitch/api/notification_policies.ts index 1db79a6e74..48b78f96fc 100644 --- a/app/javascript/flavours/glitch/api/notification_policies.ts +++ b/app/javascript/flavours/glitch/api/notification_policies.ts @@ -2,8 +2,8 @@ import { apiRequestGet, apiRequestPut } from 'flavours/glitch/api'; import type { NotificationPolicyJSON } from 'flavours/glitch/api_types/notification_policies'; export const apiGetNotificationPolicy = () => - apiRequestGet('/v2/notifications/policy'); + apiRequestGet('v2/notifications/policy'); export const apiUpdateNotificationsPolicy = ( policy: Partial, -) => apiRequestPut('/v2/notifications/policy', policy); +) => apiRequestPut('v2/notifications/policy', policy); diff --git a/app/javascript/flavours/glitch/api_types/statuses.ts b/app/javascript/flavours/glitch/api_types/statuses.ts index 9de86e7fa6..c84ecc7afc 100644 --- a/app/javascript/flavours/glitch/api_types/statuses.ts +++ b/app/javascript/flavours/glitch/api_types/statuses.ts @@ -58,6 +58,29 @@ export interface ApiPreviewCardJSON { authors: ApiPreviewCardAuthorJSON[]; } +export type FilterContext = + | 'home' + | 'notifications' + | 'public' + | 'thread' + | 'account'; + +export interface ApiFilterJSON { + id: string; + title: string; + context: FilterContext; + expires_at: string; + filter_action: 'warn' | 'hide'; + keywords?: unknown[]; // TODO: FilterKeywordSerializer + statuses?: unknown[]; // TODO: FilterStatusSerializer +} + +export interface ApiFilterResultJSON { + filter: ApiFilterJSON; + keyword_matches: string[]; + status_matches: string[]; +} + export interface ApiStatusJSON { id: string; created_at: string; @@ -80,8 +103,7 @@ export interface ApiStatusJSON { bookmarked?: boolean; pinned?: boolean; - // filtered: FilterResult[] - filtered: unknown; // TODO + filtered?: ApiFilterResultJSON[]; content?: string; text?: string; diff --git a/app/javascript/flavours/glitch/reducers/notification_groups.ts b/app/javascript/flavours/glitch/reducers/notification_groups.ts index 4dedfe27a8..a721e4008d 100644 --- a/app/javascript/flavours/glitch/reducers/notification_groups.ts +++ b/app/javascript/flavours/glitch/reducers/notification_groups.ts @@ -387,12 +387,14 @@ export const notificationGroupsReducer = createReducer( }) .addCase(processNewNotificationForGroups.fulfilled, (state, action) => { const notification = action.payload; - processNewNotification( - usePendingItems ? state.pendingGroups : state.groups, - notification, - ); - updateLastReadId(state); - trimNotifications(state); + if (notification) { + processNewNotification( + usePendingItems ? state.pendingGroups : state.groups, + notification, + ); + updateLastReadId(state); + trimNotifications(state); + } }) .addCase(disconnectTimeline, (state, action) => { if (action.payload.timeline === 'home') { diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 713126b44f..601666ac05 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -8521,7 +8521,8 @@ noscript { .account__avatar { background: var(--background-color); - border: 2px solid var(--background-border-color); + border: 1px solid var(--background-border-color); + border-radius: 4px; } } } diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 021877d435..d41577cf05 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -52,10 +52,6 @@ html { color: darken($action-button-color, 25%); } -.account__header__bar .avatar .account__avatar { - border-color: $white; -} - .getting-started__footer a { color: $ui-secondary-color; text-decoration: underline; diff --git a/app/javascript/flavours/glitch/styles/reset.scss b/app/javascript/flavours/glitch/styles/reset.scss index 903b6c804f..f54ed5bc79 100644 --- a/app/javascript/flavours/glitch/styles/reset.scss +++ b/app/javascript/flavours/glitch/styles/reset.scss @@ -56,3 +56,40 @@ table { html { scrollbar-color: lighten($ui-base-color, 4%) rgba($base-overlay-background, 0.1); } + +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +::-webkit-scrollbar-thumb { + background: lighten($ui-base-color, 4%); + border: 0px none $base-border-color; + border-radius: 50px; +} + +::-webkit-scrollbar-thumb:hover { + background: lighten($ui-base-color, 6%); +} + +::-webkit-scrollbar-thumb:active { + background: lighten($ui-base-color, 4%); +} + +::-webkit-scrollbar-track { + border: 0px none $base-border-color; + border-radius: 0; + background: rgba($base-overlay-background, 0.1); +} + +::-webkit-scrollbar-track:hover { + background: $ui-base-color; +} + +::-webkit-scrollbar-track:active { + background: $ui-base-color; +} + +::-webkit-scrollbar-corner { + background: transparent; +} diff --git a/app/javascript/mastodon/actions/notification_groups.ts b/app/javascript/mastodon/actions/notification_groups.ts index fc5807c8c0..ab62f8715c 100644 --- a/app/javascript/mastodon/actions/notification_groups.ts +++ b/app/javascript/mastodon/actions/notification_groups.ts @@ -15,6 +15,7 @@ import type { NotificationGap } from 'mastodon/reducers/notification_groups'; import { selectSettingsNotificationsExcludedTypes, selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsShows, } from 'mastodon/selectors/settings'; import type { AppDispatch } from 'mastodon/store'; import { @@ -104,7 +105,31 @@ export const fetchNotificationsGap = createDataLoadingThunk( export const processNewNotificationForGroups = createAppAsyncThunk( 'notificationGroups/processNew', - (notification: ApiNotificationJSON, { dispatch }) => { + (notification: ApiNotificationJSON, { dispatch, getState }) => { + const state = getState(); + const activeFilter = selectSettingsNotificationsQuickFilterActive(state); + const notificationShows = selectSettingsNotificationsShows(state); + + const showInColumn = + activeFilter === 'all' + ? notificationShows[notification.type] + : activeFilter === notification.type; + + if (!showInColumn) return; + + if ( + (notification.type === 'mention' || notification.type === 'update') && + notification.status.filtered + ) { + const filters = notification.status.filtered.filter((result) => + result.filter.context.includes('notifications'), + ); + + if (filters.some((result) => result.filter.filter_action === 'hide')) { + return; + } + } + dispatchAssociatedRecords(dispatch, [notification]); return notification; diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js index f50f41b0d9..44025bd596 100644 --- a/app/javascript/mastodon/actions/streaming.js +++ b/app/javascript/mastodon/actions/streaming.js @@ -104,7 +104,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti const notificationJSON = JSON.parse(data.payload); dispatch(updateNotifications(notificationJSON, messages, locale)); // TODO: remove this once the groups feature replaces the previous one - if(getState().notificationGroups.groups.length > 0) { + if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) { dispatch(processNewNotificationForGroups(notificationJSON)); } break; diff --git a/app/javascript/mastodon/api/notification_policies.ts b/app/javascript/mastodon/api/notification_policies.ts index 7747397556..3bc8174139 100644 --- a/app/javascript/mastodon/api/notification_policies.ts +++ b/app/javascript/mastodon/api/notification_policies.ts @@ -2,8 +2,8 @@ import { apiRequestGet, apiRequestPut } from 'mastodon/api'; import type { NotificationPolicyJSON } from 'mastodon/api_types/notification_policies'; export const apiGetNotificationPolicy = () => - apiRequestGet('/v2/notifications/policy'); + apiRequestGet('v2/notifications/policy'); export const apiUpdateNotificationsPolicy = ( policy: Partial, -) => apiRequestPut('/v2/notifications/policy', policy); +) => apiRequestPut('v2/notifications/policy', policy); diff --git a/app/javascript/mastodon/api_types/statuses.ts b/app/javascript/mastodon/api_types/statuses.ts index a934faeb7a..2c59645ea7 100644 --- a/app/javascript/mastodon/api_types/statuses.ts +++ b/app/javascript/mastodon/api_types/statuses.ts @@ -58,6 +58,29 @@ export interface ApiPreviewCardJSON { authors: ApiPreviewCardAuthorJSON[]; } +export type FilterContext = + | 'home' + | 'notifications' + | 'public' + | 'thread' + | 'account'; + +export interface ApiFilterJSON { + id: string; + title: string; + context: FilterContext; + expires_at: string; + filter_action: 'warn' | 'hide'; + keywords?: unknown[]; // TODO: FilterKeywordSerializer + statuses?: unknown[]; // TODO: FilterStatusSerializer +} + +export interface ApiFilterResultJSON { + filter: ApiFilterJSON; + keyword_matches: string[]; + status_matches: string[]; +} + export interface ApiStatusJSON { id: string; created_at: string; @@ -80,8 +103,7 @@ export interface ApiStatusJSON { bookmarked?: boolean; pinned?: boolean; - // filtered: FilterResult[] - filtered: unknown; // TODO + filtered?: ApiFilterResultJSON[]; content?: string; text?: string; diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index d2651aeffa..9d2553e7df 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -356,8 +356,16 @@ "home.pending_critical_update.link": "Veure actualitzacions", "home.pending_critical_update.title": "Actualització de seguretat crítica disponible!", "home.show_announcements": "Mostra els anuncis", + "ignore_notifications_modal.disclaimer": "Mastodon no pot informar als usuaris de que heu ignorat notificacions seves.\nIgnorar notificacions no evitarà que se segueixin enviant els missatges.", "ignore_notifications_modal.filter_to_act_users": "Encara podreu acceptar, rebutjar o reportar usuaris", + "ignore_notifications_modal.filter_to_avoid_confusion": "Filtrar ajuda a evitar potencials confusions", "ignore_notifications_modal.filter_to_review_separately": "Podeu revisar separadament notificacions filtrades", + "ignore_notifications_modal.ignore": "Ignora les notificacions", + "ignore_notifications_modal.limited_accounts_title": "Voleu ignorar les notificacions dels comptes moderats?", + "ignore_notifications_modal.new_accounts_title": "Voleu ignorar les notificacions dels comptes nous?", + "ignore_notifications_modal.not_followers_title": "Voleu ignorar les notificacions de qui no us segueix?", + "ignore_notifications_modal.not_following_title": "Voleu ignorar les notificacions de qui no seguiu?", + "ignore_notifications_modal.private_mentions_title": "Voleu ignorar les notificacions de mencions privades no sol·licitades?", "interaction_modal.description.favourite": "Amb un compte a Mastodon pots afavorir aquest tut perquè l'autor sàpiga que t'ha agradat i desar-lo per a més endavant.", "interaction_modal.description.follow": "Amb un compte a Mastodon, pots seguir a {name} per a rebre els seus tuts en la teva línia de temps d'Inici.", "interaction_modal.description.reblog": "Amb un compte a Mastodon, pots impulsar aquest tut per a compartir-lo amb els teus seguidors.", @@ -514,6 +522,7 @@ "notification_requests.confirm_accept_all.button": "Accepta-ho tot", "notification_requests.confirm_accept_all.message": "Esteu a punt d'acceptar {count, plural, one {una petició de notificació} other {# peticions de notificació}}. N'esteu segurs de continuar?", "notification_requests.confirm_accept_all.title": "Accepteu peticions de notificació?", + "notification_requests.confirm_dismiss_all.button": "Descarta-les totes", "notification_requests.dismiss": "Ignora", "notification_requests.explainer_for_limited_account": "S'han filtrat les notificacions d'aquest compte perquè un moderador l'ha limitat.", "notification_requests.explainer_for_limited_remote_account": "S'han filtrat les notificacions d'aquest compte perquè un moderador ha limitat el compte o el seu servidor.", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index b55bb890e6..288575286b 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -11,6 +11,7 @@ "about.not_available": "Эта информация не указана на данном сервере.", "about.powered_by": "Децентрализованная социальная сеть на базе {mastodon}", "about.rules": "Правила сервера", + "account.account_note_header": "Личная заметка", "account.add_or_remove_from_list": "Управление списками", "account.badges.bot": "Бот", "account.badges.group": "Группа", @@ -167,19 +168,25 @@ "confirmations.block.confirm": "Заблокировать", "confirmations.delete.confirm": "Удалить", "confirmations.delete.message": "Вы уверены, что хотите удалить этот пост?", + "confirmations.delete.title": "Удалить пост?", "confirmations.delete_list.confirm": "Удалить", "confirmations.delete_list.message": "Вы действительно хотите навсегда удалить этот список?", + "confirmations.delete_list.title": "Удалить список?", "confirmations.discard_edit_media.confirm": "Отменить", "confirmations.discard_edit_media.message": "У вас есть несохранённые изменения описания мультимедиа или предпросмотра, отменить их?", "confirmations.edit.confirm": "Редактировать", "confirmations.edit.message": "В данный момент, редактирование перезапишет составляемое вами сообщение. Вы уверены, что хотите продолжить?", + "confirmations.edit.title": "Переписать сообщение?", "confirmations.logout.confirm": "Выйти", "confirmations.logout.message": "Вы уверены, что хотите выйти?", + "confirmations.logout.title": "Выйти?", "confirmations.mute.confirm": "Игнорировать", "confirmations.redraft.confirm": "Удалить и исправить", "confirmations.redraft.message": "Вы уверены, что хотите удалить и переписать этот пост? Отметки «избранного», продвижения и ответы к оригинальному посту будут удалены.", + "confirmations.redraft.title": "Удалим и исправим пост?", "confirmations.reply.confirm": "Ответить", "confirmations.reply.message": "При ответе, текст набираемого поста будет очищен. Продолжить?", + "confirmations.reply.title": "Перепишем пост?", "confirmations.unfollow.confirm": "Отписаться", "confirmations.unfollow.message": "Вы уверены, что хотите отписаться от {name}?", "conversation.delete": "Удалить беседу", @@ -484,13 +491,16 @@ "notification.update": "{name} изменил(а) пост", "notification_requests.accept": "Принять", "notification_requests.dismiss": "Отклонить", + "notification_requests.maximize": "Развернуть", "notification_requests.notifications_from": "Уведомления от {name}", "notification_requests.title": "Отфильтрованные уведомления", "notifications.clear": "Очистить уведомления", "notifications.clear_confirmation": "Вы уверены, что хотите очистить все уведомления?", + "notifications.clear_title": "Сбросить уведомления?", "notifications.column_settings.admin.report": "Новые жалобы:", "notifications.column_settings.admin.sign_up": "Новые регистрации:", "notifications.column_settings.alert": "Уведомления на рабочем столе", + "notifications.column_settings.beta.category": "Экспериментальные функции", "notifications.column_settings.favourite": "Избранные:", "notifications.column_settings.filter_bar.advanced": "Отображать все категории", "notifications.column_settings.filter_bar.category": "Панель сортировки", @@ -519,6 +529,7 @@ "notifications.permission_denied": "Уведомления на рабочем столе недоступны, так как вы запретили их отправку в браузере. Проверьте настройки для сайта, чтобы включить их обратно.", "notifications.permission_denied_alert": "Уведомления на рабочем столе недоступны, так как вы ранее отклонили запрос на их отправку.", "notifications.permission_required": "Чтобы включить уведомления на рабочем столе, необходимо разрешить их в браузере.", + "notifications.policy.drop": "Игнорируем", "notifications.policy.filter_new_accounts.hint": "Создано в течение последних {days, plural, one {один день} few {# дней} many {# дней} other {# дня}}", "notifications.policy.filter_new_accounts_title": "Новые учётные записи", "notifications.policy.filter_not_followers_title": "Люди, не подписанные на вас", @@ -652,8 +663,10 @@ "report.unfollow_explanation": "Вы подписаны на этого пользователя. Чтобы не видеть его/её посты в своей домашней ленте, отпишитесь от него/неё.", "report_notification.attached_statuses": "{count, plural, one {{count} сообщение} few {{count} сообщения} many {{count} сообщений} other {{count} сообщений}} вложено", "report_notification.categories.legal": "Правовая информация", + "report_notification.categories.legal_sentence": "срамной контент", "report_notification.categories.other": "Прочее", "report_notification.categories.spam": "Спам", + "report_notification.categories.spam_sentence": "спам", "report_notification.categories.violation": "Нарушение правил", "report_notification.open": "Открыть жалобу", "search.no_recent_searches": "Недавние запросы отсутствуют", diff --git a/app/javascript/mastodon/reducers/notification_groups.ts b/app/javascript/mastodon/reducers/notification_groups.ts index 871f50364b..0d3f34d2fb 100644 --- a/app/javascript/mastodon/reducers/notification_groups.ts +++ b/app/javascript/mastodon/reducers/notification_groups.ts @@ -387,12 +387,14 @@ export const notificationGroupsReducer = createReducer( }) .addCase(processNewNotificationForGroups.fulfilled, (state, action) => { const notification = action.payload; - processNewNotification( - usePendingItems ? state.pendingGroups : state.groups, - notification, - ); - updateLastReadId(state); - trimNotifications(state); + if (notification) { + processNewNotification( + usePendingItems ? state.pendingGroups : state.groups, + notification, + ); + updateLastReadId(state); + trimNotifications(state); + } }) .addCase(disconnectTimeline, (state, action) => { if (action.payload.timeline === 'home') { diff --git a/app/javascript/material-icons/400-24px/feedback-fill.svg b/app/javascript/material-icons/400-24px/feedback-fill.svg new file mode 100644 index 0000000000..7edf5667b0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/feedback-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/feedback.svg b/app/javascript/material-icons/400-24px/feedback.svg new file mode 100644 index 0000000000..b001b512c5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/feedback.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 89d3caeab5..55eb88dae1 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -52,10 +52,6 @@ html { color: darken($action-button-color, 25%); } -.account__header__bar .avatar .account__avatar { - border-color: $white; -} - .getting-started__footer a { color: $ui-secondary-color; text-decoration: underline; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 052b7cc384..9061026bbd 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -7970,7 +7970,8 @@ noscript { .account__avatar { background: var(--background-color); - border: 2px solid var(--background-border-color); + border: 1px solid var(--background-border-color); + border-radius: 4px; } } } diff --git a/app/javascript/styles/mastodon/reset.scss b/app/javascript/styles/mastodon/reset.scss index 903b6c804f..f54ed5bc79 100644 --- a/app/javascript/styles/mastodon/reset.scss +++ b/app/javascript/styles/mastodon/reset.scss @@ -56,3 +56,40 @@ table { html { scrollbar-color: lighten($ui-base-color, 4%) rgba($base-overlay-background, 0.1); } + +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +::-webkit-scrollbar-thumb { + background: lighten($ui-base-color, 4%); + border: 0px none $base-border-color; + border-radius: 50px; +} + +::-webkit-scrollbar-thumb:hover { + background: lighten($ui-base-color, 6%); +} + +::-webkit-scrollbar-thumb:active { + background: lighten($ui-base-color, 4%); +} + +::-webkit-scrollbar-track { + border: 0px none $base-border-color; + border-radius: 0; + background: rgba($base-overlay-background, 0.1); +} + +::-webkit-scrollbar-track:hover { + background: $ui-base-color; +} + +::-webkit-scrollbar-track:active { + background: $ui-base-color; +} + +::-webkit-scrollbar-corner { + background: transparent; +} diff --git a/config/initializers/3_omniauth.rb b/config/initializers/3_omniauth.rb index aa8ba1a056..0f8378ee14 100644 --- a/config/initializers/3_omniauth.rb +++ b/config/initializers/3_omniauth.rb @@ -84,6 +84,7 @@ Devise.setup do |config| oidc_options[:response_mode] = ENV['OIDC_RESPONSE_MODE'] if ENV['OIDC_RESPONSE_MODE'] # OPTIONAL (default: query) oidc_options[:display] = ENV['OIDC_DISPLAY'] if ENV['OIDC_DISPLAY'] # OPTIONAL (default: page) oidc_options[:prompt] = ENV['OIDC_PROMPT'] if ENV['OIDC_PROMPT'] # OPTIONAL + oidc_options[:pkce] = ENV['OIDC_USE_PKCE'] == 'true' if ENV['OIDC_USE_PKCE'] # OPTIONAL (default: false) oidc_options[:send_nonce] = ENV['OIDC_SEND_NONCE'] == 'true' if ENV['OIDC_SEND_NONCE'] # OPTIONAL (default: true) oidc_options[:send_scope_to_token_endpoint] = ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] == 'true' if ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] # OPTIONAL (default: true) oidc_options[:post_logout_redirect_uri] = ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] if ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] # OPTIONAL diff --git a/config/locales/devise.ru.yml b/config/locales/devise.ru.yml index 9dd418f2cd..9e7ace6433 100644 --- a/config/locales/devise.ru.yml +++ b/config/locales/devise.ru.yml @@ -6,12 +6,13 @@ ru: send_instructions: Вы получите e-mail с инструкцией по подтверждению вашего адреса e-mail в течение нескольких минут. send_paranoid_instructions: Если Ваш адрес e-mail есть в нашей базе данных, вы получите e-mail с инструкцией по подтверждению вашего адреса в течение нескольких минут. failure: - already_authenticated: Вы уже авторизованы. + already_authenticated: Вы уже вошли. inactive: Ваша учётная запись ещё не активирована. invalid: Неверно введены %{authentication_keys} или пароль. last_attempt: У Вас есть последняя попытка, после чего вход будет заблокирован. locked: Ваша учётная запись заблокирована. not_found_in_database: Неверно введены %{authentication_keys} или пароль. + omniauth_user_creation_failure: Ошибка создания учетной записи с этим идентификатором. pending: Ваша заявка на вступление всё ещё рассматривается. timeout: Ваша сессия истекла. Пожалуйста, войдите снова, чтобы продолжить. unauthenticated: Вам необходимо войти или зарегистрироваться. diff --git a/config/locales/doorkeeper.ru.yml b/config/locales/doorkeeper.ru.yml index ce8392cb11..12b7e7e87e 100644 --- a/config/locales/doorkeeper.ru.yml +++ b/config/locales/doorkeeper.ru.yml @@ -15,7 +15,7 @@ ru: fragment_present: не может содержать фрагмент. invalid_uri: должен быть правильным URI. relative_uri: должен быть абсолютным URI. - secured_uri: должен быть HTTPS/SSL URI. + secured_uri: нужен HTTPS/SSL URI. doorkeeper: applications: buttons: @@ -83,6 +83,7 @@ ru: access_denied: Владелец ресурса или сервер авторизации ответил отказом на Ваш запрос. credential_flow_not_configured: Поток с предоставлением клиенту пароля завершился неудачей, поскольку параметр Doorkeeper.configure.resource_owner_from_credentials не был сконфигурирован. invalid_client: Клиентская аутентификация завершилась неудачей (неизвестный клиент, не включена клиентская аутентификация, или метод аутентификации не поддерживается. + invalid_code_challenge_method: Метод проверки кода должен быть S256, простой не годится. invalid_grant: Предоставленный доступ некорректен, истек, отозван, не совпадает с URI перенаправления, использованным в запросе авторизации, или был выпущен для другого клиента. invalid_redirect_uri: Включенный URI перенаправления некорректен. invalid_request: @@ -135,6 +136,7 @@ ru: media: Медиафайлы mutes: Игнорирует notifications: Уведомления + profile: Ваш профиль Mastodon push: Push-уведомления reports: Обращения search: Поиск @@ -165,6 +167,7 @@ ru: admin:write:reports: производить модерацию жалоб crypto: использ. сквозное шифрование follow: управлять подписками и списком блокировок + profile: данные вашего профиля только для чтения push: получать push-уведомления read: просматривать данные вашей учётной записи read:accounts: видеть информацию об учётных записях diff --git a/config/locales/el.yml b/config/locales/el.yml index bd90d8f7ab..6b1d8bc0e5 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -58,6 +58,7 @@ el: demote: Υποβιβασμός destroyed_msg: Τα δεδομένα του/της %{username} εκκρεμούν για άμεση διαγραφή disable: Πάγωμα + disable_sign_in_token_auth: Απενεργοποίηση επαλήθευσης διακριτικού email disable_two_factor_authentication: Απενεργοποίηση 2FA disabled: Παγωμένος display_name: Εμφανιζόμενο όνομα @@ -66,6 +67,7 @@ el: email: Email email_status: Κατάσταση email enable: Ξεπάγωμα + enable_sign_in_token_auth: Ενεργοποίηση ελέγχου ταυτότητας διακριτικού e-mail enabled: Ενεργοποιημένο enabled_msg: Επιτυχές ξεπάγωμα λογαριασμού του/της %{username} followers: Ακόλουθοι @@ -130,6 +132,7 @@ el: resubscribe: Επανεγγραφή role: Ρόλος search: Αναζήτηση + search_same_email_domain: Άλλοι χρήστες με τον ίδιο τομέα email search_same_ip: Υπόλοιποι χρήστες με την ίδια διεύθυνση IP security: Ασφάλεια security_measures: @@ -170,21 +173,26 @@ el: approve_appeal: Έγκριση Έφεσης approve_user: Έγκριση Χρήστη assigned_to_self_report: Ανάθεση Αναφοράς + change_email_user: Αλλαγή email για Χρήστη change_role_user: Αλλαγή του ρόλου του χρήστη confirm_user: Επιβεβαίωση Χρήστη create_account_warning: Δημιουργία Προειδοποίησης create_announcement: Δημιουργία Ανακοίνωσης + create_canonical_email_block: Δημιουργία Αποκλεισμού Email create_custom_emoji: Δημιουργία Προσαρμοσμένου Emoji create_domain_allow: Δημιουργία Αποδεκτού Τομέα create_domain_block: Δημιουργία Αποκλεισμού Τομέα + create_email_domain_block: Δημιουργία Αποκλεισμού Τομέα Email create_ip_block: Δημιουργία κανόνα IP create_unavailable_domain: Δημιουργία Μη Διαθέσιμου Τομέα create_user_role: Δημιουργία Ρόλου demote_user: Υποβιβασμός Χρήστη destroy_announcement: Διαγραφή Ανακοίνωσης + destroy_canonical_email_block: Διαγραφή Αποκλεισμού Email destroy_custom_emoji: Διαγραφή Προσαρμοσμένου Emoji destroy_domain_allow: Διαγραφή Αποδεκτού Τομέα destroy_domain_block: Διαγραφή Αποκλεισμού Τομέα + destroy_email_domain_block: Διαγραφή Αποκλεισμού Τομέα Email destroy_instance: Εκκαθάριση Τομέα destroy_ip_block: Διαγραφή κανόνα IP destroy_status: Διαγραφή Ανάρτησης @@ -192,8 +200,10 @@ el: destroy_user_role: Καταστροφή Ρόλου disable_2fa_user: Απενεργοποίηση 2FA disable_custom_emoji: Απενεργοποίηση Προσαρμοσμένων Emoji + disable_sign_in_token_auth_user: Απενεργοποίηση Ελέγχου Ταυτότητας Διακριτικού Email για Χρήστη disable_user: Απενεργοποίηση Χρήστη enable_custom_emoji: Ενεργοποίηση Προσαρμοσμένων Emoji + enable_sign_in_token_auth_user: Ενεργοποίηση Ελέγχου Ταυτότητας Διακριτικού Email για Χρήστη enable_user: Ενεργοποίηση Χρήστη memorialize_account: Μετατροπή Λογαριασμού σε Εις Μνήμην promote_user: Προαγωγή Χρήστη @@ -223,12 +233,16 @@ el: approve_appeal_html: Ο/Η %{name} ενέκρινε την ένσταση της απόφασης των συντονιστών από %{target} approve_user_html: ο/η %{name} ενέκρινε την εγγραφή του %{target} assigned_to_self_report_html: Ο/Η %{name} ανάθεσε την αναφορά %{target} στον εαυτό του/της + change_email_user_html: Ο χρήστης %{name} άλλαξε τη διεύθυνση email του χρήστη %{target} change_role_user_html: Ο/Η %{name} άλλαξε ρόλο του/της %{target} + confirm_user_html: Ο χρήστης %{name} επιβεβαίωσε τη διεύθυνση email του χρήστη %{target} create_account_warning_html: Ο/Η %{name} έστειλε προειδοποίηση προς %{target} create_announcement_html: Ο/Η %{name} δημιούργησε νέα ανακοίνωση %{target} + create_canonical_email_block_html: Ο χρήστης %{name} απέκλεισε email με το hash %{target} create_custom_emoji_html: Ο/Η %{name} ανέβασε νέο emoji %{target} create_domain_allow_html: Ο/Η %{name} επέτρεψε την συναλλαγή με τον τομέα %{target} create_domain_block_html: Ο/Η %{name} απέκλεισε τον τομέα %{target} + create_email_domain_block_html: Ο χρήστης %{name} απέκλεισε τον τομέα email %{target} create_ip_block_html: Ο/Η %{name} δημιούργησε κανόνα για την IP %{target} create_unavailable_domain_html: Ο/Η %{name} σταμάτησε να τροφοδοτεί τον τομέα %{target} create_user_role_html: Ο/Η %{name} δημιούργησε ρόλο %{target} diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 324a22500d..9a92879cc5 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -175,6 +175,7 @@ ru: approve_appeal: Одобрить обжалование approve_user: Утвердить assigned_to_self_report: Присвоение жалоб + change_email_user: Сменить e-mail для пользователя change_role_user: Изменить роль пользователя confirm_user: Подтверждение пользователей create_account_warning: Выдача предупреждения @@ -221,6 +222,7 @@ ru: update_custom_emoji: Обновление эмодзи update_domain_block: Изменение блокировки домена update_ip_block: Обновить правило для IP-адреса + update_report: Обновить рапорт update_status: Изменение постов update_user_role: Обновить роль actions: @@ -436,6 +438,7 @@ ru: resolve: Проверить домен not_permitted: Не разрешено resolved_through_html: Разрешено через %{domain} + title: Заблокированные e-mail домены export_domain_allows: new: title: Импорт домена разрешён @@ -714,6 +717,7 @@ ru: manage_taxonomies: Управление трендами manage_taxonomies_description: Позволяет пользователям модерировать список популярного контента и менять настройки хэштегов manage_user_access: Управление правами пользователей + manage_user_access_description: Разрешает пользователям отключать двухэтапную аутентификацию другим пользователям, менять их e-mail и сбрасывать их пароль manage_users: Управление пользователями manage_users_description: Разрешает пользователям просматривать информацию о других пользователях и применять против них модерацию manage_webhooks: Управление веб-хуками @@ -871,6 +875,8 @@ ru: action: Нажмите сюда, чтобы узнать подробности message_html: "Ваше хранилище объектов неправильно настроено. Безопасность ваших пользователей находится под угрозой" tags: + moderation: + title: Статус review: Состояние проверки updated_msg: Настройки хэштега обновлены title: Администрирование diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml index c2effdcb88..e7a29fdad1 100644 --- a/config/locales/simple_form.ru.yml +++ b/config/locales/simple_form.ru.yml @@ -39,12 +39,14 @@ ru: text: Вы можете обжаловать замечание только один раз defaults: autofollow: Люди, пришедшие по этому приглашению, автоматически будут подписаны на вас. + avatar: WEBP PNG, GIF и JPG. Не более %{size}. Будет уменьшен до %{dimensions}px bot: Отметьте, если с этой учётной записи выполняются автоматизированные действия и она может не просматриваться владельцем. context: Один или несколько контекстов, к которым должны быть применены фильтры current_password: В целях безопасности введите пароль текущей учётной записи current_username: Для подтверждения, пожалуйста, введите имя пользователя текущей учётной записи digest: Если вы долго не заглядывали, отправим вам дайджест событий, которые происходили в период вашего отсутствия. email: Вам будет отправлено электронное письмо с подтверждением. + header: WEBP PNG, GIF и JPG. Не более %{size}. Будет уменьшен до %{dimensions}px inbox_url: Копировать URL с главной страницы ретранслятора, который вы хотите использовать irreversible: Отфильтрованные посты будут утеряны навсегда, даже если в будущем фильтр будет убран locale: Язык интерфейса, e-mail писем и push-уведомлений @@ -75,6 +77,7 @@ ru: warn: Скрыть отфильтрованный контент за предупреждением с указанием названия фильтра form_admin_settings: activity_api_enabled: Подсчёт количества локальных постов, активных пользователей и новых регистраций на еженедельной основе + backups_retention_period: Пользователи могут создавать архивы своих постов, чтобы потом их забрать. Если задать положительное значение, эти архивы автоматически удалятся с вашего хранилища через указанное число дней. bootstrap_timeline_accounts: Эти аккаунты будут рекомендованы для подписки новым пользователям. closed_registrations_message: Отображается, когда регистрация закрыта custom_css: Вы можете применять пользовательские стили в веб-версии Mastodon. @@ -239,6 +242,7 @@ ru: bootstrap_timeline_accounts: Всегда рекомендовать эти учетные записи новым пользователям closed_registrations_message: Сообщение, когда регистрация недоступна custom_css: Пользовательский CSS + favicon: Favicon mascot: Пользовательский маскот (устаревшее) media_cache_retention_period: Период хранения кэша медиафайлов peers_api_enabled: Публикация списка обнаруженных узлов в API @@ -294,6 +298,7 @@ ru: patch: Уведомлять об обновлении исправлений trending_tag: Новый тренд требует рассмотрения rule: + hint: Больше информации text: Правило settings: indexable: Включить страницу профиля в поисковые системы diff --git a/config/navigation.rb b/config/navigation.rb index 21755cb7a1..f5269d18ce 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -53,7 +53,8 @@ SimpleNavigation::Configuration.run do |navigation| n.item :moderation, safe_join([material_symbol('gavel'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s| s.item :reports, safe_join([material_symbol('flag'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports|admin/report_notes}, if: -> { current_user.can?(:manage_reports) } - s.item :accounts, safe_join([material_symbol('groups'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) } + s.item :appeals, safe_join([material_symbol('feedback'), t('admin.disputes.appeals.title')]), admin_disputes_appeals_path, highlights_on: %r{/admin/disputes/appeals}, if: -> { current_user.can?(:manage_appeals) } + s.item :accounts, safe_join([material_symbol('groups'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/users}, if: -> { current_user.can?(:manage_users) } s.item :tags, safe_join([material_symbol('tag'), t('admin.tags.title')]), admin_tags_path, highlights_on: %r{/admin/tags}, if: -> { current_user.can?(:manage_taxonomies) } s.item :invites, safe_join([material_symbol('person_add'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } s.item :instances, safe_join([material_symbol('cloud'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) } diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index 5bc6da6ebe..e6ba5ab250 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -75,7 +75,7 @@ class Sanitize end MASTODON_STRICT = freeze_config( - elements: %w(p br span a abbr del pre blockquote code b strong u sub sup i em h1 h2 h3 h4 h5 ul ol li ruby rt rp), + elements: %w(p br span a abbr del s pre blockquote code b strong u sub sup i em h1 h2 h3 h4 h5 ul ol li ruby rt rp), attributes: { 'a' => %w(href rel class title translate),