diff --git a/cmd/gotosocial/action/testrig/testrig.go b/cmd/gotosocial/action/testrig/testrig.go index f6721d8b6..0036b7a7d 100644 --- a/cmd/gotosocial/action/testrig/testrig.go +++ b/cmd/gotosocial/action/testrig/testrig.go @@ -20,11 +20,9 @@ package testrig import ( - "bytes" "context" "errors" "fmt" - "io" "net/http" "os" "os/signal" @@ -160,16 +158,8 @@ testrig.StandardStorageSetup(state.Storage, "./testrig/media") // build backend handlers - transportController := testrig.NewTestTransportController(state, testrig.NewMockHTTPClient(func(req *http.Request) (*http.Response, error) { - r := io.NopCloser(bytes.NewReader([]byte{})) - return &http.Response{ - StatusCode: 200, - Body: r, - Header: http.Header{ - "Content-Type": req.Header.Values("Accept"), - }, - }, nil - }, "")) + httpClient := testrig.NewMockHTTPClient(nil, "./testrig/media") + transportController := testrig.NewTestTransportController(state, httpClient) mediaManager := testrig.NewTestMediaManager(state) federator := testrig.NewTestFederator(state, transportController, mediaManager) diff --git a/web/source/settings/components/pageable-list.tsx b/web/source/settings/components/pageable-list.tsx index 3571fb1cd..92c5e220d 100644 --- a/web/source/settings/components/pageable-list.tsx +++ b/web/source/settings/components/pageable-list.tsx @@ -30,7 +30,7 @@ export interface PageableListProps { items?: T[]; itemToEntry: (_item: T) => ReactNode; isLoading: boolean; - isFetching: boolean; + isFetching?: boolean; isError: boolean; error: FetchBaseQueryError | SerializedError | undefined; emptyMessage: ReactNode; diff --git a/web/source/settings/lib/query/admin/domain-permissions/subscriptions.ts b/web/source/settings/lib/query/admin/domain-permissions/subscriptions.ts index f065aaf54..fef512a56 100644 --- a/web/source/settings/lib/query/admin/domain-permissions/subscriptions.ts +++ b/web/source/settings/lib/query/admin/domain-permissions/subscriptions.ts @@ -20,6 +20,7 @@ import { gtsApi } from "../../gts-api"; import type { + DomainPerm, DomainPermSub, DomainPermSubCreateUpdateParams, DomainPermSubSearchParams, @@ -120,6 +121,13 @@ const extended = gtsApi.injectEndpoints({ asForm: true, body: { remove_children: remove_children }, }), + }), + + testDomainPermissionSubscription: build.mutation<{ error: string } | DomainPerm[], string>({ + query: (id) => ({ + method: "POST", + url: `/api/v1/admin/domain_permission_subscriptions/${id}/test`, + }), }) }), }); @@ -154,6 +162,11 @@ const useUpdateDomainPermissionSubscriptionMutation = extended.useUpdateDomainPe */ const useRemoveDomainPermissionSubscriptionMutation = extended.useRemoveDomainPermissionSubscriptionMutation; +/** + * Test a domain permission subscription to see if data can be fetched + parsed. + */ +const useTestDomainPermissionSubscriptionMutation = extended.useTestDomainPermissionSubscriptionMutation; + export { useLazySearchDomainPermissionSubscriptionsQuery, useGetDomainPermissionSubscriptionQuery, @@ -161,4 +174,5 @@ export { useGetDomainPermissionSubscriptionsPreviewQuery, useUpdateDomainPermissionSubscriptionMutation, useRemoveDomainPermissionSubscriptionMutation, + useTestDomainPermissionSubscriptionMutation, }; diff --git a/web/source/settings/style.css b/web/source/settings/style.css index bbb8fd61c..75e7e7e3f 100644 --- a/web/source/settings/style.css +++ b/web/source/settings/style.css @@ -1426,6 +1426,18 @@ button.tab-button { } } +.domain-permission-subscription-details { + > .list > .entries > .perm-preview { + gap: 0.5rem; + } + + > .perm-issue > b > code { + background: $info-bg; + padding: 0; + } +} + + .domain-permission-subscription-title { font-size: 1.2rem; font-weight: bold; @@ -1451,7 +1463,8 @@ button.tab-button { } } -.domain-permission-subscription-remove { +.domain-permission-subscription-remove, +.domain-permission-subscription-test { gap: 1rem; } diff --git a/web/source/settings/views/moderation/domain-permissions/subscriptions/detail.tsx b/web/source/settings/views/moderation/domain-permissions/subscriptions/detail.tsx index 408d81b92..06f1582ae 100644 --- a/web/source/settings/views/moderation/domain-permissions/subscriptions/detail.tsx +++ b/web/source/settings/views/moderation/domain-permissions/subscriptions/detail.tsx @@ -17,19 +17,20 @@ along with this program. If not, see . */ -import React, { useState } from "react"; +import React, { ReactNode, useState } from "react"; import { useLocation, useParams } from "wouter"; import { useBaseUrl } from "../../../../lib/navigation/util"; import BackButton from "../../../../components/back-button"; -import { useGetDomainPermissionSubscriptionQuery, useRemoveDomainPermissionSubscriptionMutation, useUpdateDomainPermissionSubscriptionMutation } from "../../../../lib/query/admin/domain-permissions/subscriptions"; +import { useGetDomainPermissionSubscriptionQuery, useRemoveDomainPermissionSubscriptionMutation, useTestDomainPermissionSubscriptionMutation, useUpdateDomainPermissionSubscriptionMutation } from "../../../../lib/query/admin/domain-permissions/subscriptions"; import { useBoolInput, useNumberInput, useTextInput } from "../../../../lib/form"; import FormWithData from "../../../../lib/form/form-with-data"; -import { DomainPermSub } from "../../../../lib/types/domain-permission"; +import { DomainPerm, DomainPermSub } from "../../../../lib/types/domain-permission"; import MutationButton from "../../../../components/form/mutation-button"; import { Checkbox, NumberInput, Select, TextInput } from "../../../../components/form/inputs"; import useFormSubmit from "../../../../lib/form/submit"; import UsernameLozenge from "../../../../components/username-lozenge"; import { urlValidator } from "../../../../lib/util/formvalidators"; +import { PageableList } from "../../../../components/pageable-list"; export default function DomainPermissionSubscriptionDetail() { const params = useParams(); @@ -56,6 +57,7 @@ function DomainPermSubForm({ data: permSub }: { data: DomainPermSub }) {

Domain Permission Subscription Detail

+ ); @@ -382,3 +384,73 @@ function DeleteDomainPermSub({ permSub, backLocation }: { permSub: DomainPermSub ); } + +function TestDomainPermSub({ permSub }: { permSub: DomainPermSub }) { + const permType = permSub.permission_type; + if (!permType) { + throw "permission_type was undefined"; + } + + const [ testSub, testRes ] = useTestDomainPermissionSubscriptionMutation(); + const onSubmit = (e) => { + e.preventDefault(); + testSub(permSub.id); + }; + + // Function to map an item to a list entry. + function itemToEntry(perm: DomainPerm): ReactNode { + return ( + + { perm.domain } + { perm.public_comment && <>({ perm.public_comment }) } + + ); + } + + return ( + <> +
+

Test Subscription

+ Click the "test" button to instruct your instance to do a test + fetch and parse of the {permType} list at the subscription URI. +
+ If the fetch is successful, you will see a list of {permType}s + (or {permType} drafts) that *would* be created by this subscription, + along with the public comment for each {permType} (if applicable). +
+ The test does not actually create those {permType}s in your database. + + + { testRes.data && "error" in testRes.data + ?
+ + + The following issue was encountered when doing a fetch + parse: +
{ testRes.data.error } +
This may be due to a temporary outage at the remote URL, + or you may wish to check your subscription settings and test again. +
+
+ : <> + { testRes.data && `${testRes.data?.length} ${permType}s would be created by this subscription:`} + No entries!} + /> + + } + + ); +}