mirror of
https://github.com/funamitech/mastodon
synced 2024-11-30 15:58:28 +09:00
Merge branch 'main' of https://github.com/glitch-soc/mastodon
This commit is contained in:
commit
d45671066c
6
.github/workflows/build-push-pr.yml
vendored
6
.github/workflows/build-push-pr.yml
vendored
@ -21,9 +21,11 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- id: version_vars
|
||||
run: |
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
echo mastodon_short_sha=$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
|
||||
short_sha: ${{ steps.version_vars.outputs.mastodon_short_sha }}
|
||||
|
||||
build-image:
|
||||
needs: compute-suffix
|
||||
@ -39,6 +41,7 @@ jobs:
|
||||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
secrets: inherit
|
||||
|
||||
build-image-streaming:
|
||||
@ -55,4 +58,5 @@ jobs:
|
||||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
secrets: inherit
|
||||
|
4
.github/workflows/build-security.yml
vendored
4
.github/workflows/build-security.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
labels: |
|
||||
org.opencontainers.image.description=Nightly build image used for testing purposes
|
||||
flavor: |
|
||||
latest=true
|
||||
latest=auto
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=nightly
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
labels: |
|
||||
org.opencontainers.image.description=Nightly build image used for testing purposes
|
||||
flavor: |
|
||||
latest=true
|
||||
latest=auto
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=nightly
|
||||
|
26
CHANGELOG.md
26
CHANGELOG.md
@ -2,7 +2,7 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [4.3.0] - UNRELEASED
|
||||
## [4.3.0] - 2024-10-08
|
||||
|
||||
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
||||
|
||||
@ -11,12 +11,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- **Add confirmation interstitial instead of silently redirecting logged-out visitors to remote resources** (#27792, #28902, and #30651 by @ClearlyClaire and @Gargron)\
|
||||
This fixes a longstanding open redirect in Mastodon, at the cost of added friction when local links to remote resources are shared.
|
||||
- Fix ReDoS vulnerability on some Ruby versions ([GHSA-jpxp-r43f-rhvx](https://github.com/mastodon/mastodon/security/advisories/GHSA-jpxp-r43f-rhvx))
|
||||
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 by @ClearlyClaire)
|
||||
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 and #32241 by @ClearlyClaire)
|
||||
- Update dependencies
|
||||
|
||||
### Added
|
||||
|
||||
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610, #31929, #32089 and #32085 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
||||
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610, #31929, #32089, #32085, #32243, #32179 and #32254 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
||||
Group notifications of the same type for the same target, so that your notifications no longer get cluttered by boost and favorite notifications as soon as a couple of your posts get traction.\
|
||||
This is done server-side so that clients can efficiently get relevant groups without having to go through numerous pages of individual notifications.\
|
||||
As part of this, the visual design of the entire notifications feature has been revamped.\
|
||||
@ -28,7 +28,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- `GET /api/v2/notifications/:group_key/accounts`: https://docs.joinmastodon.org/methods/grouped_notifications/#get-group-accounts
|
||||
- `POST /api/v2/notifications/:group_key/dimsiss`: https://docs.joinmastodon.org/methods/grouped_notifications/#dismiss-group
|
||||
- `GET /api/v2/notifications/:unread_count`: https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count
|
||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, #31723 and #32062 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, #31723, #32062 and #32281 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
||||
The old “Block notifications from non-followers”, “Block notifications from people you don't follow” and “Block direct messages from people you don't follow” notification settings have been replaced by a new set of settings found directly in the notification column.\
|
||||
You can now separately filter or drop notifications from people you don't follow, people who don't follow you, accounts created within the past 30 days, as well as unsolicited private mentions, and accounts limited by the moderation.\
|
||||
Instead of being outright dropped, notifications that you chose to filter are put in a separate “Filtered notifications” box that you can review separately without it clogging your main notifications.\
|
||||
@ -61,7 +61,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- **Add timeline of public posts about a trending link** (#30381 and #30840 by @Gargron)\
|
||||
You can now see public posts mentioning currently-trending articles from people who have opted into discovery features.\
|
||||
This adds a new REST API endpoint: https://docs.joinmastodon.org/methods/timelines/#link
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, and #31900 by @Gargron and @oneiros)\
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, #31900 and #32188 by @Gargron, @mjankowski and @oneiros)\
|
||||
This adds a mechanism to [highlight the author of news articles](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) shared on Mastodon.\
|
||||
Articles hosted outside the fediverse can indicate a fediverse author with a meta tag:
|
||||
```html
|
||||
@ -150,10 +150,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Add groundwork for annual reports for accounts (#28693 by @Gargron)\
|
||||
This lays the groundwork for a “year-in-review”/“wrapped” style report for local users, but is currently not in use.
|
||||
- Add notification email on invalid second authenticator (#28822 by @ClearlyClaire)
|
||||
- Add date of account deletion in list of accounts in the admin interface (#25640 by @tribela)
|
||||
- Add new emojis from `jdecked/twemoji` 15.0 (#28404 by @TheEssem)
|
||||
- Add configurable error handling in attachment batch deletion (#28184 by @vmstan)\
|
||||
This makes the S3 batch size configurable through the `S3_BATCH_DELETE_LIMIT` environment variable (defaults to 1000), and adds some retry logic, configurable through the `S3_BATCH_DELETE_RETRY` environment variable (defaults to 3).
|
||||
- Add VAPID public key to instance serializer (#28006 by @ThisIsMissEm)
|
||||
- Add support for serving JRD `/.well-known/host-meta.json` in addition to XRD host-meta (#32206 by @c960657)
|
||||
- Add `nodeName` and `nodeDescription` to nodeinfo `metadata` (#28079 by @6543)
|
||||
- Add Thai diacritics and tone marks in `HASHTAG_INVALID_CHARS_RE` (#26576 by @ppnplus)
|
||||
- Add variable delay before link verification of remote account links (#27774 by @ClearlyClaire)
|
||||
@ -168,7 +170,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
|
||||
### Changed
|
||||
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, and #31525 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, #31525, #32153, and #32201 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
This changes all the interface icons from FontAwesome to Material Symbols for a more modern look, consistent with the official Mastodon Android app.\
|
||||
In addition, better care is given to pixel alignment, and icon variants are used to better highlight active/inactive state.
|
||||
- **Change design of compose form in web UI** (#28119, #29059, #29248, #29372, #29384, #29417, #29456, #29406, #29651, #29659, #31889 and #32033 by @ClearlyClaire, @Gargron, @eai04191, @hinaloe, and @ronilaukkarinen)\
|
||||
@ -192,9 +194,9 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
Administrators may need to update their setup accordingly.
|
||||
- Change how content warnings and filters are displayed in web UI (#31365, and #31761 by @Gargron)
|
||||
- Change preview card processing to ignore `undefined` as canonical url (#31882 by @oneiros)
|
||||
- Change embedded posts to use web UI (#31766 and #32135 by @Gargron)
|
||||
- Change embedded posts to use web UI (#31766, #32135 and #32271 by @Gargron)
|
||||
- Change inner borders in media galleries in web UI (#31852 by @Gargron)
|
||||
- Change design of media attachments and profile media tab in web UI (#31807, #32048, and #31967 by @Gargron)
|
||||
- Change design of media attachments and profile media tab in web UI (#31807, #32048, #31967, #32217, #32224 and #32257 by @ClearlyClaire and @Gargron)
|
||||
- Change labels on thread indicators in web UI (#31806 by @Gargron)
|
||||
- Change label of "Data export" menu item in settings interface (#32099 by @c960657)
|
||||
- Change responsive break points on navigation panel in web UI (#32034 by @Gargron)
|
||||
@ -284,9 +286,10 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix error when accepting an appeal for sensitive posts deleted in the meantime (#32037 by @ClearlyClaire)
|
||||
- Fix error when encountering reblog of deleted post in feed rebuild (#32001 by @ClearlyClaire)
|
||||
- Fix Safari browser glitch related to horizontal scrolling (#31960 by @Gargron)
|
||||
- Fix unresolvable mentions sometimes preventing processing incoming posts (#29215 by @tribela and @ClearlyClaire)
|
||||
- Fix too many requests caused by relationship look-ups in web UI (#32042 by @Gargron)
|
||||
- Fix links for reblogs in moderation interface (#31979 by @ClearlyClaire)
|
||||
- Fix the appearance of avatars when they do not load (#31966 by @renchap)
|
||||
- Fix the appearance of avatars when they do not load (#31966 and #32270 by @Gargron and @renchap)
|
||||
- Fix spurious error notifications for aborted requests in web UI (#31952 by @c960657)
|
||||
- Fix HTTP 500 error in `/api/v1/polls/:id/votes` when required `choices` parameter is missing (#25598 by @danielmbrasil)
|
||||
- Fix security context sometimes not being added in LD-Signed activities (#31871 by @ClearlyClaire)
|
||||
@ -309,10 +312,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix “Redirect URI” field not being marked as required in “New application” form (#30311 by @ThisIsMissEm)
|
||||
- Fix right-to-left text in preview cards (#30930 by @ClearlyClaire)
|
||||
- Fix rack attack `match_type` value typo in logging config (#30514 by @mjankowski)
|
||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, #31445 and #32091 by @ClearlyClaire, @valtlai and @vmstan)
|
||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, #31445, #32091, #32147 and #32137 by @ClearlyClaire, @mjankowski, @valtlai and @vmstan)
|
||||
- Fix editing description of media uploads with custom thumbnails (#32221 by @ClearlyClaire)
|
||||
- Fix race condition in `POST /api/v1/push/subscription` (#30166 by @ClearlyClaire)
|
||||
- Fix post deletion not being delayed when those are part of an account warning (#30163 by @ClearlyClaire)
|
||||
- Fix rendering error on `/start` when not logged in (#30023 by @timothyjrogers)
|
||||
- Fix unneeded requests to blocked domains when receiving relayed signed activities from them (#31161 by @ClearlyClaire)
|
||||
- Fix logo pushing header buttons out of view on certain conditions in mobile layout (#29787 by @ClearlyClaire)
|
||||
- Fix notification-related records not being reattributed when merging accounts (#29694 by @ClearlyClaire)
|
||||
- Fix results/query in `api/v1/featured_tags/suggestions` (#29597 by @mjankowski)
|
||||
@ -322,6 +327,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix full date display not respecting the locale 12/24h format (#29448 by @renchap)
|
||||
- Fix filters title and keywords overflow (#29396 by @GeopJr)
|
||||
- Fix incorrect date format in “Follows and followers” (#29390 by @JasonPunyon)
|
||||
- Fix navigation item active highlight for some paths (#32159 by @mjankowski)
|
||||
- Fix “Edit media” modal sizing and layout when space-constrained (#27095 by @ronilaukkarinen)
|
||||
- Fix modal container bounds (#29185 by @nico3333fr)
|
||||
- Fix inefficient HTTP signature parsing using regexps and `StringScanner` (#29133 by @ClearlyClaire)
|
||||
|
@ -615,7 +615,7 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.9)
|
||||
rack (2.2.10)
|
||||
rack-attack (6.7.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-cors (2.0.2)
|
||||
|
11
SECURITY.md
11
SECURITY.md
@ -13,8 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | --------- |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Yes |
|
||||
| < 4.1 | No |
|
||||
| Version | Supported |
|
||||
| ------- | ---------------- |
|
||||
| 4.3.x | Yes |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Until 2025-04-08 |
|
||||
| < 4.1 | No |
|
||||
|
@ -52,7 +52,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController
|
||||
private
|
||||
|
||||
def load_requests
|
||||
requests = NotificationRequest.where(account: current_account).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
requests = NotificationRequest.where(account: current_account).without_suspended.includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
|
@ -35,7 +35,7 @@ class ApplicationController < ActionController::Base
|
||||
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
||||
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
||||
|
||||
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
||||
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
|
||||
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable
|
||||
|
||||
rescue_from Seahorse::Client::NetworkingError do |e|
|
||||
|
@ -20,7 +20,7 @@ module Api::ErrorHandling
|
||||
render json: { error: 'Record not found' }, status: 404
|
||||
end
|
||||
|
||||
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
|
||||
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::UnexpectedResponseError) do
|
||||
render json: { error: 'Remote data could not be fetched' }, status: 503
|
||||
end
|
||||
|
||||
|
@ -80,7 +80,7 @@ module SignatureVerification
|
||||
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature']
|
||||
rescue SignatureVerificationError => e
|
||||
fail_with! e.message
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError => e
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS => e
|
||||
fail_with! "Failed to fetch remote data: #{e.message}"
|
||||
rescue Mastodon::UnexpectedResponseError
|
||||
fail_with! 'Failed to fetch remote data (got unexpected reply from server)'
|
||||
|
@ -13,7 +13,7 @@ class MediaProxyController < ApplicationController
|
||||
rescue_from ActiveRecord::RecordInvalid, with: :not_found
|
||||
rescue_from Mastodon::UnexpectedResponseError, with: :not_found
|
||||
rescue_from Mastodon::NotPermittedError, with: :not_found
|
||||
rescue_from HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, with: :internal_server_error
|
||||
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
|
||||
|
||||
def show
|
||||
with_redis_lock("media_download:#{params[:id]}") do
|
||||
|
@ -193,6 +193,7 @@ module LanguagesHelper
|
||||
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||
csb: ['Kashubian', 'Kaszëbsczi'].freeze,
|
||||
gsw: ['Swiss German', 'Schwiizertütsch'].freeze,
|
||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||
ldn: ['Láadan', 'Láadan'].freeze,
|
||||
|
@ -13,7 +13,7 @@ export interface ApiAccountRoleJSON {
|
||||
}
|
||||
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiAccountJSON {
|
||||
export interface BaseApiAccountJSON {
|
||||
acct: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
@ -45,3 +45,12 @@ export interface ApiAccountJSON {
|
||||
memorial?: boolean;
|
||||
hide_collections: boolean;
|
||||
}
|
||||
|
||||
// See app/serializers/rest/muted_account_serializer.rb
|
||||
export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
|
||||
mute_expires_at?: string | null;
|
||||
}
|
||||
|
||||
// For now, we have the same type representing both `Account` and `MutedAccount`
|
||||
// objects, but we should refactor this in the future.
|
||||
export type ApiAccountJSON = ApiMutedAccountJSON;
|
||||
|
@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||
|
||||
const handleLeftNav = useCallback(() => {
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
import type { IconProp } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import Status from 'flavours/glitch/containers/status_container';
|
||||
import { getStatusHidden } from 'flavours/glitch/selectors/filters';
|
||||
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||
|
||||
import { DisplayedName } from './displayed_name';
|
||||
@ -51,6 +52,12 @@ export const NotificationWithStatus: React.FC<{
|
||||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||
);
|
||||
|
||||
const isFiltered = useAppSelector(
|
||||
(state) =>
|
||||
statusId &&
|
||||
getStatusHidden(state, { id: statusId, contextType: 'notifications' }),
|
||||
);
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
@ -77,7 +84,7 @@ export const NotificationWithStatus: React.FC<{
|
||||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
if (!statusId) return null;
|
||||
if (!statusId || isFiltered) return null;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
|
@ -15,6 +15,7 @@ import { Icon } from 'flavours/glitch/components/icon';
|
||||
import {
|
||||
selectSettingsNotificationsQuickFilterActive,
|
||||
selectSettingsNotificationsQuickFilterAdvanced,
|
||||
selectSettingsNotificationsQuickFilterShow,
|
||||
} from 'flavours/glitch/selectors/settings';
|
||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
@ -70,6 +71,11 @@ export const FilterBar: React.FC = () => {
|
||||
const advancedMode = useAppSelector(
|
||||
selectSettingsNotificationsQuickFilterAdvanced,
|
||||
);
|
||||
const useFilterBar = useAppSelector(
|
||||
selectSettingsNotificationsQuickFilterShow,
|
||||
);
|
||||
|
||||
if (!useFilterBar) return null;
|
||||
|
||||
if (advancedMode)
|
||||
return (
|
||||
|
@ -21,6 +21,7 @@ import { Permalink } from 'flavours/glitch/components/permalink';
|
||||
import { PictureInPicture } from 'flavours/glitch/features/picture_in_picture';
|
||||
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
||||
import { layoutFromWindow } from 'flavours/glitch/is_mobile';
|
||||
import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
|
||||
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
|
||||
@ -90,7 +91,7 @@ const mapStateToProps = state => ({
|
||||
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
|
||||
isWide: state.getIn(['local_settings', 'stretch']),
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
unreadNotifications: selectUnreadNotificationGroupsCount(state),
|
||||
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
|
||||
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
|
||||
moved: state.getIn(['accounts', me, 'moved']) && state.getIn(['accounts', state.getIn(['accounts', me, 'moved'])]),
|
||||
|
@ -95,6 +95,9 @@ export const accountDefaultValues: AccountShape = {
|
||||
limited: false,
|
||||
moved: null,
|
||||
hide_collections: false,
|
||||
// This comes from `ApiMutedAccountJSON`, but we should eventually
|
||||
// store that in a different object.
|
||||
mute_expires_at: null,
|
||||
};
|
||||
|
||||
const AccountFactory = ImmutableRecord<AccountShape>(accountDefaultValues);
|
||||
|
@ -559,7 +559,10 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>(
|
||||
compareId(state.lastReadId, mostRecentGroup.page_max_id) < 0
|
||||
)
|
||||
state.lastReadId = mostRecentGroup.page_max_id;
|
||||
commitLastReadId(state);
|
||||
|
||||
// We don't call `commitLastReadId`, because that is conditional
|
||||
// and we want to unconditionally update the state instead.
|
||||
state.readMarkerId = state.lastReadId;
|
||||
})
|
||||
.addCase(fetchMarkers.fulfilled, (state, action) => {
|
||||
if (
|
||||
|
50
app/javascript/flavours/glitch/selectors/filters.ts
Normal file
50
app/javascript/flavours/glitch/selectors/filters.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
import type { RootState } from 'flavours/glitch/store';
|
||||
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
||||
|
||||
// TODO: move to `app/javascript/flavours/glitch/models` and use more globally
|
||||
type Filter = Immutable.Map<string, unknown>;
|
||||
|
||||
// TODO: move to `app/javascript/flavours/glitch/models` and use more globally
|
||||
type FilterResult = Immutable.Map<string, unknown>;
|
||||
|
||||
export const getFilters = createSelector(
|
||||
[
|
||||
(state: RootState) => state.filters as Immutable.Map<string, Filter>,
|
||||
(_, { contextType }: { contextType: string }) => contextType,
|
||||
],
|
||||
(filters, contextType) => {
|
||||
if (!contextType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const serverSideType = toServerSideType(contextType);
|
||||
|
||||
return filters.filter((filter) => {
|
||||
const context = filter.get('context') as Immutable.List<string>;
|
||||
const expiration = filter.get('expires_at') as Date | null;
|
||||
return (
|
||||
context.includes(serverSideType) &&
|
||||
(expiration === null || expiration > now)
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export const getStatusHidden = (
|
||||
state: RootState,
|
||||
{ id, contextType }: { id: string; contextType: string },
|
||||
) => {
|
||||
const filters = getFilters(state, { contextType });
|
||||
if (filters === null) return false;
|
||||
|
||||
const filtered = state.statuses.getIn([id, 'filtered']) as
|
||||
| Immutable.List<FilterResult>
|
||||
| undefined;
|
||||
return filtered?.some(
|
||||
(result) =>
|
||||
filters.getIn([result.get('filter'), 'filter_action']) === 'hide',
|
||||
);
|
||||
};
|
@ -1,23 +1,12 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
||||
|
||||
import { me } from '../initial_state';
|
||||
|
||||
import { getFilters } from './filters';
|
||||
|
||||
export { makeGetAccount } from "./accounts";
|
||||
|
||||
const getFilters = createSelector([state => state.get('filters'), (_, { contextType }) => contextType], (filters, contextType) => {
|
||||
if (!contextType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const serverSideType = toServerSideType(contextType);
|
||||
|
||||
return filters.filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || filter.get('expires_at') > now));
|
||||
});
|
||||
|
||||
export const makeGetStatus = () => {
|
||||
return createSelector(
|
||||
[
|
||||
|
@ -1050,6 +1050,12 @@ a.name-tag,
|
||||
color: var(--user-role-accent);
|
||||
}
|
||||
|
||||
.applications-list {
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.announcements-list,
|
||||
.filters-list {
|
||||
border: 1px solid var(--background-border-color);
|
||||
|
@ -8542,79 +8542,23 @@ noscript {
|
||||
background: rgba($base-overlay-background, 0.5);
|
||||
}
|
||||
|
||||
.list-adder,
|
||||
.list-editor {
|
||||
background: $ui-base-color;
|
||||
backdrop-filter: var(--background-filter);
|
||||
background: var(--modal-background-color);
|
||||
border: 1px solid var(--modal-border-color);
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
width: 380px;
|
||||
overflow: hidden;
|
||||
|
||||
@media screen and (width <= 420px) {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding: 15px 0;
|
||||
background: lighten($ui-base-color, 13%);
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
height: 50vh;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
&.backdrop {
|
||||
width: calc(100% - 60px);
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.account__display-name {
|
||||
&:hover strong {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.list-adder {
|
||||
background: $ui-base-color;
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
width: 380px;
|
||||
overflow: hidden;
|
||||
|
||||
@media screen and (width <= 420px) {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
&__account {
|
||||
background: lighten($ui-base-color, 13%);
|
||||
}
|
||||
|
||||
&__lists {
|
||||
background: lighten($ui-base-color, 13%);
|
||||
height: 50vh;
|
||||
border-radius: 0 0 8px 8px;
|
||||
overflow-y: auto;
|
||||
@ -8635,6 +8579,52 @@ noscript {
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-editor {
|
||||
h4 {
|
||||
padding: 15px 0;
|
||||
background: lighten($ui-base-color, 13%);
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
height: 50vh;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
&.backdrop {
|
||||
width: calc(100% - 60px);
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
background: unset;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.account__display-name {
|
||||
&:hover strong {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ export interface ApiAccountRoleJSON {
|
||||
}
|
||||
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiAccountJSON {
|
||||
export interface BaseApiAccountJSON {
|
||||
acct: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
@ -45,3 +45,12 @@ export interface ApiAccountJSON {
|
||||
memorial?: boolean;
|
||||
hide_collections: boolean;
|
||||
}
|
||||
|
||||
// See app/serializers/rest/muted_account_serializer.rb
|
||||
export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
|
||||
mute_expires_at?: string | null;
|
||||
}
|
||||
|
||||
// For now, we have the same type representing both `Account` and `MutedAccount`
|
||||
// objects, but we should refactor this in the future.
|
||||
export type ApiAccountJSON = ApiMutedAccountJSON;
|
||||
|
@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||
|
||||
const handleLeftNav = useCallback(() => {
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import Status from 'mastodon/containers/status_container';
|
||||
import { getStatusHidden } from 'mastodon/selectors/filters';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { DisplayedName } from './displayed_name';
|
||||
@ -48,6 +49,12 @@ export const NotificationWithStatus: React.FC<{
|
||||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||
);
|
||||
|
||||
const isFiltered = useAppSelector(
|
||||
(state) =>
|
||||
statusId &&
|
||||
getStatusHidden(state, { id: statusId, contextType: 'notifications' }),
|
||||
);
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
@ -73,7 +80,7 @@ export const NotificationWithStatus: React.FC<{
|
||||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
if (!statusId) return null;
|
||||
if (!statusId || isFiltered) return null;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
|
@ -85,6 +85,7 @@
|
||||
"alert.rate_limited.title": "Ліміт перавышаны",
|
||||
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
||||
"alert.unexpected.title": "Вой!",
|
||||
"alt_text_badge.title": "Альтернативный текст",
|
||||
"announcement.announcement": "Аб'ява",
|
||||
"attachments_list.unprocessed": "(неапрацаваны)",
|
||||
"audio.hide": "Схаваць аўдыя",
|
||||
|
@ -62,7 +62,7 @@
|
||||
"account.requested_follow": "{name} möchte dir folgen",
|
||||
"account.share": "Profil von @{name} teilen",
|
||||
"account.show_reblogs": "Geteilte Beiträge von @{name} anzeigen",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} posts}}",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}",
|
||||
"account.unblock": "Blockierung von @{name} aufheben",
|
||||
"account.unblock_domain": "Blockierung von {domain} aufheben",
|
||||
"account.unblock_short": "Blockierung aufheben",
|
||||
|
@ -95,6 +95,9 @@ export const accountDefaultValues: AccountShape = {
|
||||
limited: false,
|
||||
moved: null,
|
||||
hide_collections: false,
|
||||
// This comes from `ApiMutedAccountJSON`, but we should eventually
|
||||
// store that in a different object.
|
||||
mute_expires_at: null,
|
||||
};
|
||||
|
||||
const AccountFactory = ImmutableRecord<AccountShape>(accountDefaultValues);
|
||||
|
@ -559,7 +559,10 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>(
|
||||
compareId(state.lastReadId, mostRecentGroup.page_max_id) < 0
|
||||
)
|
||||
state.lastReadId = mostRecentGroup.page_max_id;
|
||||
commitLastReadId(state);
|
||||
|
||||
// We don't call `commitLastReadId`, because that is conditional
|
||||
// and we want to unconditionally update the state instead.
|
||||
state.readMarkerId = state.lastReadId;
|
||||
})
|
||||
.addCase(fetchMarkers.fulfilled, (state, action) => {
|
||||
if (
|
||||
|
50
app/javascript/mastodon/selectors/filters.ts
Normal file
50
app/javascript/mastodon/selectors/filters.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
import type { RootState } from 'mastodon/store';
|
||||
import { toServerSideType } from 'mastodon/utils/filters';
|
||||
|
||||
// TODO: move to `app/javascript/mastodon/models` and use more globally
|
||||
type Filter = Immutable.Map<string, unknown>;
|
||||
|
||||
// TODO: move to `app/javascript/mastodon/models` and use more globally
|
||||
type FilterResult = Immutable.Map<string, unknown>;
|
||||
|
||||
export const getFilters = createSelector(
|
||||
[
|
||||
(state: RootState) => state.filters as Immutable.Map<string, Filter>,
|
||||
(_, { contextType }: { contextType: string }) => contextType,
|
||||
],
|
||||
(filters, contextType) => {
|
||||
if (!contextType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const serverSideType = toServerSideType(contextType);
|
||||
|
||||
return filters.filter((filter) => {
|
||||
const context = filter.get('context') as Immutable.List<string>;
|
||||
const expiration = filter.get('expires_at') as Date | null;
|
||||
return (
|
||||
context.includes(serverSideType) &&
|
||||
(expiration === null || expiration > now)
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export const getStatusHidden = (
|
||||
state: RootState,
|
||||
{ id, contextType }: { id: string; contextType: string },
|
||||
) => {
|
||||
const filters = getFilters(state, { contextType });
|
||||
if (filters === null) return false;
|
||||
|
||||
const filtered = state.statuses.getIn([id, 'filtered']) as
|
||||
| Immutable.List<FilterResult>
|
||||
| undefined;
|
||||
return filtered?.some(
|
||||
(result) =>
|
||||
filters.getIn([result.get('filter'), 'filter_action']) === 'hide',
|
||||
);
|
||||
};
|
@ -1,23 +1,12 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { toServerSideType } from 'mastodon/utils/filters';
|
||||
|
||||
import { me } from '../initial_state';
|
||||
|
||||
import { getFilters } from './filters';
|
||||
|
||||
export { makeGetAccount } from "./accounts";
|
||||
|
||||
const getFilters = createSelector([state => state.get('filters'), (_, { contextType }) => contextType], (filters, contextType) => {
|
||||
if (!contextType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const serverSideType = toServerSideType(contextType);
|
||||
|
||||
return filters.filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || filter.get('expires_at') > now));
|
||||
});
|
||||
|
||||
export const makeGetStatus = () => {
|
||||
return createSelector(
|
||||
[
|
||||
|
@ -1045,6 +1045,12 @@ a.name-tag,
|
||||
color: var(--user-role-accent);
|
||||
}
|
||||
|
||||
.applications-list {
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.announcements-list,
|
||||
.filters-list {
|
||||
border: 1px solid var(--background-border-color);
|
||||
|
@ -2878,7 +2878,7 @@ $ui-header-logo-wordmark-width: 99px;
|
||||
}
|
||||
|
||||
.column {
|
||||
width: 400px;
|
||||
width: clamp(380px, calc((100% - 350px) / 4), 400px);
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
@ -8007,79 +8007,23 @@ noscript {
|
||||
background: rgba($base-overlay-background, 0.5);
|
||||
}
|
||||
|
||||
.list-adder,
|
||||
.list-editor {
|
||||
background: $ui-base-color;
|
||||
backdrop-filter: var(--background-filter);
|
||||
background: var(--modal-background-color);
|
||||
border: 1px solid var(--modal-border-color);
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
width: 380px;
|
||||
overflow: hidden;
|
||||
|
||||
@media screen and (width <= 420px) {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding: 15px 0;
|
||||
background: lighten($ui-base-color, 13%);
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
height: 50vh;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
&.backdrop {
|
||||
width: calc(100% - 60px);
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.account__display-name {
|
||||
&:hover strong {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.list-adder {
|
||||
background: $ui-base-color;
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
width: 380px;
|
||||
overflow: hidden;
|
||||
|
||||
@media screen and (width <= 420px) {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
&__account {
|
||||
background: lighten($ui-base-color, 13%);
|
||||
}
|
||||
|
||||
&__lists {
|
||||
background: lighten($ui-base-color, 13%);
|
||||
height: 50vh;
|
||||
border-radius: 0 0 8px 8px;
|
||||
overflow-y: auto;
|
||||
@ -8100,6 +8044,52 @@ noscript {
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-editor {
|
||||
h4 {
|
||||
padding: 15px 0;
|
||||
background: lighten($ui-base-color, 13%);
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
height: 50vh;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
&.backdrop {
|
||||
width: calc(100% - 60px);
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
background: unset;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.account__display-name {
|
||||
&:hover strong {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
return if account.nil?
|
||||
|
||||
@mentions << Mention.new(account: account, silent: false)
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
@unresolved_mentions << tag['href']
|
||||
end
|
||||
|
||||
@ -250,7 +250,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
media_attachment.download_file!
|
||||
media_attachment.download_thumbnail!
|
||||
media_attachment.save
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id)
|
||||
rescue Seahorse::Client::NetworkingError => e
|
||||
Rails.logger.warn "Error storing media attachment: #{e}"
|
||||
|
@ -35,7 +35,7 @@ class AccountAlias < ApplicationRecord
|
||||
def set_uri
|
||||
target_account = ResolveAccountService.new.call(acct)
|
||||
self.uri = ActivityPub::TagManager.instance.uri_for(target_account) unless target_account.nil?
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
|
||||
rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::Error
|
||||
# Validation will take care of it
|
||||
end
|
||||
|
||||
|
@ -61,7 +61,7 @@ class AccountMigration < ApplicationRecord
|
||||
|
||||
def set_target_account
|
||||
self.target_account = ResolveAccountService.new.call(acct, skip_cache: true)
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
# Validation will take care of it
|
||||
end
|
||||
|
||||
|
@ -26,7 +26,7 @@ module Remotable
|
||||
|
||||
public_send(:"#{attachment_name}=", ResponseWithLimit.new(response, limit))
|
||||
end
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS => e
|
||||
Rails.logger.debug { "Error fetching remote #{attachment_name}: #{e}" }
|
||||
public_send(:"#{attachment_name}=", nil) if public_send(:"#{attachment_name}_file_name").present?
|
||||
raise e unless suppress_errors
|
||||
|
@ -40,7 +40,9 @@ class DomainBlock < ApplicationRecord
|
||||
if suspend?
|
||||
[:suspend]
|
||||
else
|
||||
[severity.to_sym, reject_media? ? :reject_media : nil, reject_reports? ? :reject_reports : nil].reject { |policy| policy == :noop || policy.nil? }
|
||||
[severity.to_sym, reject_media? ? :reject_media : nil, reject_reports? ? :reject_reports : nil]
|
||||
.reject { |policy| policy == :noop }
|
||||
.compact
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -18,5 +18,6 @@ class FollowRecommendation < ApplicationRecord
|
||||
belongs_to :account_summary, foreign_key: :account_id, inverse_of: false
|
||||
belongs_to :account
|
||||
|
||||
scope :localized, ->(locale) { joins(:account_summary).merge(AccountSummary.localized(locale)) }
|
||||
scope :unsupressed, -> { where.not(FollowRecommendationSuppression.where(FollowRecommendationSuppression.arel_table[:account_id].eq(arel_table[:account_id])).select(1).arel.exists) }
|
||||
scope :localized, ->(locale) { unsupressed.joins(:account_summary).merge(AccountSummary.localized(locale)) }
|
||||
end
|
||||
|
@ -32,7 +32,7 @@ class Form::Redirect
|
||||
|
||||
def set_target_account
|
||||
@target_account = ResolveAccountService.new.call(acct, skip_cache: true)
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
# Validation will take care of it
|
||||
end
|
||||
|
||||
|
@ -62,6 +62,6 @@ class NotificationPolicy < ApplicationRecord
|
||||
private
|
||||
|
||||
def pending_notification_requests
|
||||
@pending_notification_requests ||= notification_requests.limit(MAX_MEANINGFUL_COUNT).pick(Arel.sql('count(*), coalesce(sum(notifications_count), 0)::bigint'))
|
||||
@pending_notification_requests ||= notification_requests.without_suspended.limit(MAX_MEANINGFUL_COUNT).pick(Arel.sql('count(*), coalesce(sum(notifications_count), 0)::bigint'))
|
||||
end
|
||||
end
|
||||
|
@ -26,6 +26,8 @@ class NotificationRequest < ApplicationRecord
|
||||
|
||||
before_save :prepare_notifications_count
|
||||
|
||||
scope :without_suspended, -> { joins(:from_account).merge(Account.without_suspended) }
|
||||
|
||||
def self.preload_cache_collection(requests)
|
||||
cached_statuses_by_id = yield(requests.filter_map(&:last_status)).index_by(&:id) # Call cache_collection in block
|
||||
|
||||
|
@ -66,7 +66,7 @@ class RemoteFollow
|
||||
|
||||
def acct_resource
|
||||
@acct_resource ||= Webfinger.new("acct:#{acct}").perform
|
||||
rescue Webfinger::Error, HTTP::ConnectionError
|
||||
rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
nil
|
||||
end
|
||||
|
||||
|
@ -8,7 +8,8 @@ class ManifestSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :short_name,
|
||||
:icons, :theme_color, :background_color,
|
||||
:display, :start_url, :scope,
|
||||
:share_target, :shortcuts
|
||||
:share_target, :shortcuts,
|
||||
:prefer_related_applications, :related_applications
|
||||
|
||||
def id
|
||||
# This is set to `/home` because that was the old value of `start_url` and
|
||||
@ -89,4 +90,28 @@ class ManifestSerializer < ActiveModel::Serializer
|
||||
},
|
||||
]
|
||||
end
|
||||
|
||||
def prefer_related_applications
|
||||
true
|
||||
end
|
||||
|
||||
def related_applications
|
||||
[
|
||||
{
|
||||
platform: 'play',
|
||||
url: 'https://play.google.com/store/apps/details?id=org.joinmastodon.android',
|
||||
id: 'org.joinmastodon.android',
|
||||
},
|
||||
{
|
||||
platform: 'itunes',
|
||||
url: 'https://apps.apple.com/us/app/mastodon-for-iphone/id1571998974',
|
||||
id: 'id1571998974',
|
||||
},
|
||||
{
|
||||
platform: 'f-droid',
|
||||
url: 'https://f-droid.org/en/packages/org.joinmastodon.android/',
|
||||
id: 'org.joinmastodon.android',
|
||||
},
|
||||
]
|
||||
end
|
||||
end
|
||||
|
@ -127,13 +127,13 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
begin
|
||||
@account.avatar_remote_url = image_url('icon') || '' unless skip_download?
|
||||
@account.avatar = nil if @account.avatar_remote_url.blank?
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
RedownloadAvatarWorker.perform_in(rand(30..600).seconds, @account.id)
|
||||
end
|
||||
begin
|
||||
@account.header_remote_url = image_url('image') || '' unless skip_download?
|
||||
@account.header = nil if @account.header_remote_url.blank?
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
RedownloadHeaderWorker.perform_in(rand(30..600).seconds, @account.id)
|
||||
end
|
||||
@account.statuses_count = outbox_total_items if outbox_total_items.present?
|
||||
@ -276,7 +276,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
total_items = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil
|
||||
has_first_page = collection.is_a?(Hash) && collection['first'].present?
|
||||
@collections[type] = [total_items, has_first_page]
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::LengthValidationError
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::LengthValidationError
|
||||
@collections[type] = [nil, nil]
|
||||
end
|
||||
|
||||
|
@ -109,7 +109,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||
media_attachment.download_file! if media_attachment.remote_url_previously_changed?
|
||||
media_attachment.download_thumbnail! if media_attachment.thumbnail_remote_url_previously_changed?
|
||||
media_attachment.save
|
||||
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id)
|
||||
rescue Seahorse::Client::NetworkingError => e
|
||||
Rails.logger.warn "Error storing media attachment: #{e}"
|
||||
|
@ -29,7 +29,7 @@ class FetchLinkCardService < BaseService
|
||||
end
|
||||
|
||||
attach_card if @card&.persisted?
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Encoding::UndefinedConversionError, ActiveRecord::RecordInvalid => e
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Encoding::UndefinedConversionError, ActiveRecord::RecordInvalid => e
|
||||
Rails.logger.debug { "Error fetching link #{@original_url}: #{e}" }
|
||||
nil
|
||||
end
|
||||
|
@ -12,7 +12,7 @@ class FetchResourceService < BaseService
|
||||
return if url.blank?
|
||||
|
||||
process(url)
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e
|
||||
Rails.logger.debug { "Error fetching resource #{@url}: #{e}" }
|
||||
nil
|
||||
end
|
||||
|
@ -115,7 +115,7 @@ class ImportService < BaseService
|
||||
next if status.nil? && ActivityPub::TagManager.instance.local_uri?(uri)
|
||||
|
||||
status || ActivityPub::FetchRemoteStatusService.new.call(uri)
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::UnexpectedResponseError
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::UnexpectedResponseError
|
||||
nil
|
||||
rescue => e
|
||||
Rails.logger.warn "Unexpected error when importing bookmark: #{e}"
|
||||
|
@ -44,7 +44,7 @@ class ProcessMentionsService < BaseService
|
||||
if mention_undeliverable?(mentioned_account)
|
||||
begin
|
||||
mentioned_account = ResolveAccountService.new.call(Regexp.last_match(1))
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::UnexpectedResponseError
|
||||
rescue Webfinger::Error, *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::UnexpectedResponseError
|
||||
mentioned_account = nil
|
||||
end
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ class SoftwareUpdateCheckService < BaseService
|
||||
Request.new(:get, "#{api_url}?version=#{version}").add_headers('Accept' => 'application/json', 'User-Agent' => 'Mastodon update checker').perform do |res|
|
||||
return Oj.load(res.body_with_limit, mode: :strict) if res.code == 200
|
||||
end
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError, Oj::ParseError
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Oj::ParseError
|
||||
nil
|
||||
end
|
||||
|
||||
|
@ -10,7 +10,7 @@ class VerifyLinkService < BaseService
|
||||
return unless link_back_present?
|
||||
|
||||
field.mark_verified!
|
||||
rescue OpenSSL::SSL::SSLError, HTTP::Error, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, IPAddr::AddressFamilyError => e
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, IPAddr::AddressFamilyError => e
|
||||
Rails.logger.debug { "Error fetching link #{@url}: #{e}" }
|
||||
nil
|
||||
end
|
||||
|
@ -21,7 +21,7 @@ class RefollowWorker
|
||||
# Schedule re-follow
|
||||
begin
|
||||
FollowService.new.call(follower, target_account, reblogs: reblogs, notify: notify, languages: languages, bypass_limit: true)
|
||||
rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, HTTP::Error, OpenSSL::SSL::SSLError
|
||||
rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||
next
|
||||
end
|
||||
end
|
||||
|
@ -55,12 +55,8 @@ class Web::PushNotificationWorker
|
||||
end
|
||||
|
||||
def push_notification_json
|
||||
Oj.dump(serialized_notification_in_subscription_locale.as_json)
|
||||
end
|
||||
|
||||
def serialized_notification_in_subscription_locale
|
||||
I18n.with_locale(@subscription.locale.presence || I18n.default_locale) do
|
||||
serialized_notification
|
||||
Oj.dump(serialized_notification.as_json)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -96,10 +96,6 @@ module Mastodon
|
||||
config.middleware.use Rack::Attack
|
||||
config.middleware.use Mastodon::RackMiddleware
|
||||
|
||||
initializer :deprecator do |app|
|
||||
app.deprecators[:mastodon] = ActiveSupport::Deprecation.new('4.3', 'mastodon/mastodon')
|
||||
end
|
||||
|
||||
config.before_configuration do
|
||||
require 'mastodon/redis_configuration'
|
||||
::REDIS_CONFIGURATION = Mastodon::RedisConfiguration.new
|
||||
|
@ -1,56 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Some migrations have been present in glitch-soc for a long time and have then
|
||||
# been merged in upstream Mastodon, under a different version number.
|
||||
#
|
||||
# This puts us in an uneasy situation in which if we remove upstream's
|
||||
# migration file, people migrating from upstream will end up having a conflict
|
||||
# with their already-ran migration.
|
||||
#
|
||||
# On the other hand, if we keep upstream's migration and remove our own,
|
||||
# any current glitch-soc user will have a conflict during migration.
|
||||
#
|
||||
# For lack of a better solution, as those migrations are indeed identical,
|
||||
# we decided monkey-patching Rails' Migrator to completely ignore the duplicate,
|
||||
# keeping only the one that has run, or an arbitrary one.
|
||||
|
||||
ALLOWED_DUPLICATES = [2018_04_10_220657, 2018_08_31_171112].freeze
|
||||
|
||||
module ActiveRecord
|
||||
class Migrator
|
||||
def self.new(direction, migrations, schema_migration, internal_metadata, target_version = nil)
|
||||
migrated = Set.new(Base.connection.migration_context.get_all_versions)
|
||||
|
||||
migrations.group_by(&:name).each_value do |duplicates|
|
||||
next unless duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }
|
||||
|
||||
# We have a set of allowed duplicates. Keep the migrated one, if any.
|
||||
non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }
|
||||
|
||||
migrations = begin
|
||||
if duplicates.length == non_migrated.length || non_migrated.empty?
|
||||
# There weren't any migrated one, so we have to pick one “canonical” migration
|
||||
migrations - duplicates[1..]
|
||||
else
|
||||
# Just reject every duplicate which hasn't been migrated yet
|
||||
migrations - non_migrated
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
class MigrationContext
|
||||
def needs_migration?
|
||||
# A set of duplicated migrations is considered migrated if at least one of
|
||||
# them is migrated.
|
||||
migrated = get_all_versions
|
||||
migrations.group_by(&:name).each_value do |duplicates|
|
||||
return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) }
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
@ -20,6 +20,7 @@
|
||||
- ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
|
||||
|
||||
Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables.
|
||||
Do not change the secrets once they are set, as doing so may cause data loss and other issues that will be difficult or impossible to recover from.
|
||||
MESSAGE
|
||||
end
|
||||
|
||||
|
@ -21,6 +21,7 @@ ca:
|
||||
one: Tut
|
||||
other: Tuts
|
||||
posts_tab_heading: Tuts
|
||||
self_follow_error: No es permet seguir el compte propi
|
||||
admin:
|
||||
account_actions:
|
||||
action: Realitza l'acció
|
||||
|
@ -21,6 +21,7 @@ da:
|
||||
one: Indlæg
|
||||
other: Indlæg
|
||||
posts_tab_heading: Indlæg
|
||||
self_follow_error: Det er ikke tilladt at følge sin egen konto
|
||||
admin:
|
||||
account_actions:
|
||||
action: Udfør handling
|
||||
|
@ -21,6 +21,7 @@ de:
|
||||
one: Beitrag
|
||||
other: Beiträge
|
||||
posts_tab_heading: Beiträge
|
||||
self_follow_error: Es ist nicht erlaubt, deinem eigenen Konto zu folgen
|
||||
admin:
|
||||
account_actions:
|
||||
action: Aktion ausführen
|
||||
|
@ -21,6 +21,7 @@ eo:
|
||||
one: Afiŝo
|
||||
other: Mesaĝoj
|
||||
posts_tab_heading: Afiŝoj
|
||||
self_follow_error: Sekvi vian propran konton ne estas permesita
|
||||
admin:
|
||||
account_actions:
|
||||
action: Plenumi agon
|
||||
|
@ -21,6 +21,7 @@ es-AR:
|
||||
one: Mensaje
|
||||
other: Mensajes
|
||||
posts_tab_heading: Mensajes
|
||||
self_follow_error: No está permitido seguir tu propia cuenta
|
||||
admin:
|
||||
account_actions:
|
||||
action: Ejecutar acción
|
||||
|
@ -21,6 +21,7 @@ es-MX:
|
||||
one: Toot
|
||||
other: Toots
|
||||
posts_tab_heading: Toots
|
||||
self_follow_error: No se permite seguir tu propia cuenta
|
||||
admin:
|
||||
account_actions:
|
||||
action: Realizar acción
|
||||
|
@ -21,6 +21,7 @@ es:
|
||||
one: Publicación
|
||||
other: Publicaciones
|
||||
posts_tab_heading: Publicaciones
|
||||
self_follow_error: No está permitido seguir tu propia cuenta
|
||||
admin:
|
||||
account_actions:
|
||||
action: Realizar acción
|
||||
|
@ -21,6 +21,7 @@ fi:
|
||||
one: Julkaisu
|
||||
other: viestiä
|
||||
posts_tab_heading: Julkaisut
|
||||
self_follow_error: Oman tilisi seuraaminen ei ole sallittua
|
||||
admin:
|
||||
account_actions:
|
||||
action: Suorita toimi
|
||||
|
@ -21,6 +21,7 @@ fo:
|
||||
one: Uppslag
|
||||
other: Uppsløg
|
||||
posts_tab_heading: Uppsløg
|
||||
self_follow_error: Tað er ikki loyvt at fylgja tíni egnu kontu
|
||||
admin:
|
||||
account_actions:
|
||||
action: Frem atgerð
|
||||
|
@ -21,6 +21,7 @@ gl:
|
||||
one: Publicación
|
||||
other: Publicacións
|
||||
posts_tab_heading: Publicacións
|
||||
self_follow_error: Non está permitido seguir a túa propia conta
|
||||
admin:
|
||||
account_actions:
|
||||
action: Executar acción
|
||||
|
@ -25,6 +25,7 @@ he:
|
||||
other: הודעות
|
||||
two: הודעותיים
|
||||
posts_tab_heading: הודעות
|
||||
self_follow_error: בלתי אפשרי לך לעקוב אחרי חשבונך
|
||||
admin:
|
||||
account_actions:
|
||||
action: בצע/י פעולה
|
||||
|
@ -21,6 +21,7 @@ is:
|
||||
one: Færsla
|
||||
other: Færslur
|
||||
posts_tab_heading: Færslur
|
||||
self_follow_error: Ekki er leyft að fylgjast með eigin aðgangi
|
||||
admin:
|
||||
account_actions:
|
||||
action: Framkvæma aðgerð
|
||||
|
@ -19,6 +19,7 @@ ja:
|
||||
posts:
|
||||
other: 投稿
|
||||
posts_tab_heading: 投稿
|
||||
self_follow_error: 自分のアカウントをフォローすることはできません
|
||||
admin:
|
||||
account_actions:
|
||||
action: アクションを実行
|
||||
|
@ -19,6 +19,7 @@ ko:
|
||||
posts:
|
||||
other: 게시물
|
||||
posts_tab_heading: 게시물
|
||||
self_follow_error: 본인의 계정을 팔로우할 수는 없습니다
|
||||
admin:
|
||||
account_actions:
|
||||
action: 조치 취하기
|
||||
|
@ -21,6 +21,7 @@ nl:
|
||||
one: Toot
|
||||
other: Berichten
|
||||
posts_tab_heading: Berichten
|
||||
self_follow_error: Het volgen van je eigen account is niet toegestaan
|
||||
admin:
|
||||
account_actions:
|
||||
action: Actie uitvoeren
|
||||
|
@ -21,6 +21,7 @@ nn:
|
||||
one: Tut
|
||||
other: Tut
|
||||
posts_tab_heading: Tut
|
||||
self_follow_error: Det er ikkje tillate å følgje din eigen konto
|
||||
admin:
|
||||
account_actions:
|
||||
action: Utfør
|
||||
|
@ -25,6 +25,7 @@ pl:
|
||||
one: wpis
|
||||
other: Wpisów
|
||||
posts_tab_heading: Wpisy
|
||||
self_follow_error: Nie możesz obserwować swojego konta
|
||||
admin:
|
||||
account_actions:
|
||||
action: Wykonaj działanie
|
||||
|
@ -21,6 +21,7 @@ pt-BR:
|
||||
one: Publicação
|
||||
other: Publicações
|
||||
posts_tab_heading: Publicações
|
||||
self_follow_error: Seguir sua conta não é permitido
|
||||
admin:
|
||||
account_actions:
|
||||
action: Tomar uma atitude
|
||||
|
@ -21,6 +21,7 @@ tr:
|
||||
one: Gönderi
|
||||
other: Gönderiler
|
||||
posts_tab_heading: Gönderiler
|
||||
self_follow_error: Kendi hesabınızı takip etmenize izin yok
|
||||
admin:
|
||||
account_actions:
|
||||
action: Eylemi gerçekleştir
|
||||
|
@ -25,6 +25,7 @@ uk:
|
||||
one: Допис
|
||||
other: Дописів
|
||||
posts_tab_heading: Дописів
|
||||
self_follow_error: Ви не можете стежити за власним обліковим записом
|
||||
admin:
|
||||
account_actions:
|
||||
action: Виконати дію
|
||||
|
@ -19,6 +19,7 @@ vi:
|
||||
posts:
|
||||
other: Tút
|
||||
posts_tab_heading: Tút
|
||||
self_follow_error: Bạn không thể tự theo dõi chính bạn
|
||||
admin:
|
||||
account_actions:
|
||||
action: Thực hiện hành động
|
||||
|
@ -19,6 +19,7 @@ zh-CN:
|
||||
posts:
|
||||
other: 嘟文
|
||||
posts_tab_heading: 嘟文
|
||||
self_follow_error: 不可以关注自己
|
||||
admin:
|
||||
account_actions:
|
||||
action: 执行操作
|
||||
|
@ -19,6 +19,7 @@ zh-TW:
|
||||
posts:
|
||||
other: 嘟文
|
||||
posts_tab_heading: 嘟文
|
||||
self_follow_error: 無法跟隨您自己的帳號
|
||||
admin:
|
||||
account_actions:
|
||||
action: 執行動作
|
||||
|
@ -1,10 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This migration is a duplicate of 20180831171112 and may get ignored, see
|
||||
# config/initializers/0_duplicate_migrations.rb
|
||||
# This migration is a duplicate of 20180831171112
|
||||
|
||||
class GlitchCreateBookmarks < ActiveRecord::Migration[5.1]
|
||||
def up
|
||||
return if table_exists?(:bookmarks)
|
||||
|
||||
class CreateBookmarks < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
create_table :bookmarks do |t|
|
||||
t.references :account, null: false
|
||||
t.references :status, null: false
|
||||
@ -19,4 +20,6 @@ class CreateBookmarks < ActiveRecord::Migration[5.1]
|
||||
|
||||
add_index :bookmarks, [:account_id, :status_id], unique: true
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
@ -1,10 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This migration is a duplicate of 20180410220657 and may get ignored, see
|
||||
# config/initializers/0_duplicate_migrations.rb
|
||||
# This migration is a duplicate of 20180410220657
|
||||
|
||||
class CreateBookmarks < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
def up
|
||||
return if table_exists?(:bookmarks)
|
||||
|
||||
create_table :bookmarks do |t|
|
||||
t.references :account, null: false
|
||||
t.references :status, null: false
|
||||
@ -19,4 +20,8 @@ class CreateBookmarks < ActiveRecord::Migration[5.2]
|
||||
|
||||
add_index :bookmarks, [:account_id, :status_id], unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :bookmarks
|
||||
end
|
||||
end
|
||||
|
@ -59,7 +59,7 @@ services:
|
||||
web:
|
||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||
# build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.0-rc.1
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.0
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec puma -C config/puma.rb
|
||||
@ -83,7 +83,7 @@ services:
|
||||
# build:
|
||||
# dockerfile: ./streaming/Dockerfile
|
||||
# context: .
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.0-rc.1
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.0
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: node ./streaming/index.js
|
||||
@ -101,7 +101,7 @@ services:
|
||||
|
||||
sidekiq:
|
||||
build: .
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.0-rc.1
|
||||
image: ghcr.io/mastodon/mastodon:v4.3.0
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
|
@ -36,4 +36,11 @@ module Mastodon
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
HTTP_CONNECTION_ERRORS = [
|
||||
HTTP::ConnectionError,
|
||||
HTTP::Error,
|
||||
HTTP::TimeoutError,
|
||||
OpenSSL::SSL::SSLError,
|
||||
].freeze
|
||||
end
|
||||
|
@ -305,7 +305,7 @@ module Mastodon::CLI
|
||||
|
||||
begin
|
||||
code = Request.new(:head, account.uri).perform(&:code)
|
||||
rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Mastodon::PrivateNetworkAddressError
|
||||
rescue *Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::PrivateNetworkAddressError
|
||||
skip_domains << account.domain
|
||||
end
|
||||
|
||||
|
@ -5,7 +5,7 @@ require_relative 'base'
|
||||
|
||||
module Mastodon::CLI
|
||||
class IpBlocks < Base
|
||||
option :severity, required: true, enum: %w(no_access sign_up_requires_approval sign_up_block), desc: 'Severity of the block'
|
||||
option :severity, required: true, enum: IpBlock.severities.keys, desc: 'Severity of the block'
|
||||
option :comment, aliases: [:c], desc: 'Optional comment'
|
||||
option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds'
|
||||
option :force, type: :boolean, aliases: [:f], desc: 'Overwrite existing blocks'
|
||||
|
@ -7,8 +7,19 @@ namespace :db do
|
||||
namespace :encryption do
|
||||
desc 'Generate a set of keys for configuring Active Record encryption in a given environment'
|
||||
task :init do # rubocop:disable Rails/RakeEnvironment
|
||||
if %w(
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
|
||||
).any? { |key| ENV.key?(key) }
|
||||
pastel = Pastel.new
|
||||
puts pastel.red(<<~MSG)
|
||||
WARNING: It looks like encryption secrets have already been set. Please ensure you are not changing secrets for a Mastodon installation that already uses them, as this will cause data loss and other issues that are difficult to recover from.
|
||||
MSG
|
||||
end
|
||||
|
||||
puts <<~MSG
|
||||
Add these secret environment variables to your Mastodon environment (e.g. .env.production):#{' '}
|
||||
Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set:#{' '}
|
||||
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=#{SecureRandom.alphanumeric(32)}
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=#{SecureRandom.alphanumeric(32)}
|
||||
|
@ -1,82 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TagsController do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
before do
|
||||
Fabricate(:tag)
|
||||
|
||||
tag_filter = instance_double(Admin::TagFilter, results: Tag.all)
|
||||
allow(Admin::TagFilter).to receive(:new).and_return(tag_filter)
|
||||
end
|
||||
|
||||
let(:params) { { order: 'newest' } }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:index)
|
||||
|
||||
expect(Admin::TagFilter)
|
||||
.to have_received(:new)
|
||||
.with(hash_including(params))
|
||||
end
|
||||
|
||||
describe 'with filters' do
|
||||
let(:params) { { order: 'newest', name: 'test' } }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index, params: { name: 'test' }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:index)
|
||||
|
||||
expect(Admin::TagFilter)
|
||||
.to have_received(:new)
|
||||
.with(hash_including(params))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let!(:tag) { Fabricate(:tag) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: tag.id }
|
||||
end
|
||||
|
||||
it 'returns status 200' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let!(:tag) { Fabricate(:tag, listable: false) }
|
||||
|
||||
context 'with valid params' do
|
||||
it 'updates the tag' do
|
||||
put :update, params: { id: tag.id, tag: { listable: '1' } }
|
||||
|
||||
expect(response).to redirect_to(admin_tag_path(tag.id))
|
||||
expect(tag.reload).to be_listable
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
it 'does not update the tag' do
|
||||
put :update, params: { id: tag.id, tag: { name: 'cant-change-name' } }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:show)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -3,14 +3,13 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe DomainBlock do
|
||||
describe 'validations' do
|
||||
describe 'Validations' do
|
||||
it { is_expected.to validate_presence_of(:domain) }
|
||||
|
||||
it 'is invalid if the same normalized domain already exists' do
|
||||
_domain_block = Fabricate(:domain_block, domain: 'にゃん')
|
||||
domain_block_with_normalized_value = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b')
|
||||
domain_block_with_normalized_value.valid?
|
||||
expect(domain_block_with_normalized_value).to model_have_error_on_field(:domain)
|
||||
context 'when a normalized domain exists' do
|
||||
before { Fabricate(:domain_block, domain: 'にゃん') }
|
||||
|
||||
it { is_expected.to_not allow_value('xn--r9j5b5b').for(:domain) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -105,4 +104,26 @@ RSpec.describe DomainBlock do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#policies' do
|
||||
subject { domain_block.policies }
|
||||
|
||||
context 'when severity is suspend' do
|
||||
let(:domain_block) { Fabricate.build :domain_block, severity: :suspend }
|
||||
|
||||
it { is_expected.to eq(%i(suspend)) }
|
||||
end
|
||||
|
||||
context 'when severity is noop' do
|
||||
let(:domain_block) { Fabricate.build :domain_block, severity: :noop, reject_media: true }
|
||||
|
||||
it { is_expected.to eq(%i(reject_media)) }
|
||||
end
|
||||
|
||||
context 'when severity is silence' do
|
||||
let(:domain_block) { Fabricate.build :domain_block, severity: :silence, reject_reports: true }
|
||||
|
||||
it { is_expected.to eq(%i(silence reject_reports)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -7,19 +7,25 @@ RSpec.describe NotificationPolicy do
|
||||
subject { Fabricate(:notification_policy) }
|
||||
|
||||
let(:sender) { Fabricate(:account) }
|
||||
let(:suspended_sender) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
Fabricate.times(2, :notification, account: subject.account, activity: Fabricate(:status, account: sender), filtered: true, type: :mention)
|
||||
Fabricate(:notification_request, account: subject.account, from_account: sender)
|
||||
|
||||
Fabricate(:notification, account: subject.account, activity: Fabricate(:status, account: suspended_sender), filtered: true, type: :mention)
|
||||
Fabricate(:notification_request, account: subject.account, from_account: suspended_sender)
|
||||
|
||||
suspended_sender.suspend!
|
||||
|
||||
subject.summarize!
|
||||
end
|
||||
|
||||
it 'sets pending_requests_count' do
|
||||
expect(subject.pending_requests_count).to eq 1
|
||||
end
|
||||
|
||||
it 'sets pending_notifications_count' do
|
||||
expect(subject.pending_notifications_count).to eq 2
|
||||
it 'sets pending_requests_count and pending_notifications_count' do
|
||||
expect(subject).to have_attributes(
|
||||
pending_requests_count: 1,
|
||||
pending_notifications_count: 2
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -559,11 +559,53 @@ RSpec.describe Status do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
it 'disallow empty uri for remote status' do
|
||||
alice.update(domain: 'example.com')
|
||||
status = Fabricate.build(:status, uri: '', account: alice)
|
||||
expect(status).to model_have_error_on_field(:uri)
|
||||
describe 'Validations' do
|
||||
context 'with a remote account' do
|
||||
subject { Fabricate.build :status, account: remote_account }
|
||||
|
||||
let(:remote_account) { Fabricate :account, domain: 'example.com' }
|
||||
|
||||
it { is_expected.to_not allow_value('').for(:uri) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Callbacks' do
|
||||
describe 'Stripping content when required' do
|
||||
context 'with a remote account' do
|
||||
subject { Fabricate.build :status, local: false, account:, text: ' text ', spoiler_text: ' spoiler ' }
|
||||
|
||||
let(:account) { Fabricate.build :account, domain: 'host.example' }
|
||||
|
||||
it 'preserves content' do
|
||||
expect { subject.valid? }
|
||||
.to not_change(subject, :text)
|
||||
.and not_change(subject, :spoiler_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a local account' do
|
||||
let(:account) { Fabricate.build :account, domain: nil }
|
||||
|
||||
context 'with populated fields' do
|
||||
subject { Fabricate.build :status, local: true, account:, text: ' text ', spoiler_text: ' spoiler ' }
|
||||
|
||||
it 'strips content' do
|
||||
expect { subject.valid? }
|
||||
.to change(subject, :text).to('text')
|
||||
.and change(subject, :spoiler_text).to('spoiler')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with empty fields' do
|
||||
subject { Fabricate.build :status, local: true, account:, text: nil, spoiler_text: nil }
|
||||
|
||||
it 'preserves content' do
|
||||
expect { subject.valid? }
|
||||
.to not_change(subject, :text)
|
||||
.and not_change(subject, :spoiler_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
38
spec/system/admin/tags_spec.rb
Normal file
38
spec/system/admin/tags_spec.rb
Normal file
@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Tags' do
|
||||
describe 'Tag interaction' do
|
||||
let!(:tag) { Fabricate(:tag, name: 'test') }
|
||||
|
||||
before { sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
it 'allows tags listing and editing' do
|
||||
visit admin_tags_path
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('admin.tags.title'))
|
||||
|
||||
click_on '#test'
|
||||
|
||||
fill_in display_name_field, with: 'NewTagName'
|
||||
expect { click_on submit_button }
|
||||
.to_not(change { tag.reload.display_name })
|
||||
expect(page)
|
||||
.to have_content(match_error_text)
|
||||
|
||||
fill_in display_name_field, with: 'TEST'
|
||||
expect { click_on submit_button }
|
||||
.to(change { tag.reload.display_name }.to('TEST'))
|
||||
end
|
||||
|
||||
def display_name_field
|
||||
I18n.t('simple_form.labels.defaults.display_name')
|
||||
end
|
||||
|
||||
def match_error_text
|
||||
I18n.t('tags.does_not_match_previous_name')
|
||||
end
|
||||
end
|
||||
end
|
@ -24,28 +24,28 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
subject
|
||||
|
||||
# It presents the user with an authorization page
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_authorize_text)
|
||||
|
||||
# It grants the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be true
|
||||
expect { click_on oauth_authorize_text }
|
||||
.to change { user_has_grant_with_client_app? }.to(true)
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
|
||||
it 'when rejecting the authorization request' do
|
||||
subject
|
||||
|
||||
# It presents the user with an authorization page
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.deny'))
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_deny_text)
|
||||
|
||||
# It does not grant the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be false
|
||||
expect { click_on oauth_deny_text }
|
||||
.to_not change { user_has_grant_with_client_app? }.from(false)
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
|
||||
# The tests in this context ensures that requests without PKCE parameters
|
||||
@ -133,7 +133,6 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
end
|
||||
|
||||
it 'when accepting the authorization request' do
|
||||
params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
|
||||
visit "/oauth/authorize?#{params.to_query}"
|
||||
|
||||
# It presents the user with a log-in page
|
||||
@ -145,18 +144,17 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
|
||||
# Logging in redirects to an authorization page
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_authorize_text)
|
||||
|
||||
# It grants the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be true
|
||||
expect { click_on oauth_authorize_text }
|
||||
.to change { user_has_grant_with_client_app? }.to(true)
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
|
||||
it 'when rejecting the authorization request' do
|
||||
params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
|
||||
visit "/oauth/authorize?#{params.to_query}"
|
||||
|
||||
# It presents the user with a log-in page
|
||||
@ -168,21 +166,20 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
|
||||
# Logging in redirects to an authorization page
|
||||
fill_in_auth_details(email, password)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_authorize_text)
|
||||
|
||||
# It does not grant the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be false
|
||||
expect { click_on oauth_deny_text }
|
||||
.to_not change { user_has_grant_with_client_app? }.from(false)
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
|
||||
context 'when the user has set up TOTP' do
|
||||
let(:user) { Fabricate(:user, email: email, password: password, otp_required_for_login: true, otp_secret: User.generate_otp_secret) }
|
||||
|
||||
it 'when accepting the authorization request' do
|
||||
params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
|
||||
visit "/oauth/authorize?#{params.to_query}"
|
||||
|
||||
# It presents the user with a log-in page
|
||||
@ -202,18 +199,17 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
|
||||
# Filling in the correct TOTP code redirects to an app authorization page
|
||||
fill_in_otp_details(user.current_otp)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_authorize_text)
|
||||
|
||||
# It grants the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be true
|
||||
expect { click_on oauth_authorize_text }
|
||||
.to change { user_has_grant_with_client_app? }.to(true)
|
||||
|
||||
# Upon authorizing, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
|
||||
it 'when rejecting the authorization request' do
|
||||
params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
|
||||
visit "/oauth/authorize?#{params.to_query}"
|
||||
|
||||
# It presents the user with a log-in page
|
||||
@ -233,14 +229,14 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
|
||||
# Filling in the correct TOTP code redirects to an app authorization page
|
||||
fill_in_otp_details(user.current_otp)
|
||||
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
|
||||
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
expect(page).to have_content(oauth_authorize_text)
|
||||
|
||||
# It does not grant the app access to the account
|
||||
expect(Doorkeeper::AccessGrant.exists?(application: client_app, resource_owner_id: user.id)).to be false
|
||||
expect { click_on oauth_deny_text }
|
||||
.to_not change { user_has_grant_with_client_app? }.from(false)
|
||||
|
||||
# Upon denying, it redirects to the apps' callback URL
|
||||
expect(page).to redirect_to_callback_url
|
||||
end
|
||||
end
|
||||
# TODO: external auth
|
||||
@ -252,4 +248,24 @@ RSpec.describe 'Using OAuth from an external app' do
|
||||
fill_in 'user_otp_attempt', with: value
|
||||
click_on I18n.t('auth.login')
|
||||
end
|
||||
|
||||
def oauth_authorize_text
|
||||
I18n.t('doorkeeper.authorizations.buttons.authorize')
|
||||
end
|
||||
|
||||
def oauth_deny_text
|
||||
I18n.t('doorkeeper.authorizations.buttons.deny')
|
||||
end
|
||||
|
||||
def redirect_to_callback_url
|
||||
have_current_path(/\A#{client_app.redirect_uri}/, url: true)
|
||||
end
|
||||
|
||||
def user_has_grant_with_client_app?
|
||||
Doorkeeper::AccessGrant
|
||||
.exists?(
|
||||
application: client_app,
|
||||
resource_owner_id: user.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
532
yarn.lock
532
yarn.lock
@ -1533,13 +1533,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/cascade-layer-name-parser@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@csstools/cascade-layer-name-parser@npm:2.0.1"
|
||||
"@csstools/cascade-layer-name-parser@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/cascade-layer-name-parser@npm:2.0.2"
|
||||
peerDependencies:
|
||||
"@csstools/css-parser-algorithms": ^3.0.1
|
||||
"@csstools/css-tokenizer": ^3.0.1
|
||||
checksum: 10c0/e1f9030285d1a16ca0424018289e5288e58dee2d6f6cc392e27d9e8eca0deeea4ced9b749eef09a8322746cb15b6304bc7e2d04bb9dc7405c29b3717ec80e736
|
||||
"@csstools/css-parser-algorithms": ^3.0.2
|
||||
"@csstools/css-tokenizer": ^3.0.2
|
||||
checksum: 10c0/2cc840445328400bb3e1e4186e6081e6519a23d9abde36a16c95892b6ad75155b3af3410d79fdda1c53a068384f970cabff4b5f5ba6867578168cbd3419016c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1550,42 +1550,42 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/css-calc@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@csstools/css-calc@npm:2.0.1"
|
||||
"@csstools/css-calc@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/css-calc@npm:2.0.2"
|
||||
peerDependencies:
|
||||
"@csstools/css-parser-algorithms": ^3.0.1
|
||||
"@csstools/css-tokenizer": ^3.0.1
|
||||
checksum: 10c0/84c0ba3dac51466c9ac22c3540360f6058cf351a3676d71d4412584b165a91abc7c69a4ddf5a5dacc6e6082806d2317cf50ddbc0a0562275b2aedaee41cb87a9
|
||||
"@csstools/css-parser-algorithms": ^3.0.2
|
||||
"@csstools/css-tokenizer": ^3.0.2
|
||||
checksum: 10c0/b36e655b4abc8ea39b300725e33cd43b1875d759dd60bee8155bf7841065615a7f24cf53199382e30aa10bb137f64021043e4af7e11b7199b674a6e6cf3ccd01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/css-color-parser@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/css-color-parser@npm:3.0.2"
|
||||
"@csstools/css-color-parser@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@csstools/css-color-parser@npm:3.0.3"
|
||||
dependencies:
|
||||
"@csstools/color-helpers": "npm:^5.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.2"
|
||||
peerDependencies:
|
||||
"@csstools/css-parser-algorithms": ^3.0.1
|
||||
"@csstools/css-tokenizer": ^3.0.1
|
||||
checksum: 10c0/31f42cc22426c937f5c6999889f72b40aec8504189a6badf3319552f27a5af73dd5f46be9ebc54eb87e526468eb2546ffbd60a6879fe599efa6c98e51d6cfa3d
|
||||
"@csstools/css-parser-algorithms": ^3.0.2
|
||||
"@csstools/css-tokenizer": ^3.0.2
|
||||
checksum: 10c0/02367ffc222254132c47f9cbc856f65fe0b81ee4a5e7381251b95c4064138b5ed99a5e5a79c0c8689f9e75e3d900f94773258a161a97f467c3f0420838c10e04
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/css-parser-algorithms@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@csstools/css-parser-algorithms@npm:3.0.1"
|
||||
"@csstools/css-parser-algorithms@npm:^3.0.1, @csstools/css-parser-algorithms@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/css-parser-algorithms@npm:3.0.2"
|
||||
peerDependencies:
|
||||
"@csstools/css-tokenizer": ^3.0.1
|
||||
checksum: 10c0/064c6d519197b5af43bbf5efe8f4cdbd361b006113aa82160d637e925b50c643a52d33d512ca01c63042d952d723a2a10798231a714668356b76668fb11294e3
|
||||
"@csstools/css-tokenizer": ^3.0.2
|
||||
checksum: 10c0/246afbf518ee9eaa24ed7f083360eb66884f1172fd4f8c663bff8c6099de2a8abd1e2a31d5b6fe42e010277d238469d780cff62bc7fdc6a52e7a90626b8924dc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/css-tokenizer@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@csstools/css-tokenizer@npm:3.0.1"
|
||||
checksum: 10c0/c9ed4373e5731b5375ea9791590081019c04e95f08b46b272977e5e7b8c3d560affc62e82263cb8def1df1e57f0673140e7e16a14a5e7be04e6a234be088d1d3
|
||||
"@csstools/css-tokenizer@npm:^3.0.1, @csstools/css-tokenizer@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/css-tokenizer@npm:3.0.2"
|
||||
checksum: 10c0/a74e5829420ed35982fd33be272c2a19cb2380179d357abe750aa848be6d6699d0437008f47a57eb7c6ff64a34b0c8f91a97dd63dbddd08249b7cf7983767e5e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1599,6 +1599,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/media-query-list-parser@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "@csstools/media-query-list-parser@npm:4.0.0"
|
||||
peerDependencies:
|
||||
"@csstools/css-parser-algorithms": ^3.0.2
|
||||
"@csstools/css-tokenizer": ^3.0.2
|
||||
checksum: 10c0/416417bcfd84c18a2df8dc77f31c87830e151dc20530fe7f0d8f13a0848b1a9090858abdf7792d82bf2edb41ddedb7b57b34eb78b68b5c10755ae02c019e496a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-cascade-layers@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "@csstools/postcss-cascade-layers@npm:5.0.0"
|
||||
@ -1611,60 +1621,60 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-color-function@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "@csstools/postcss-color-function@npm:4.0.2"
|
||||
"@csstools/postcss-color-function@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "@csstools/postcss-color-function@npm:4.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/c987ccc7ab326668895396d3fe69c05087cf6e245be6f70e8c33da0cdeb56f8ac3d117cfad984191ec57be9691ab56d427aaa28c61c4a7446521972993dd5039
|
||||
checksum: 10c0/c994660ca0e2652755d9ad181c8cb46a07220c972086c97c843fa9bacf690be10c642770f898aeec4acc47c2b718dfc7372107285a678361f34d84d9e9c11e0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-color-mix-function@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/postcss-color-mix-function@npm:3.0.2"
|
||||
"@csstools/postcss-color-mix-function@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@csstools/postcss-color-mix-function@npm:3.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/cfdc641f504f9d02b9a7b53d6bd933d4e767ecaee5f3d2df45d897f69b8a38b5b79b538d307b16fb56dcb7c19dc7e107518c356772e89771e28e04fd846d9035
|
||||
checksum: 10c0/4ba358eb9030fc485bfe2922d897eeb712725762cc399eaba60ba665c84dc3e56a4d5a52dfb320093c0b217d32fedb9b5197fa45738cade53d9afcbefdadf04f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-content-alt-text@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@csstools/postcss-content-alt-text@npm:2.0.1"
|
||||
"@csstools/postcss-content-alt-text@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/postcss-content-alt-text@npm:2.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/693e4cfa9a30a9c384120bd24846a7cd5ba1e1ebf975eb81b0e0131a21ac28a0301c7dcfa13706bc7d8b5343536fb43a46de636c3257d0fd05041c7255366e87
|
||||
checksum: 10c0/e52d40f6567b9b23b32a6c40f9b2a74d57f99a9921b4cae015f51f72453474236c760bb13120682f8815698a615e0ad7bed22314c29dca89c34b5480d83a7a6d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-exponential-functions@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@csstools/postcss-exponential-functions@npm:2.0.1"
|
||||
"@csstools/postcss-exponential-functions@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/postcss-exponential-functions@npm:2.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-calc": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/ddcaedfa48cc0cf93611c8d2ed5a75d56c1d196a97015db644b45881adabb47f3255242acaef6ea869a1e5ba66328725d254bf6d29eb5e988cde8b040bc5f55d
|
||||
checksum: 10c0/034ff89089872f63a6b00bda670c5ff11361babd221ed3e441dde969a718059e5d44ab0ed331868f137bb205331b808ecbcc4cb641d5c945238ebca28aa3ed59
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1680,46 +1690,46 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-gamut-mapping@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/postcss-gamut-mapping@npm:2.0.2"
|
||||
"@csstools/postcss-gamut-mapping@npm:^2.0.3":
|
||||
version: 2.0.3
|
||||
resolution: "@csstools/postcss-gamut-mapping@npm:2.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/8b6504f81c5036e3c2a9f9516c371f48a283112469b746546c8c7f6f0da2467c915d4dac6dfe8bb05d7dab3a7503911391eb9e666cb7632e09a032e801c029f5
|
||||
checksum: 10c0/21f5708f63e9c3b7603f8b72b5f288e0a021e9710a6abf4aaa713ff4d04bae057d1861e1f28d7670ea39ba463ac04f1507876d4a11178934e7cc7a1c6a780084
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-gradients-interpolation-method@npm:^5.0.2":
|
||||
version: 5.0.2
|
||||
resolution: "@csstools/postcss-gradients-interpolation-method@npm:5.0.2"
|
||||
"@csstools/postcss-gradients-interpolation-method@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "@csstools/postcss-gradients-interpolation-method@npm:5.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/4fa27437ad9861b1457c28228f2503c17bcc2f77dcb38da1314a4a5d38fd010e7e5d11b5f9d69e0a2cb2999bbfeca1e99ce2f59422bda5b382658dcb03f7326e
|
||||
checksum: 10c0/062d27148438309c940a1973bfc7d42a06caa9397bf2382c7a61979f5be3d6f3fae1bc8ddf94d2dd8e6c807e0530a9e76179510266aaddc439677bf79447a765
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-hwb-function@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "@csstools/postcss-hwb-function@npm:4.0.2"
|
||||
"@csstools/postcss-hwb-function@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "@csstools/postcss-hwb-function@npm:4.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/46dc9596e37830de4c38f70764d6da9f2fc7bc339217b4291eced75daa8998c4e05fb743c271701e44818df4ac111c285019b7bb3a728e8b61d86899bbeb74eb
|
||||
checksum: 10c0/faf2bfbafeec765391e37c7a5cbc7b4647d9ab1ffa51e922c7dfffa545c3d436d15604dfdfb9d7684e760042e62bb42e0243dd4ebd8c3c14694a9f7be4e57b30
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1757,17 +1767,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-light-dark-function@npm:^2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "@csstools/postcss-light-dark-function@npm:2.0.4"
|
||||
"@csstools/postcss-light-dark-function@npm:^2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "@csstools/postcss-light-dark-function@npm:2.0.5"
|
||||
dependencies:
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/0176422ad9747953964b1ceff002df1ecb1952ebc481db6192070d68777135b582ea6fd32ae819b9c64c96cb9170bd6907c647c85b48daa4984b7ed3d7f9bccb
|
||||
checksum: 10c0/80635ee312d2a8f42aa5ce6792f1dc4a71199c384c66a3270d37e998d96db55beaa6836d689cda3b7e4828227960582fae04659ba5e4e0f64fd4543cbf15c6ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1809,42 +1819,42 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-logical-viewport-units@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@csstools/postcss-logical-viewport-units@npm:3.0.1"
|
||||
"@csstools/postcss-logical-viewport-units@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/postcss-logical-viewport-units@npm:3.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/f54f91ec4d308562371576e82131c3cc1ff461a951c9a38f0b42b783c26f37a93cc846fcd025d3c4a8437b55a4fff1192ebfac8ccf84abb6478b2c515d232552
|
||||
checksum: 10c0/31f525e774bc053f545a159eb53bb21465ea2930118e87c40207ad90fa97d3151e6de83efd02f84803fb0e93ed4a4b42a3904b734423410e73ac4c6ce9666ab4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-media-minmax@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@csstools/postcss-media-minmax@npm:2.0.1"
|
||||
"@csstools/postcss-media-minmax@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@csstools/postcss-media-minmax@npm:2.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-calc": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/media-query-list-parser": "npm:^3.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/media-query-list-parser": "npm:^4.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/23c1fb0c3ed8bf82f3223f161d0d65ba62045b917bc19624581f64aaa5d678485d22c23af2591a3f634ba02030ccb419c2b30209aa22f9fd2baa1a6474af810a
|
||||
checksum: 10c0/83cf10742884fca3baa7ae26e2cb34123ce5a022622390566c139b4587ea8583fab00acbb85545786b36398e2201d2a94301e0fae805e55f375f1b5c38f67ce8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:3.0.1"
|
||||
"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:3.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/media-query-list-parser": "npm:^3.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/media-query-list-parser": "npm:^4.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/e491cb149fb4fff85b2f03191511e43654ae00716e3c1ea9f1dc22ec4e7042c35f034d372082a69d3621c86cafbe46e8f419872fa36f4a534f145f584d655768
|
||||
checksum: 10c0/3ac4073d2e958bfb24ae45f673070dd805f0fcf07bc8d00a9a98f596d1096e7be282c8d8e87df3abde90f33fcbe2c7705e972b8c1a58e43ec44729f470b76096
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1871,18 +1881,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-oklab-function@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "@csstools/postcss-oklab-function@npm:4.0.2"
|
||||
"@csstools/postcss-oklab-function@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "@csstools/postcss-oklab-function@npm:4.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/3209a7cec6d3577544a7ef41f2d5cca25f77891d4ec0d7f39d32f9a79a6c9a9b0ee6b54b2937a2d995548ad11c39966b07d4b9f58e907ffbe1a4b454f2d277f3
|
||||
checksum: 10c0/650bcb4f664308972588a8f789f806d63c4069e2e008cfc3b5c80bf9df992c62972dce279b8f434c7f78823e97095942ee4f0e37bc549258887213e72acb7ef8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1897,18 +1907,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-relative-color-syntax@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "@csstools/postcss-relative-color-syntax@npm:3.0.2"
|
||||
"@csstools/postcss-relative-color-syntax@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@csstools/postcss-relative-color-syntax@npm:3.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/34a8c999e08c6e7833484ee2fb91e7fcc25235d6c361712fed581e44a5a29f1ceb95415b6f4260de53809ac13f5da5415d1905c2971477cf5d45e5196081c663
|
||||
checksum: 10c0/c241fe6b725d775f6d2085be1dff3868d189b176fa91ab1eb1133e30e30c8151bded4e50d17a845edd0bdd0a7adf9e8883cb2634fea3394872591fe9ad2a7e86
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1923,16 +1933,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-stepped-value-functions@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "@csstools/postcss-stepped-value-functions@npm:4.0.1"
|
||||
"@csstools/postcss-stepped-value-functions@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "@csstools/postcss-stepped-value-functions@npm:4.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-calc": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/7e65969b124fce603675ca17c2ffa2bb456677866e54bc9fbdc4da0945be1593fde2abb0730d3d03190776ad2022b394a1f9d4834c5b1f4c7ec497929fd35f8f
|
||||
checksum: 10c0/444a27d725bc7a8e1554469e8ac69e248ff525b728fbe058523b0f1aefcff80ca707f543d21fead0a22d51603b1669190fb01f0f2dcd599a01768a37e0d62bc3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1948,16 +1958,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@csstools/postcss-trigonometric-functions@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "@csstools/postcss-trigonometric-functions@npm:4.0.1"
|
||||
"@csstools/postcss-trigonometric-functions@npm:^4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "@csstools/postcss-trigonometric-functions@npm:4.0.2"
|
||||
dependencies:
|
||||
"@csstools/css-calc": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-calc": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/59e017ebb9f4f8f027e134024e3322b5e202cc96073e0bb0d45733a829c8eadc7f4f7ce57ce8360a748a677595af9ea95da1779684699b48b911b73b4017ac8b
|
||||
checksum: 10c0/eaecb2ea891162e4fcbbccf4f660c99e9e59f21937b70fe6aec3b51441eff2a12c1a2dc13fff426722629a7929919fd866311eaa68d74ee9d1f5387a23502fe2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -2257,8 +2267,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/cli@npm:^6.1.1":
|
||||
version: 6.2.12
|
||||
resolution: "@formatjs/cli@npm:6.2.12"
|
||||
version: 6.2.15
|
||||
resolution: "@formatjs/cli@npm:6.2.15"
|
||||
peerDependencies:
|
||||
"@glimmer/env": ^0.1.7
|
||||
"@glimmer/reference": ^0.91.1 || ^0.92.0
|
||||
@ -2287,7 +2297,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
formatjs: bin/formatjs
|
||||
checksum: 10c0/3bd05a9fad6c837e22988e6638f426c128efa46ab80ff88cf2ad81fb3bc10cf4f228907577fc01e24c2d7d505cfabfaa69f0496d2ec8f0ab2d6b5eaccb5e475c
|
||||
checksum: 10c0/e947aa7f3994251392fe15673752a8d8e3c8a30733bb49de5e617d45a327a3e1d16419e2d6b01f7ef2cbe86e2946024342d5b3301e6a8f17de3de9e2e7aedb29
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3113,8 +3123,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@reduxjs/toolkit@npm:^2.0.1":
|
||||
version: 2.2.7
|
||||
resolution: "@reduxjs/toolkit@npm:2.2.7"
|
||||
version: 2.2.8
|
||||
resolution: "@reduxjs/toolkit@npm:2.2.8"
|
||||
dependencies:
|
||||
immer: "npm:^10.0.3"
|
||||
redux: "npm:^5.0.1"
|
||||
@ -3128,7 +3138,7 @@ __metadata:
|
||||
optional: true
|
||||
react-redux:
|
||||
optional: true
|
||||
checksum: 10c0/7761a91adac2b5e1d50a8163ba5441480bb86a3a80b7583037c27a88463394b132dd7592862fc2be03aa7ab98a6e1710549889986dc0d3f033c169a3ba2cb02e
|
||||
checksum: 10c0/bf1356d71bfb82e5a181692c79c19b7bc19355260a9966f6562604c995f0cd0ce1154177ccd14095e8b319e73f64cfe86a4e46a83d24edba7876d4ae71fd5ae0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6402,10 +6412,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cookie@npm:0.6.0":
|
||||
version: 0.6.0
|
||||
resolution: "cookie@npm:0.6.0"
|
||||
checksum: 10c0/f2318b31af7a31b4ddb4a678d024514df5e705f9be5909a192d7f116cfb6d45cbacf96a473fa733faa95050e7cff26e7832bb3ef94751592f1387b71c8956686
|
||||
"cookie@npm:0.7.1":
|
||||
version: 0.7.1
|
||||
resolution: "cookie@npm:0.7.1"
|
||||
checksum: 10c0/5de60c67a410e7c8dc8a46a4b72eb0fe925871d057c9a5d2c0e8145c4270a4f81076de83410c4d397179744b478e33cd80ccbcc457abf40a9409ad27dcd21dde
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6622,10 +6632,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-functions-list@npm:^3.2.2":
|
||||
version: 3.2.2
|
||||
resolution: "css-functions-list@npm:3.2.2"
|
||||
checksum: 10c0/8638a63d0cf1bdc50d4a752ec1c94a57e9953c3b03eace4f5526db20bec3c061e95089f905dbb4999c44b9780ce777ba856967560f6d15119a303f6030901c10
|
||||
"css-functions-list@npm:^3.2.3":
|
||||
version: 3.2.3
|
||||
resolution: "css-functions-list@npm:3.2.3"
|
||||
checksum: 10c0/03f9ed34eeed310d2b1cf0e524eea02bc5f87854a4de85f8957ea432ab1036841a3fb00879590519f7bb8fda40d992ce7a72fa9b61696ca1dc53b90064858f96
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6733,6 +6743,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-tree@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "css-tree@npm:3.0.0"
|
||||
dependencies:
|
||||
mdn-data: "npm:2.10.0"
|
||||
source-map-js: "npm:^1.0.1"
|
||||
checksum: 10c0/43d44fdf7004ae91d73d486f17894fef77efa33747a6752b9241cf0f5fb47fabc16ec34a96a993651d9014dfdeee803d7c5fcd3548214252ee19f4e5c98999b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-tree@npm:~2.2.0":
|
||||
version: 2.2.1
|
||||
resolution: "css-tree@npm:2.2.1"
|
||||
@ -6982,15 +7002,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:~4.3.6":
|
||||
version: 4.3.6
|
||||
resolution: "debug@npm:4.3.6"
|
||||
"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.3.7, debug@npm:~4.3.6":
|
||||
version: 4.3.7
|
||||
resolution: "debug@npm:4.3.7"
|
||||
dependencies:
|
||||
ms: "npm:2.1.2"
|
||||
ms: "npm:^2.1.3"
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
checksum: 10c0/3293416bff072389c101697d4611c402a6bacd1900ac20c0492f61a9cdd6b3b29750fc7f5e299f8058469ef60ff8fb79b86395a30374fbd2490113c1c7112285
|
||||
checksum: 10c0/1471db19c3b06d485a622d62f65947a19a23fbd0dd73f7fd3eafb697eec5360cde447fb075919987899b1a2096e85d35d4eb5a4de09a57600ac9cf7e6c8e768b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8413,15 +8433,15 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"express@npm:^4.17.1, express@npm:^4.18.2":
|
||||
version: 4.21.0
|
||||
resolution: "express@npm:4.21.0"
|
||||
version: 4.21.1
|
||||
resolution: "express@npm:4.21.1"
|
||||
dependencies:
|
||||
accepts: "npm:~1.3.8"
|
||||
array-flatten: "npm:1.1.1"
|
||||
body-parser: "npm:1.20.3"
|
||||
content-disposition: "npm:0.5.4"
|
||||
content-type: "npm:~1.0.4"
|
||||
cookie: "npm:0.6.0"
|
||||
cookie: "npm:0.7.1"
|
||||
cookie-signature: "npm:1.0.6"
|
||||
debug: "npm:2.6.9"
|
||||
depd: "npm:2.0.0"
|
||||
@ -8447,7 +8467,7 @@ __metadata:
|
||||
type-is: "npm:~1.6.18"
|
||||
utils-merge: "npm:1.0.1"
|
||||
vary: "npm:~1.1.2"
|
||||
checksum: 10c0/4cf7ca328f3fdeb720f30ccb2ea7708bfa7d345f9cc460b64a82bf1b2c91e5b5852ba15a9a11b2a165d6089acf83457fc477dc904d59cd71ed34c7a91762c6cc
|
||||
checksum: 10c0/0c287867e5f6129d3def1edd9b63103a53c40d4dc8628839d4b6827e35eb8f0de5a4656f9d85f4457eba584f9871ebb2ad26c750b36bd75d9bbb8bcebdc4892c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8591,12 +8611,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"file-entry-cache@npm:^9.0.0":
|
||||
version: 9.0.0
|
||||
resolution: "file-entry-cache@npm:9.0.0"
|
||||
"file-entry-cache@npm:^9.1.0":
|
||||
version: 9.1.0
|
||||
resolution: "file-entry-cache@npm:9.1.0"
|
||||
dependencies:
|
||||
flat-cache: "npm:^5.0.0"
|
||||
checksum: 10c0/07b0a4f062dc0aa258f3e1b06ac083ea25313f5e289943e146fafdaf3315dcc031635545eea7fe98fe5598b91d6c7f48dba7a251dd7ac20108a6ebf7d00b0b1c
|
||||
checksum: 10c0/4b4dbc1e972f50202b1a4430d30fd99378ef6e2a64857176abdc65c5e4730a948fb37e274478520a7bacbc70f3abba455a4b9d2c1915c53f30d11dc85d3fef5e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8948,9 +8968,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"fuzzysort@npm:^3.0.0":
|
||||
version: 3.0.2
|
||||
resolution: "fuzzysort@npm:3.0.2"
|
||||
checksum: 10c0/c6cdbd092a8e91ed822aeac6d4fb95559759c10602cb29f27307c1cabd01fdd384fa399f7757722435b595244efb000cd63f144104c41b8551b2faff123279cb
|
||||
version: 3.1.0
|
||||
resolution: "fuzzysort@npm:3.1.0"
|
||||
checksum: 10c0/da9bb32de16f2a5c2c000b99031d9f4f8a01380c12d5d3b67296443a1152c55987ce3c4ddbfe97481b0e9b6f2fb77d61dceba29a93ad36ee23ef5bab6a31afb8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9670,13 +9690,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^5.2.0, ignore@npm:^5.3.1, ignore@npm:^5.3.2":
|
||||
"ignore@npm:^5.2.0, ignore@npm:^5.3.1":
|
||||
version: 5.3.2
|
||||
resolution: "ignore@npm:5.3.2"
|
||||
checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^6.0.2":
|
||||
version: 6.0.2
|
||||
resolution: "ignore@npm:6.0.2"
|
||||
checksum: 10c0/9a38feac1861906a78ba0f03e8ef3cd6b0526dce2a1a84e1009324b557763afeb9c3ebcc04666b21f7bbf71adda45e76781bb9e2eaa0903d45dcaded634454f5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"immer@npm:^10.0.3":
|
||||
version: 10.0.3
|
||||
resolution: "immer@npm:10.0.3"
|
||||
@ -11842,6 +11869,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mdn-data@npm:2.10.0":
|
||||
version: 2.10.0
|
||||
resolution: "mdn-data@npm:2.10.0"
|
||||
checksum: 10c0/f6f1a6a6eb092bab250d06f6f6c7cb1733a77a17e7119aac829ad67d4322bbf6a30df3c6d88686e71942e66bd49274b2ddfede22a1d3df0d6c49a56fbd09eb7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-typer@npm:0.3.0":
|
||||
version: 0.3.0
|
||||
resolution: "media-typer@npm:0.3.0"
|
||||
@ -12221,14 +12255,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ms@npm:2.1.2":
|
||||
version: 2.1.2
|
||||
resolution: "ms@npm:2.1.2"
|
||||
checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ms@npm:2.1.3, ms@npm:^2.1.1":
|
||||
"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "ms@npm:2.1.3"
|
||||
checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
|
||||
@ -13376,18 +13403,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-color-functional-notation@npm:^7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "postcss-color-functional-notation@npm:7.0.2"
|
||||
"postcss-color-functional-notation@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "postcss-color-functional-notation@npm:7.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/e89c0bff94558b0c978ac36f7e02f7f516291f90fd43169d39c63ad2bb0415e3b1c4b3c2469280d578727e850fdf15a557230cb28275f3f0676f0f73187f2867
|
||||
checksum: 10c0/5e04c81002512c960784043c096bc91ebc76b8fddb9259a2418b0e121eb65042944cc0f78946f6b7e5774ff1fee087849019655e4848af1f88879e3ab9ff7c17
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -13441,46 +13468,46 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-custom-media@npm:^11.0.2":
|
||||
version: 11.0.2
|
||||
resolution: "postcss-custom-media@npm:11.0.2"
|
||||
"postcss-custom-media@npm:^11.0.3":
|
||||
version: 11.0.3
|
||||
resolution: "postcss-custom-media@npm:11.0.3"
|
||||
dependencies:
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/media-query-list-parser": "npm:^3.0.1"
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/media-query-list-parser": "npm:^4.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/7bec2b1e0b5d786c33c5715b611ffc8b9737252ee6bf77ca59255ac16f91ce614406923f43250e5c88b04f1bb050f155dc5ed4d9350dbd704c45fbd72e5a9a04
|
||||
checksum: 10c0/bd3f0cf17d7422385d26afed510dc2acebb1d8c25fce13e2bbee1c49cdc7fe95ebe7f50b89ef0a88ebdd5f6826e89d99e26b905881ceff788df655670dba93d8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-custom-properties@npm:^14.0.1":
|
||||
version: 14.0.1
|
||||
resolution: "postcss-custom-properties@npm:14.0.1"
|
||||
"postcss-custom-properties@npm:^14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "postcss-custom-properties@npm:14.0.2"
|
||||
dependencies:
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
postcss-value-parser: "npm:^4.2.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/12180a7f4a4fe2d528387346a1810b82ed870081756dcf6be226c839716ab3f6f4d6ca4c7208a07d7d84bf2c986beef6473e29964e7c2572066fca5d3b000ed5
|
||||
checksum: 10c0/ea2e0cb60c558bb1afb4e601dcc64a38e1b28e5df3e47b83b858fc12d909d0e3453013e6b368fc05a7db7098ffcdc702a30a92f1a3c0ef67dfb97bf089021f1a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-custom-selectors@npm:^8.0.1":
|
||||
version: 8.0.1
|
||||
resolution: "postcss-custom-selectors@npm:8.0.1"
|
||||
"postcss-custom-selectors@npm:^8.0.2":
|
||||
version: 8.0.2
|
||||
resolution: "postcss-custom-selectors@npm:8.0.2"
|
||||
dependencies:
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.1"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/cascade-layer-name-parser": "npm:^2.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
postcss-selector-parser: "npm:^6.1.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/b867233b3d68fbab90afca8a776eb74196ebc3fac8988175d95118a47993c793138fec6cc580272bb35d9bd31086acbdd33ff86da0cab83ef2f08bfc1c23ecd6
|
||||
checksum: 10c0/81673ffb0874f63c0f5e14315a5808259ec80ae8452aaf10d28112d30a9aaabbf61d13edb02f8be2965f44b943968c7eda051a1693da436ef157e77fcff0d752
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -13598,18 +13625,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-lab-function@npm:^7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "postcss-lab-function@npm:7.0.2"
|
||||
"postcss-lab-function@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "postcss-lab-function@npm:7.0.3"
|
||||
dependencies:
|
||||
"@csstools/css-color-parser": "npm:^3.0.2"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
"@csstools/css-color-parser": "npm:^3.0.3"
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.2"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.2"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/utilities": "npm:^2.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/6b2be7e762b4ccb58ea9051723d390f6732ad78bb30bfef9499139cf5e2ac160c3de31b2b005fcc30e9fced4abe1685df6cb76c99d548896bae6746105ac8520
|
||||
checksum: 10c0/c50a73a9ed54b4194998c4627599d1f42074235f572edbbcdb0e00717f3ae2121dc8378d917792b281860c5650a617d923823da6f395515f610b5760d115354d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -13930,38 +13957,38 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"postcss-preset-env@npm:^10.0.0":
|
||||
version: 10.0.6
|
||||
resolution: "postcss-preset-env@npm:10.0.6"
|
||||
version: 10.0.7
|
||||
resolution: "postcss-preset-env@npm:10.0.7"
|
||||
dependencies:
|
||||
"@csstools/postcss-cascade-layers": "npm:^5.0.0"
|
||||
"@csstools/postcss-color-function": "npm:^4.0.2"
|
||||
"@csstools/postcss-color-mix-function": "npm:^3.0.2"
|
||||
"@csstools/postcss-content-alt-text": "npm:^2.0.1"
|
||||
"@csstools/postcss-exponential-functions": "npm:^2.0.1"
|
||||
"@csstools/postcss-color-function": "npm:^4.0.3"
|
||||
"@csstools/postcss-color-mix-function": "npm:^3.0.3"
|
||||
"@csstools/postcss-content-alt-text": "npm:^2.0.2"
|
||||
"@csstools/postcss-exponential-functions": "npm:^2.0.2"
|
||||
"@csstools/postcss-font-format-keywords": "npm:^4.0.0"
|
||||
"@csstools/postcss-gamut-mapping": "npm:^2.0.2"
|
||||
"@csstools/postcss-gradients-interpolation-method": "npm:^5.0.2"
|
||||
"@csstools/postcss-hwb-function": "npm:^4.0.2"
|
||||
"@csstools/postcss-gamut-mapping": "npm:^2.0.3"
|
||||
"@csstools/postcss-gradients-interpolation-method": "npm:^5.0.3"
|
||||
"@csstools/postcss-hwb-function": "npm:^4.0.3"
|
||||
"@csstools/postcss-ic-unit": "npm:^4.0.0"
|
||||
"@csstools/postcss-initial": "npm:^2.0.0"
|
||||
"@csstools/postcss-is-pseudo-class": "npm:^5.0.0"
|
||||
"@csstools/postcss-light-dark-function": "npm:^2.0.4"
|
||||
"@csstools/postcss-light-dark-function": "npm:^2.0.5"
|
||||
"@csstools/postcss-logical-float-and-clear": "npm:^3.0.0"
|
||||
"@csstools/postcss-logical-overflow": "npm:^2.0.0"
|
||||
"@csstools/postcss-logical-overscroll-behavior": "npm:^2.0.0"
|
||||
"@csstools/postcss-logical-resize": "npm:^3.0.0"
|
||||
"@csstools/postcss-logical-viewport-units": "npm:^3.0.1"
|
||||
"@csstools/postcss-media-minmax": "npm:^2.0.1"
|
||||
"@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^3.0.1"
|
||||
"@csstools/postcss-logical-viewport-units": "npm:^3.0.2"
|
||||
"@csstools/postcss-media-minmax": "npm:^2.0.2"
|
||||
"@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^3.0.2"
|
||||
"@csstools/postcss-nested-calc": "npm:^4.0.0"
|
||||
"@csstools/postcss-normalize-display-values": "npm:^4.0.0"
|
||||
"@csstools/postcss-oklab-function": "npm:^4.0.2"
|
||||
"@csstools/postcss-oklab-function": "npm:^4.0.3"
|
||||
"@csstools/postcss-progressive-custom-properties": "npm:^4.0.0"
|
||||
"@csstools/postcss-relative-color-syntax": "npm:^3.0.2"
|
||||
"@csstools/postcss-relative-color-syntax": "npm:^3.0.3"
|
||||
"@csstools/postcss-scope-pseudo-class": "npm:^4.0.0"
|
||||
"@csstools/postcss-stepped-value-functions": "npm:^4.0.1"
|
||||
"@csstools/postcss-stepped-value-functions": "npm:^4.0.2"
|
||||
"@csstools/postcss-text-decoration-shorthand": "npm:^4.0.1"
|
||||
"@csstools/postcss-trigonometric-functions": "npm:^4.0.1"
|
||||
"@csstools/postcss-trigonometric-functions": "npm:^4.0.2"
|
||||
"@csstools/postcss-unset-value": "npm:^4.0.0"
|
||||
autoprefixer: "npm:^10.4.19"
|
||||
browserslist: "npm:^4.23.1"
|
||||
@ -13971,12 +13998,12 @@ __metadata:
|
||||
cssdb: "npm:^8.1.1"
|
||||
postcss-attribute-case-insensitive: "npm:^7.0.0"
|
||||
postcss-clamp: "npm:^4.1.0"
|
||||
postcss-color-functional-notation: "npm:^7.0.2"
|
||||
postcss-color-functional-notation: "npm:^7.0.3"
|
||||
postcss-color-hex-alpha: "npm:^10.0.0"
|
||||
postcss-color-rebeccapurple: "npm:^10.0.0"
|
||||
postcss-custom-media: "npm:^11.0.2"
|
||||
postcss-custom-properties: "npm:^14.0.1"
|
||||
postcss-custom-selectors: "npm:^8.0.1"
|
||||
postcss-custom-media: "npm:^11.0.3"
|
||||
postcss-custom-properties: "npm:^14.0.2"
|
||||
postcss-custom-selectors: "npm:^8.0.2"
|
||||
postcss-dir-pseudo-class: "npm:^9.0.0"
|
||||
postcss-double-position-gradients: "npm:^6.0.0"
|
||||
postcss-focus-visible: "npm:^10.0.0"
|
||||
@ -13984,7 +14011,7 @@ __metadata:
|
||||
postcss-font-variant: "npm:^5.0.0"
|
||||
postcss-gap-properties: "npm:^6.0.0"
|
||||
postcss-image-set-function: "npm:^7.0.0"
|
||||
postcss-lab-function: "npm:^7.0.2"
|
||||
postcss-lab-function: "npm:^7.0.3"
|
||||
postcss-logical: "npm:^8.0.0"
|
||||
postcss-nesting: "npm:^13.0.0"
|
||||
postcss-opacity-percentage: "npm:^3.0.0"
|
||||
@ -13996,7 +14023,7 @@ __metadata:
|
||||
postcss-selector-not: "npm:^8.0.0"
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
checksum: 10c0/01660acf3b9ddf4d612a31819e9a5de9fe5383e9eddd2c130180f66ae90c5a881eb408e73454fd50e1839eae71678d738bf72073de08f9013c183b0bd9950fe5
|
||||
checksum: 10c0/f789000e0504fd827e854bb0feb8b4c218d381314e4d863c5a36df925df412d0844c912952fe27892a320433640aeaff03ee94a3057b42011bf5d32b3963f333
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -14050,12 +14077,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-safe-parser@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "postcss-safe-parser@npm:7.0.0"
|
||||
"postcss-safe-parser@npm:^7.0.1":
|
||||
version: 7.0.1
|
||||
resolution: "postcss-safe-parser@npm:7.0.1"
|
||||
peerDependencies:
|
||||
postcss: ^8.4.31
|
||||
checksum: 10c0/4217afd8ce2809e959dc365e4675f499303cc6b91f94db06c8164422822db2d3b3124df701ee2234db4127ad05619b016bfb9c2bccae9bf9cf898a396f1632c9
|
||||
checksum: 10c0/6957b10b818bd8d4664ec0e548af967f7549abedfb37f844d389571d36af681340f41f9477b9ccf34bcc7599bdef222d1d72e79c64373001fae77089fba6d965
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -14119,7 +14146,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.41":
|
||||
"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.47":
|
||||
version: 8.4.47
|
||||
resolution: "postcss@npm:8.4.47"
|
||||
dependencies:
|
||||
@ -16717,8 +16744,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"stylelint@npm:^16.0.2":
|
||||
version: 16.9.0
|
||||
resolution: "stylelint@npm:16.9.0"
|
||||
version: 16.10.0
|
||||
resolution: "stylelint@npm:16.10.0"
|
||||
dependencies:
|
||||
"@csstools/css-parser-algorithms": "npm:^3.0.1"
|
||||
"@csstools/css-tokenizer": "npm:^3.0.1"
|
||||
@ -16728,17 +16755,17 @@ __metadata:
|
||||
balanced-match: "npm:^2.0.0"
|
||||
colord: "npm:^2.9.3"
|
||||
cosmiconfig: "npm:^9.0.0"
|
||||
css-functions-list: "npm:^3.2.2"
|
||||
css-tree: "npm:^2.3.1"
|
||||
debug: "npm:^4.3.6"
|
||||
css-functions-list: "npm:^3.2.3"
|
||||
css-tree: "npm:^3.0.0"
|
||||
debug: "npm:^4.3.7"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
fastest-levenshtein: "npm:^1.0.16"
|
||||
file-entry-cache: "npm:^9.0.0"
|
||||
file-entry-cache: "npm:^9.1.0"
|
||||
global-modules: "npm:^2.0.0"
|
||||
globby: "npm:^11.1.0"
|
||||
globjoin: "npm:^0.1.4"
|
||||
html-tags: "npm:^3.3.1"
|
||||
ignore: "npm:^5.3.2"
|
||||
ignore: "npm:^6.0.2"
|
||||
imurmurhash: "npm:^0.1.4"
|
||||
is-plain-object: "npm:^5.0.0"
|
||||
known-css-properties: "npm:^0.34.0"
|
||||
@ -16747,21 +16774,20 @@ __metadata:
|
||||
micromatch: "npm:^4.0.8"
|
||||
normalize-path: "npm:^3.0.0"
|
||||
picocolors: "npm:^1.0.1"
|
||||
postcss: "npm:^8.4.41"
|
||||
postcss: "npm:^8.4.47"
|
||||
postcss-resolve-nested-selector: "npm:^0.1.6"
|
||||
postcss-safe-parser: "npm:^7.0.0"
|
||||
postcss-safe-parser: "npm:^7.0.1"
|
||||
postcss-selector-parser: "npm:^6.1.2"
|
||||
postcss-value-parser: "npm:^4.2.0"
|
||||
resolve-from: "npm:^5.0.0"
|
||||
string-width: "npm:^4.2.3"
|
||||
strip-ansi: "npm:^7.1.0"
|
||||
supports-hyperlinks: "npm:^3.1.0"
|
||||
svg-tags: "npm:^1.0.0"
|
||||
table: "npm:^6.8.2"
|
||||
write-file-atomic: "npm:^5.0.1"
|
||||
bin:
|
||||
stylelint: bin/stylelint.mjs
|
||||
checksum: 10c0/d3ff9c8945c56b04a2fa16ec33d163325496d5db94b6fcb5adf74c76f7f794ac992888273f9a3317652ba8b6195168b2ffff382ca2a667a241e2ace8c9505ae2
|
||||
checksum: 10c0/d07dd156c225d16c740995daacd78090f7fc317602e87bda2fca323a4ae427a8526d724f3089df3b2185df4520f987547668ceea9b30985988ccbc514034aa21
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17406,22 +17432,22 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:5, typescript@npm:^5.0.4":
|
||||
version: 5.6.2
|
||||
resolution: "typescript@npm:5.6.2"
|
||||
version: 5.6.3
|
||||
resolution: "typescript@npm:5.6.3"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/3ed8297a8c7c56b7fec282532503d1ac795239d06e7c4966b42d4330c6cf433a170b53bcf93a130a7f14ccc5235de5560df4f1045eb7f3550b46ebed16d3c5e5
|
||||
checksum: 10c0/44f61d3fb15c35359bc60399cb8127c30bae554cd555b8e2b46d68fa79d680354b83320ad419ff1b81a0bdf324197b29affe6cc28988cd6a74d4ac60c94f9799
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>":
|
||||
version: 5.6.2
|
||||
resolution: "typescript@patch:typescript@npm%3A5.6.2#optional!builtin<compat/typescript>::version=5.6.2&hash=8c6c40"
|
||||
version: 5.6.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin<compat/typescript>::version=5.6.3&hash=8c6c40"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/94eb47e130d3edd964b76da85975601dcb3604b0c848a36f63ac448d0104e93819d94c8bdf6b07c00120f2ce9c05256b8b6092d23cf5cf1c6fa911159e4d572f
|
||||
checksum: 10c0/7c9d2e07c81226d60435939618c91ec2ff0b75fbfa106eec3430f0fcf93a584bc6c73176676f532d78c3594fe28a54b36eb40b3d75593071a7ec91301533ace7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17660,11 +17686,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"use-debounce@npm:^10.0.0":
|
||||
version: 10.0.3
|
||||
resolution: "use-debounce@npm:10.0.3"
|
||||
version: 10.0.4
|
||||
resolution: "use-debounce@npm:10.0.4"
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
checksum: 10c0/351b62c565d6dce5a21ecc21fe3e1f8db74f70c81c8f7d9dbdfc2da1cb82d883578589f6146e684d91dac534bc3c8b145ab1a36fbf4d44cbb4113827508b39aa
|
||||
checksum: 10c0/73494fc44b2bd58a7ec799a528fc20077c45fe2e94fedff6dcd88d136f7a39f417d77f584d5613aac615ed32aeb2ea393797ae1f7d5b2645eab57cb497a6d0cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user