mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Add project settings for intercept
This commit is contained in:
@ -17,7 +17,12 @@
|
|||||||
"prettier/prettier": ["error"],
|
"prettier/prettier": ["error"],
|
||||||
"@next/next/no-css-tags": "off",
|
"@next/next/no-css-tags": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"ignoreRestSiblings": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
"import/default": "off",
|
"import/default": "off",
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ export enum Page {
|
|||||||
ProxyLogs,
|
ProxyLogs,
|
||||||
Sender,
|
Sender,
|
||||||
Scope,
|
Scope,
|
||||||
|
Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 240;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import CancelIcon from "@mui/icons-material/Cancel";
|
import CancelIcon from "@mui/icons-material/Cancel";
|
||||||
import SendIcon from "@mui/icons-material/Send";
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material";
|
import SettingsIcon from "@mui/icons-material/Settings";
|
||||||
|
import { Alert, Box, Button, CircularProgress, IconButton, Tooltip, Typography } from "@mui/material";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
|
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
|
||||||
import { KeyValuePair, sortKeyValuePairs } from "lib/components/KeyValuePair";
|
import { KeyValuePair, sortKeyValuePairs } from "lib/components/KeyValuePair";
|
||||||
|
import Link from "lib/components/Link";
|
||||||
import RequestTabs from "lib/components/RequestTabs";
|
import RequestTabs from "lib/components/RequestTabs";
|
||||||
import Response from "lib/components/Response";
|
import Response from "lib/components/Response";
|
||||||
import SplitPane from "lib/components/SplitPane";
|
import SplitPane from "lib/components/SplitPane";
|
||||||
@ -201,6 +203,11 @@ function EditRequest(): JSX.Element {
|
|||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
<Tooltip title="Intercept settings">
|
||||||
|
<IconButton LinkComponent={Link} href="/settings#intercept">
|
||||||
|
<SettingsIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
{modifyResult.error && (
|
{modifyResult.error && (
|
||||||
<Alert severity="error" sx={{ mt: 1 }}>
|
<Alert severity="error" sx={{ mt: 1 }}>
|
||||||
|
@ -2,6 +2,7 @@ import CloseIcon from "@mui/icons-material/Close";
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import DescriptionIcon from "@mui/icons-material/Description";
|
import DescriptionIcon from "@mui/icons-material/Description";
|
||||||
import LaunchIcon from "@mui/icons-material/Launch";
|
import LaunchIcon from "@mui/icons-material/Launch";
|
||||||
|
import SettingsIcon from "@mui/icons-material/Settings";
|
||||||
import { Alert } from "@mui/lab";
|
import { Alert } from "@mui/lab";
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
@ -29,6 +30,7 @@ import React, { useState } from "react";
|
|||||||
|
|
||||||
import useOpenProjectMutation from "../hooks/useOpenProjectMutation";
|
import useOpenProjectMutation from "../hooks/useOpenProjectMutation";
|
||||||
|
|
||||||
|
import Link, { NextLinkComposed } from "lib/components/Link";
|
||||||
import {
|
import {
|
||||||
ProjectsQuery,
|
ProjectsQuery,
|
||||||
useCloseProjectMutation,
|
useCloseProjectMutation,
|
||||||
@ -179,6 +181,11 @@ function ProjectList(): JSX.Element {
|
|||||||
{project.name} {project.isActive && <em>(Active)</em>}
|
{project.name} {project.isActive && <em>(Active)</em>}
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
|
<Tooltip title="Project settings">
|
||||||
|
<IconButton LinkComponent={Link} href="/settings" disabled={!project.isActive}>
|
||||||
|
<SettingsIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
{project.isActive && (
|
{project.isActive && (
|
||||||
<Tooltip title="Close project">
|
<Tooltip title="Close project">
|
||||||
<IconButton onClick={() => closeProject()}>
|
<IconButton onClick={() => closeProject()}>
|
||||||
|
12
admin/src/features/projects/graphql/activeProject.graphql
Normal file
12
admin/src/features/projects/graphql/activeProject.graphql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
query ActiveProject {
|
||||||
|
activeProject {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
isActive
|
||||||
|
settings {
|
||||||
|
intercept {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,13 @@ import { Alert } from "@mui/lab";
|
|||||||
import { Badge, Button, IconButton, Tooltip } from "@mui/material";
|
import { Badge, Button, IconButton, Tooltip } from "@mui/material";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
|
import { useActiveProject } from "lib/ActiveProjectContext";
|
||||||
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
|
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
|
||||||
import { ConfirmationDialog, useConfirmationDialog } from "lib/components/ConfirmationDialog";
|
import { ConfirmationDialog, useConfirmationDialog } from "lib/components/ConfirmationDialog";
|
||||||
import { HttpRequestLogsDocument, useClearHttpRequestLogMutation } from "lib/graphql/generated";
|
import { HttpRequestLogsDocument, useClearHttpRequestLogMutation } from "lib/graphql/generated";
|
||||||
|
|
||||||
function Actions(): JSX.Element {
|
function Actions(): JSX.Element {
|
||||||
|
const activeProject = useActiveProject();
|
||||||
const interceptedRequests = useInterceptedRequests();
|
const interceptedRequests = useInterceptedRequests();
|
||||||
const [clearHTTPRequestLog, clearLogsResult] = useClearHttpRequestLogMutation({
|
const [clearHTTPRequestLog, clearLogsResult] = useClearHttpRequestLogMutation({
|
||||||
refetchQueries: [{ query: HttpRequestLogsDocument }],
|
refetchQueries: [{ query: HttpRequestLogsDocument }],
|
||||||
@ -27,23 +29,25 @@ function Actions(): JSX.Element {
|
|||||||
|
|
||||||
{clearLogsResult.error && <Alert severity="error">Failed to clear HTTP logs: {clearLogsResult.error}</Alert>}
|
{clearLogsResult.error && <Alert severity="error">Failed to clear HTTP logs: {clearLogsResult.error}</Alert>}
|
||||||
|
|
||||||
<Link href="/proxy/intercept/?id=" passHref>
|
{activeProject?.settings.intercept.enabled && (
|
||||||
<Button
|
<Link href="/proxy/intercept/?id=" passHref>
|
||||||
variant="contained"
|
<Button
|
||||||
disabled={interceptedRequests === null || interceptedRequests.length === 0}
|
variant="contained"
|
||||||
color="primary"
|
disabled={interceptedRequests === null || interceptedRequests.length === 0}
|
||||||
component="a"
|
color="primary"
|
||||||
size="large"
|
component="a"
|
||||||
startIcon={
|
size="large"
|
||||||
<Badge color="error" badgeContent={interceptedRequests?.length || 0}>
|
startIcon={
|
||||||
<AltRouteIcon />
|
<Badge color="error" badgeContent={interceptedRequests?.length || 0}>
|
||||||
</Badge>
|
<AltRouteIcon />
|
||||||
}
|
</Badge>
|
||||||
sx={{ mr: 1 }}
|
}
|
||||||
>
|
sx={{ mr: 1 }}
|
||||||
Review Intercepted…
|
>
|
||||||
</Button>
|
Review Intercepted…
|
||||||
</Link>
|
</Button>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
<Tooltip title="Clear all">
|
<Tooltip title="Clear all">
|
||||||
<IconButton onClick={clearHTTPConfirmationDialog.open}>
|
<IconButton onClick={clearHTTPConfirmationDialog.open}>
|
||||||
|
95
admin/src/features/settings/components/Settings.tsx
Normal file
95
admin/src/features/settings/components/Settings.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { useApolloClient } from "@apollo/client";
|
||||||
|
import { TabContext, TabPanel } from "@mui/lab";
|
||||||
|
import TabList from "@mui/lab/TabList";
|
||||||
|
import { Box, FormControl, FormControlLabel, FormHelperText, Switch, Tab, Typography } from "@mui/material";
|
||||||
|
import { SwitchBaseProps } from "@mui/material/internal/SwitchBase";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useActiveProject } from "lib/ActiveProjectContext";
|
||||||
|
import Link from "lib/components/Link";
|
||||||
|
import { ActiveProjectDocument, useUpdateInterceptSettingsMutation } from "lib/graphql/generated";
|
||||||
|
|
||||||
|
enum TabValue {
|
||||||
|
Intercept = "intercept",
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Settings(): JSX.Element {
|
||||||
|
const client = useApolloClient();
|
||||||
|
const activeProject = useActiveProject();
|
||||||
|
const [updateInterceptSettings, updateIntercepSettingsResult] = useUpdateInterceptSettingsMutation();
|
||||||
|
|
||||||
|
const handleInterceptEnabled: SwitchBaseProps["onChange"] = (_, checked) => {
|
||||||
|
updateInterceptSettings({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
enabled: checked,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onCompleted(data) {
|
||||||
|
client.cache.updateQuery({ query: ActiveProjectDocument }, (cachedData) => ({
|
||||||
|
activeProject: {
|
||||||
|
...cachedData.activeProject,
|
||||||
|
settings: {
|
||||||
|
intercept: data.updateInterceptSettings,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const [tabValue, setTabValue] = useState(TabValue.Intercept);
|
||||||
|
|
||||||
|
const tabSx = {
|
||||||
|
textTransform: "none",
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box p={4}>
|
||||||
|
<Typography variant="h4" sx={{ mb: 2 }}>
|
||||||
|
Settings
|
||||||
|
</Typography>
|
||||||
|
<Typography paragraph sx={{ mb: 4 }}>
|
||||||
|
Settings allow you to tweak the behaviour of Hetty’s features.
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h6" sx={{ mb: 2 }}>
|
||||||
|
Project settings
|
||||||
|
</Typography>
|
||||||
|
{!activeProject && (
|
||||||
|
<Typography paragraph>
|
||||||
|
There is no project active. To configure project settings, first <Link href="/projects">open a project</Link>.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{activeProject && (
|
||||||
|
<>
|
||||||
|
<TabContext value={tabValue}>
|
||||||
|
<TabList onChange={(_, value) => setTabValue(value)} sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||||
|
<Tab value={TabValue.Intercept} label="Intercept" sx={tabSx} />
|
||||||
|
</TabList>
|
||||||
|
|
||||||
|
<TabPanel value={TabValue.Intercept} sx={{ px: 0 }}>
|
||||||
|
<FormControl>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
disabled={updateIntercepSettingsResult.loading}
|
||||||
|
onChange={handleInterceptEnabled}
|
||||||
|
checked={activeProject.settings.intercept.enabled}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Enable proxy interception"
|
||||||
|
labelPlacement="start"
|
||||||
|
sx={{ display: "inline-block", m: 0 }}
|
||||||
|
/>
|
||||||
|
<FormHelperText>
|
||||||
|
When enabled, incoming HTTP requests to the proxy are stalled for{" "}
|
||||||
|
<Link href="/proxy/intercept">manual review</Link>.
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
</TabPanel>
|
||||||
|
</TabContext>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {
|
||||||
|
updateInterceptSettings(input: $input) {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import React, { createContext, useContext } from "react";
|
import React, { createContext, useContext } from "react";
|
||||||
|
|
||||||
import { Project, useProjectsQuery } from "./graphql/generated";
|
import { Project, useActiveProjectQuery } from "./graphql/generated";
|
||||||
|
|
||||||
const ActiveProjectContext = createContext<Project | null>(null);
|
const ActiveProjectContext = createContext<Project | null>(null);
|
||||||
|
|
||||||
@ -9,8 +9,8 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ActiveProjectProvider({ children }: Props): JSX.Element {
|
export function ActiveProjectProvider({ children }: Props): JSX.Element {
|
||||||
const { data } = useProjectsQuery();
|
const { data } = useActiveProjectQuery();
|
||||||
const project = data?.projects.find((project) => project.isActive) || null;
|
const project = data?.activeProject || null;
|
||||||
|
|
||||||
return <ActiveProjectContext.Provider value={project}>{children}</ActiveProjectContext.Provider>;
|
return <ActiveProjectContext.Provider value={project}>{children}</ActiveProjectContext.Provider>;
|
||||||
}
|
}
|
||||||
|
94
admin/src/lib/components/Link.tsx
Normal file
94
admin/src/lib/components/Link.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import MuiLink, { LinkProps as MuiLinkProps } from "@mui/material/Link";
|
||||||
|
import { styled } from "@mui/material/styles";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import NextLink, { LinkProps as NextLinkProps } from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
// Add support for the sx prop for consistency with the other branches.
|
||||||
|
const Anchor = styled("a")({});
|
||||||
|
|
||||||
|
interface NextLinkComposedProps
|
||||||
|
extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href">,
|
||||||
|
Omit<NextLinkProps, "href" | "as"> {
|
||||||
|
to: NextLinkProps["href"];
|
||||||
|
linkAs?: NextLinkProps["as"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NextLinkComposed = React.forwardRef<HTMLAnchorElement, NextLinkComposedProps>(function NextLinkComposed(
|
||||||
|
props,
|
||||||
|
ref
|
||||||
|
) {
|
||||||
|
const { to, linkAs, replace, scroll, shallow, prefetch, locale, ...other } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NextLink
|
||||||
|
href={to}
|
||||||
|
prefetch={prefetch}
|
||||||
|
as={linkAs}
|
||||||
|
replace={replace}
|
||||||
|
scroll={scroll}
|
||||||
|
shallow={shallow}
|
||||||
|
passHref
|
||||||
|
locale={locale}
|
||||||
|
>
|
||||||
|
<Anchor ref={ref} {...other} />
|
||||||
|
</NextLink>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export type LinkProps = {
|
||||||
|
activeClassName?: string;
|
||||||
|
as?: NextLinkProps["as"];
|
||||||
|
href: NextLinkProps["href"];
|
||||||
|
linkAs?: NextLinkProps["as"]; // Useful when the as prop is shallow by styled().
|
||||||
|
noLinkStyle?: boolean;
|
||||||
|
} & Omit<NextLinkComposedProps, "to" | "linkAs" | "href"> &
|
||||||
|
Omit<MuiLinkProps, "href">;
|
||||||
|
|
||||||
|
// A styled version of the Next.js Link component:
|
||||||
|
// https://nextjs.org/docs/api-reference/next/link
|
||||||
|
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props, ref) {
|
||||||
|
const {
|
||||||
|
activeClassName = "active",
|
||||||
|
as,
|
||||||
|
className: classNameProps,
|
||||||
|
href,
|
||||||
|
linkAs: linkAsProp,
|
||||||
|
locale,
|
||||||
|
noLinkStyle,
|
||||||
|
prefetch,
|
||||||
|
replace,
|
||||||
|
role, // Link don't have roles.
|
||||||
|
scroll,
|
||||||
|
shallow,
|
||||||
|
...other
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const pathname = typeof href === "string" ? href : href.pathname;
|
||||||
|
const className = clsx(classNameProps, {
|
||||||
|
[activeClassName]: router.pathname === pathname && activeClassName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const isExternal = typeof href === "string" && (href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);
|
||||||
|
|
||||||
|
if (isExternal) {
|
||||||
|
if (noLinkStyle) {
|
||||||
|
return <Anchor className={className} href={href} ref={ref} {...other} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <MuiLink className={className} href={href} ref={ref} {...other} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkAs = linkAsProp || as;
|
||||||
|
const nextjsProps = { to: href, linkAs, replace, scroll, shallow, prefetch, locale };
|
||||||
|
|
||||||
|
if (noLinkStyle) {
|
||||||
|
return <NextLinkComposed className={className} ref={ref} {...nextjsProps} {...other} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <MuiLink component={NextLinkComposed} className={className} ref={ref} {...nextjsProps} {...other} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Link;
|
@ -116,6 +116,11 @@ export type HttpResponseLog = {
|
|||||||
statusReason: Scalars['String'];
|
statusReason: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InterceptSettings = {
|
||||||
|
__typename?: 'InterceptSettings';
|
||||||
|
enabled: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type ModifyRequestInput = {
|
export type ModifyRequestInput = {
|
||||||
body?: InputMaybe<Scalars['String']>;
|
body?: InputMaybe<Scalars['String']>;
|
||||||
headers?: InputMaybe<Array<HttpHeaderInput>>;
|
headers?: InputMaybe<Array<HttpHeaderInput>>;
|
||||||
@ -146,6 +151,7 @@ export type Mutation = {
|
|||||||
setHttpRequestLogFilter?: Maybe<HttpRequestLogFilter>;
|
setHttpRequestLogFilter?: Maybe<HttpRequestLogFilter>;
|
||||||
setScope: Array<ScopeRule>;
|
setScope: Array<ScopeRule>;
|
||||||
setSenderRequestFilter?: Maybe<SenderRequestFilter>;
|
setSenderRequestFilter?: Maybe<SenderRequestFilter>;
|
||||||
|
updateInterceptSettings: InterceptSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -203,11 +209,22 @@ export type MutationSetSenderRequestFilterArgs = {
|
|||||||
filter?: InputMaybe<SenderRequestFilterInput>;
|
filter?: InputMaybe<SenderRequestFilterInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationUpdateInterceptSettingsArgs = {
|
||||||
|
input: UpdateInterceptSettingsInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
__typename?: 'Project';
|
__typename?: 'Project';
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
isActive: Scalars['Boolean'];
|
isActive: Scalars['Boolean'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
|
settings: ProjectSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProjectSettings = {
|
||||||
|
__typename?: 'ProjectSettings';
|
||||||
|
intercept: InterceptSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Query = {
|
export type Query = {
|
||||||
@ -296,6 +313,10 @@ export type SenderRequestInput = {
|
|||||||
url: Scalars['URL'];
|
url: Scalars['URL'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UpdateInterceptSettingsInput = {
|
||||||
|
enabled: Scalars['Boolean'];
|
||||||
|
};
|
||||||
|
|
||||||
export type CancelRequestMutationVariables = Exact<{
|
export type CancelRequestMutationVariables = Exact<{
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
}>;
|
}>;
|
||||||
@ -317,6 +338,11 @@ export type ModifyRequestMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };
|
export type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };
|
||||||
|
|
||||||
|
export type ActiveProjectQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ActiveProjectQuery = { __typename?: 'Query', activeProject?: { __typename?: 'Project', id: string, name: string, isActive: boolean, settings: { __typename?: 'ProjectSettings', intercept: { __typename?: 'InterceptSettings', enabled: boolean } } } | null };
|
||||||
|
|
||||||
export type CloseProjectMutationVariables = Exact<{ [key: string]: never; }>;
|
export type CloseProjectMutationVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
@ -422,6 +448,13 @@ export type GetSenderRequestsQueryVariables = Exact<{ [key: string]: never; }>;
|
|||||||
|
|
||||||
export type GetSenderRequestsQuery = { __typename?: 'Query', senderRequests: Array<{ __typename?: 'SenderRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponseLog', id: string, statusCode: number, statusReason: string } | null }> };
|
export type GetSenderRequestsQuery = { __typename?: 'Query', senderRequests: Array<{ __typename?: 'SenderRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponseLog', id: string, statusCode: number, statusReason: string } | null }> };
|
||||||
|
|
||||||
|
export type UpdateInterceptSettingsMutationVariables = Exact<{
|
||||||
|
input: UpdateInterceptSettingsInput;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type UpdateInterceptSettingsMutation = { __typename?: 'Mutation', updateInterceptSettings: { __typename?: 'InterceptSettings', enabled: boolean } };
|
||||||
|
|
||||||
export type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
@ -537,6 +570,47 @@ export function useModifyRequestMutation(baseOptions?: Apollo.MutationHookOption
|
|||||||
export type ModifyRequestMutationHookResult = ReturnType<typeof useModifyRequestMutation>;
|
export type ModifyRequestMutationHookResult = ReturnType<typeof useModifyRequestMutation>;
|
||||||
export type ModifyRequestMutationResult = Apollo.MutationResult<ModifyRequestMutation>;
|
export type ModifyRequestMutationResult = Apollo.MutationResult<ModifyRequestMutation>;
|
||||||
export type ModifyRequestMutationOptions = Apollo.BaseMutationOptions<ModifyRequestMutation, ModifyRequestMutationVariables>;
|
export type ModifyRequestMutationOptions = Apollo.BaseMutationOptions<ModifyRequestMutation, ModifyRequestMutationVariables>;
|
||||||
|
export const ActiveProjectDocument = gql`
|
||||||
|
query ActiveProject {
|
||||||
|
activeProject {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
isActive
|
||||||
|
settings {
|
||||||
|
intercept {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useActiveProjectQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useActiveProjectQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useActiveProjectQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useActiveProjectQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useActiveProjectQuery(baseOptions?: Apollo.QueryHookOptions<ActiveProjectQuery, ActiveProjectQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ActiveProjectQuery, ActiveProjectQueryVariables>(ActiveProjectDocument, options);
|
||||||
|
}
|
||||||
|
export function useActiveProjectLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ActiveProjectQuery, ActiveProjectQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ActiveProjectQuery, ActiveProjectQueryVariables>(ActiveProjectDocument, options);
|
||||||
|
}
|
||||||
|
export type ActiveProjectQueryHookResult = ReturnType<typeof useActiveProjectQuery>;
|
||||||
|
export type ActiveProjectLazyQueryHookResult = ReturnType<typeof useActiveProjectLazyQuery>;
|
||||||
|
export type ActiveProjectQueryResult = Apollo.QueryResult<ActiveProjectQuery, ActiveProjectQueryVariables>;
|
||||||
export const CloseProjectDocument = gql`
|
export const CloseProjectDocument = gql`
|
||||||
mutation CloseProject {
|
mutation CloseProject {
|
||||||
closeProject {
|
closeProject {
|
||||||
@ -1166,6 +1240,39 @@ export function useGetSenderRequestsLazyQuery(baseOptions?: Apollo.LazyQueryHook
|
|||||||
export type GetSenderRequestsQueryHookResult = ReturnType<typeof useGetSenderRequestsQuery>;
|
export type GetSenderRequestsQueryHookResult = ReturnType<typeof useGetSenderRequestsQuery>;
|
||||||
export type GetSenderRequestsLazyQueryHookResult = ReturnType<typeof useGetSenderRequestsLazyQuery>;
|
export type GetSenderRequestsLazyQueryHookResult = ReturnType<typeof useGetSenderRequestsLazyQuery>;
|
||||||
export type GetSenderRequestsQueryResult = Apollo.QueryResult<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>;
|
export type GetSenderRequestsQueryResult = Apollo.QueryResult<GetSenderRequestsQuery, GetSenderRequestsQueryVariables>;
|
||||||
|
export const UpdateInterceptSettingsDocument = gql`
|
||||||
|
mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {
|
||||||
|
updateInterceptSettings(input: $input) {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type UpdateInterceptSettingsMutationFn = Apollo.MutationFunction<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useUpdateInterceptSettingsMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useUpdateInterceptSettingsMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useUpdateInterceptSettingsMutation` returns a tuple that includes:
|
||||||
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const [updateInterceptSettingsMutation, { data, loading, error }] = useUpdateInterceptSettingsMutation({
|
||||||
|
* variables: {
|
||||||
|
* input: // value for 'input'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useUpdateInterceptSettingsMutation(baseOptions?: Apollo.MutationHookOptions<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>(UpdateInterceptSettingsDocument, options);
|
||||||
|
}
|
||||||
|
export type UpdateInterceptSettingsMutationHookResult = ReturnType<typeof useUpdateInterceptSettingsMutation>;
|
||||||
|
export type UpdateInterceptSettingsMutationResult = Apollo.MutationResult<UpdateInterceptSettingsMutation>;
|
||||||
|
export type UpdateInterceptSettingsMutationOptions = Apollo.BaseMutationOptions<UpdateInterceptSettingsMutation, UpdateInterceptSettingsMutationVariables>;
|
||||||
export const GetInterceptedRequestsDocument = gql`
|
export const GetInterceptedRequestsDocument = gql`
|
||||||
query GetInterceptedRequests {
|
query GetInterceptedRequests {
|
||||||
interceptedRequests {
|
interceptedRequests {
|
||||||
|
12
admin/src/pages/settings/index.tsx
Normal file
12
admin/src/pages/settings/index.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Layout, Page } from "features/Layout";
|
||||||
|
import Settings from "features/settings/components/Settings";
|
||||||
|
|
||||||
|
function Index(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Layout page={Page.Settings} title="Settings">
|
||||||
|
<Settings />
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Index;
|
@ -104,6 +104,10 @@ type ComplexityRoot struct {
|
|||||||
StatusReason func(childComplexity int) int
|
StatusReason func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InterceptSettings struct {
|
||||||
|
Enabled func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
ModifyRequestResult struct {
|
ModifyRequestResult struct {
|
||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
@ -123,12 +127,18 @@ type ComplexityRoot struct {
|
|||||||
SetHTTPRequestLogFilter func(childComplexity int, filter *HTTPRequestLogFilterInput) int
|
SetHTTPRequestLogFilter func(childComplexity int, filter *HTTPRequestLogFilterInput) int
|
||||||
SetScope func(childComplexity int, scope []ScopeRuleInput) int
|
SetScope func(childComplexity int, scope []ScopeRuleInput) int
|
||||||
SetSenderRequestFilter func(childComplexity int, filter *SenderRequestFilterInput) int
|
SetSenderRequestFilter func(childComplexity int, filter *SenderRequestFilterInput) int
|
||||||
|
UpdateInterceptSettings func(childComplexity int, input UpdateInterceptSettingsInput) int
|
||||||
}
|
}
|
||||||
|
|
||||||
Project struct {
|
Project struct {
|
||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
IsActive func(childComplexity int) int
|
IsActive func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
|
Settings func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectSettings struct {
|
||||||
|
Intercept func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
Query struct {
|
Query struct {
|
||||||
@ -188,6 +198,7 @@ type MutationResolver interface {
|
|||||||
DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)
|
DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)
|
||||||
ModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)
|
ModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)
|
||||||
CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)
|
CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)
|
||||||
|
UpdateInterceptSettings(ctx context.Context, input UpdateInterceptSettingsInput) (*InterceptSettings, error)
|
||||||
}
|
}
|
||||||
type QueryResolver interface {
|
type QueryResolver interface {
|
||||||
HTTPRequestLog(ctx context.Context, id ulid.ULID) (*HTTPRequestLog, error)
|
HTTPRequestLog(ctx context.Context, id ulid.ULID) (*HTTPRequestLog, error)
|
||||||
@ -420,6 +431,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.HTTPResponseLog.StatusReason(childComplexity), true
|
return e.complexity.HTTPResponseLog.StatusReason(childComplexity), true
|
||||||
|
|
||||||
|
case "InterceptSettings.enabled":
|
||||||
|
if e.complexity.InterceptSettings.Enabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.InterceptSettings.Enabled(childComplexity), true
|
||||||
|
|
||||||
case "ModifyRequestResult.success":
|
case "ModifyRequestResult.success":
|
||||||
if e.complexity.ModifyRequestResult.Success == nil {
|
if e.complexity.ModifyRequestResult.Success == nil {
|
||||||
break
|
break
|
||||||
@ -580,6 +598,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Mutation.SetSenderRequestFilter(childComplexity, args["filter"].(*SenderRequestFilterInput)), true
|
return e.complexity.Mutation.SetSenderRequestFilter(childComplexity, args["filter"].(*SenderRequestFilterInput)), true
|
||||||
|
|
||||||
|
case "Mutation.updateInterceptSettings":
|
||||||
|
if e.complexity.Mutation.UpdateInterceptSettings == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_updateInterceptSettings_args(context.TODO(), rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.UpdateInterceptSettings(childComplexity, args["input"].(UpdateInterceptSettingsInput)), true
|
||||||
|
|
||||||
case "Project.id":
|
case "Project.id":
|
||||||
if e.complexity.Project.ID == nil {
|
if e.complexity.Project.ID == nil {
|
||||||
break
|
break
|
||||||
@ -601,6 +631,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Project.Name(childComplexity), true
|
return e.complexity.Project.Name(childComplexity), true
|
||||||
|
|
||||||
|
case "Project.settings":
|
||||||
|
if e.complexity.Project.Settings == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Project.Settings(childComplexity), true
|
||||||
|
|
||||||
|
case "ProjectSettings.intercept":
|
||||||
|
if e.complexity.ProjectSettings.Intercept == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ProjectSettings.Intercept(childComplexity), true
|
||||||
|
|
||||||
case "Query.activeProject":
|
case "Query.activeProject":
|
||||||
if e.complexity.Query.ActiveProject == nil {
|
if e.complexity.Query.ActiveProject == nil {
|
||||||
break
|
break
|
||||||
@ -894,6 +938,11 @@ type Project {
|
|||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
isActive: Boolean!
|
isActive: Boolean!
|
||||||
|
settings: ProjectSettings!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSettings {
|
||||||
|
intercept: InterceptSettings!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScopeRule {
|
type ScopeRule {
|
||||||
@ -1006,6 +1055,14 @@ type CancelRequestResult {
|
|||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input UpdateInterceptSettingsInput {
|
||||||
|
enabled: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterceptSettings {
|
||||||
|
enabled: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
httpRequestLog(id: ID!): HttpRequestLog
|
httpRequestLog(id: ID!): HttpRequestLog
|
||||||
httpRequestLogs: [HttpRequestLog!]!
|
httpRequestLogs: [HttpRequestLog!]!
|
||||||
@ -1036,6 +1093,9 @@ type Mutation {
|
|||||||
deleteSenderRequests: DeleteSenderRequestsResult!
|
deleteSenderRequests: DeleteSenderRequestsResult!
|
||||||
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
||||||
cancelRequest(id: ID!): CancelRequestResult!
|
cancelRequest(id: ID!): CancelRequestResult!
|
||||||
|
updateInterceptSettings(
|
||||||
|
input: UpdateInterceptSettingsInput!
|
||||||
|
): InterceptSettings!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HttpMethod {
|
enum HttpMethod {
|
||||||
@ -1232,6 +1292,21 @@ func (ec *executionContext) field_Mutation_setSenderRequestFilter_args(ctx conte
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_updateInterceptSettings_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]interface{}{}
|
||||||
|
var arg0 UpdateInterceptSettingsInput
|
||||||
|
if tmp, ok := rawArgs["input"]; ok {
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||||
|
arg0, err = ec.unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args["input"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
@ -2330,6 +2405,41 @@ func (ec *executionContext) _HttpResponseLog_headers(ctx context.Context, field
|
|||||||
return ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)
|
return ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _InterceptSettings_enabled(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "InterceptSettings",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Enabled, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ModifyRequestResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyRequestResult) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ModifyRequestResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyRequestResult) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -2920,6 +3030,48 @@ func (ec *executionContext) _Mutation_cancelRequest(ctx context.Context, field g
|
|||||||
return ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)
|
return ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_updateInterceptSettings(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.field_Mutation_updateInterceptSettings_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
fc.Args = args
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return ec.resolvers.Mutation().UpdateInterceptSettings(rctx, args["input"].(UpdateInterceptSettingsInput))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*InterceptSettings)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Project_id(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Project_id(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -3025,6 +3177,76 @@ func (ec *executionContext) _Project_isActive(ctx context.Context, field graphql
|
|||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Project_settings(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "Project",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Settings, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*ProjectSettings)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ProjectSettings_intercept(ctx context.Context, field graphql.CollectedField, obj *ProjectSettings) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "ProjectSettings",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Intercept, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*InterceptSettings)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Query_httpRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Query_httpRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -5393,6 +5615,29 @@ func (ec *executionContext) unmarshalInputSenderRequestInput(ctx context.Context
|
|||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputUpdateInterceptSettingsInput(ctx context.Context, obj interface{}) (UpdateInterceptSettingsInput, error) {
|
||||||
|
var it UpdateInterceptSettingsInput
|
||||||
|
asMap := map[string]interface{}{}
|
||||||
|
for k, v := range obj.(map[string]interface{}) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range asMap {
|
||||||
|
switch k {
|
||||||
|
case "enabled":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("enabled"))
|
||||||
|
it.Enabled, err = ec.unmarshalNBoolean2bool(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
// endregion **************************** input.gotpl *****************************
|
// endregion **************************** input.gotpl *****************************
|
||||||
|
|
||||||
// region ************************** interface.gotpl ***************************
|
// region ************************** interface.gotpl ***************************
|
||||||
@ -5751,6 +5996,33 @@ func (ec *executionContext) _HttpResponseLog(ctx context.Context, sel ast.Select
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var interceptSettingsImplementors = []string{"InterceptSettings"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _InterceptSettings(ctx context.Context, sel ast.SelectionSet, obj *InterceptSettings) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, interceptSettingsImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("InterceptSettings")
|
||||||
|
case "enabled":
|
||||||
|
out.Values[i] = ec._InterceptSettings_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var modifyRequestResultImplementors = []string{"ModifyRequestResult"}
|
var modifyRequestResultImplementors = []string{"ModifyRequestResult"}
|
||||||
|
|
||||||
func (ec *executionContext) _ModifyRequestResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyRequestResult) graphql.Marshaler {
|
func (ec *executionContext) _ModifyRequestResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyRequestResult) graphql.Marshaler {
|
||||||
@ -5851,6 +6123,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "updateInterceptSettings":
|
||||||
|
out.Values[i] = ec._Mutation_updateInterceptSettings(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
@ -5888,6 +6165,38 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet,
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "settings":
|
||||||
|
out.Values[i] = ec._Project_settings(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectSettingsImplementors = []string{"ProjectSettings"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ProjectSettings(ctx context.Context, sel ast.SelectionSet, obj *ProjectSettings) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, projectSettingsImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("ProjectSettings")
|
||||||
|
case "intercept":
|
||||||
|
out.Values[i] = ec._ProjectSettings_intercept(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
@ -6726,6 +7035,20 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNInterceptSettings2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v InterceptSettings) graphql.Marshaler {
|
||||||
|
return ec._InterceptSettings(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v *InterceptSettings) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._InterceptSettings(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNModifyRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestInput(ctx context.Context, v interface{}) (ModifyRequestInput, error) {
|
func (ec *executionContext) unmarshalNModifyRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestInput(ctx context.Context, v interface{}) (ModifyRequestInput, error) {
|
||||||
res, err := ec.unmarshalInputModifyRequestInput(ctx, v)
|
res, err := ec.unmarshalInputModifyRequestInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
@ -6793,6 +7116,16 @@ func (ec *executionContext) marshalNProject2ᚕgithubᚗcomᚋdstotijnᚋhetty
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx context.Context, sel ast.SelectionSet, v *ProjectSettings) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._ProjectSettings(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalNScopeRule2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRule(ctx context.Context, sel ast.SelectionSet, v ScopeRule) graphql.Marshaler {
|
func (ec *executionContext) marshalNScopeRule2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRule(ctx context.Context, sel ast.SelectionSet, v ScopeRule) graphql.Marshaler {
|
||||||
return ec._ScopeRule(ctx, sel, &v)
|
return ec._ScopeRule(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
@ -6981,6 +7314,11 @@ func (ec *executionContext) marshalNURL2ᚖnetᚋurlᚐURL(ctx context.Context,
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx context.Context, v interface{}) (UpdateInterceptSettingsInput, error) {
|
||||||
|
res, err := ec.unmarshalInputUpdateInterceptSettingsInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler {
|
func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler {
|
||||||
return ec.___Directive(ctx, sel, &v)
|
return ec.___Directive(ctx, sel, &v)
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,10 @@ type HTTPResponseLog struct {
|
|||||||
Headers []HTTPHeader `json:"headers"`
|
Headers []HTTPHeader `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InterceptSettings struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
type ModifyRequestInput struct {
|
type ModifyRequestInput struct {
|
||||||
ID ulid.ULID `json:"id"`
|
ID ulid.ULID `json:"id"`
|
||||||
URL *url.URL `json:"url"`
|
URL *url.URL `json:"url"`
|
||||||
@ -96,9 +100,14 @@ type ModifyRequestResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
ID ulid.ULID `json:"id"`
|
ID ulid.ULID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
IsActive bool `json:"isActive"`
|
IsActive bool `json:"isActive"`
|
||||||
|
Settings *ProjectSettings `json:"settings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSettings struct {
|
||||||
|
Intercept *InterceptSettings `json:"intercept"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScopeHeader struct {
|
type ScopeHeader struct {
|
||||||
@ -154,6 +163,10 @@ type SenderRequestInput struct {
|
|||||||
Body *string `json:"body"`
|
Body *string `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateInterceptSettingsInput struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
type HTTPMethod string
|
type HTTPMethod string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -218,6 +218,11 @@ func (r *queryResolver) ActiveProject(ctx context.Context) (*Project, error) {
|
|||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
IsActive: r.ProjectService.IsProjectActive(p.ID),
|
IsActive: r.ProjectService.IsProjectActive(p.ID),
|
||||||
|
Settings: &ProjectSettings{
|
||||||
|
Intercept: &InterceptSettings{
|
||||||
|
Enabled: p.Settings.InterceptEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,6 +595,26 @@ func (r *mutationResolver) CancelRequest(ctx context.Context, id ulid.ULID) (*Ca
|
|||||||
return &CancelRequestResult{Success: true}, nil
|
return &CancelRequestResult{Success: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mutationResolver) UpdateInterceptSettings(
|
||||||
|
ctx context.Context,
|
||||||
|
input UpdateInterceptSettingsInput,
|
||||||
|
) (*InterceptSettings, error) {
|
||||||
|
settings := intercept.Settings{
|
||||||
|
Enabled: input.Enabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.ProjectService.UpdateInterceptSettings(ctx, settings)
|
||||||
|
if errors.Is(err, proj.ErrNoProject) {
|
||||||
|
return nil, noActiveProjectErr(ctx)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not update intercept settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &InterceptSettings{
|
||||||
|
Enabled: settings.Enabled,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseSenderRequest(req sender.Request) (SenderRequest, error) {
|
func parseSenderRequest(req sender.Request) (SenderRequest, error) {
|
||||||
method := HTTPMethod(req.Method)
|
method := HTTPMethod(req.Method)
|
||||||
if method != "" && !method.IsValid() {
|
if method != "" && !method.IsValid() {
|
||||||
|
@ -30,6 +30,11 @@ type Project {
|
|||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
isActive: Boolean!
|
isActive: Boolean!
|
||||||
|
settings: ProjectSettings!
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSettings {
|
||||||
|
intercept: InterceptSettings!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScopeRule {
|
type ScopeRule {
|
||||||
@ -142,6 +147,14 @@ type CancelRequestResult {
|
|||||||
success: Boolean!
|
success: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input UpdateInterceptSettingsInput {
|
||||||
|
enabled: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterceptSettings {
|
||||||
|
enabled: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
httpRequestLog(id: ID!): HttpRequestLog
|
httpRequestLog(id: ID!): HttpRequestLog
|
||||||
httpRequestLogs: [HttpRequestLog!]!
|
httpRequestLogs: [HttpRequestLog!]!
|
||||||
@ -172,6 +185,9 @@ type Mutation {
|
|||||||
deleteSenderRequests: DeleteSenderRequestsResult!
|
deleteSenderRequests: DeleteSenderRequestsResult!
|
||||||
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
|
||||||
cancelRequest(id: ID!): CancelRequestResult!
|
cancelRequest(id: ID!): CancelRequestResult!
|
||||||
|
updateInterceptSettings(
|
||||||
|
input: UpdateInterceptSettingsInput!
|
||||||
|
): InterceptSettings!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HttpMethod {
|
enum HttpMethod {
|
||||||
|
@ -34,6 +34,7 @@ type Service interface {
|
|||||||
SetScopeRules(ctx context.Context, rules []scope.Rule) error
|
SetScopeRules(ctx context.Context, rules []scope.Rule) error
|
||||||
SetRequestLogFindFilter(ctx context.Context, filter reqlog.FindRequestsFilter) error
|
SetRequestLogFindFilter(ctx context.Context, filter reqlog.FindRequestsFilter) error
|
||||||
SetSenderRequestFindFilter(ctx context.Context, filter sender.FindRequestsFilter) error
|
SetSenderRequestFindFilter(ctx context.Context, filter sender.FindRequestsFilter) error
|
||||||
|
UpdateInterceptSettings(ctx context.Context, settings intercept.Settings) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
@ -55,13 +56,19 @@ type Project struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
|
// Request log settings
|
||||||
ReqLogBypassOutOfScope bool
|
ReqLogBypassOutOfScope bool
|
||||||
ReqLogOnlyFindInScope bool
|
ReqLogOnlyFindInScope bool
|
||||||
ReqLogSearchExpr search.Expression
|
ReqLogSearchExpr search.Expression
|
||||||
|
|
||||||
|
// Intercept settings
|
||||||
|
InterceptEnabled bool
|
||||||
|
|
||||||
|
// Sender settings
|
||||||
SenderOnlyFindInScope bool
|
SenderOnlyFindInScope bool
|
||||||
SenderSearchExpr search.Expression
|
SenderSearchExpr search.Expression
|
||||||
|
|
||||||
|
// Scope settings
|
||||||
ScopeRules []scope.Rule
|
ScopeRules []scope.Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,10 +128,12 @@ func (svc *service) CloseProject() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
svc.activeProjectID = ulid.ULID{}
|
svc.activeProjectID = ulid.ULID{}
|
||||||
svc.interceptSvc.ClearRequests()
|
|
||||||
svc.reqLogSvc.SetActiveProjectID(ulid.ULID{})
|
svc.reqLogSvc.SetActiveProjectID(ulid.ULID{})
|
||||||
svc.reqLogSvc.SetBypassOutOfScopeRequests(false)
|
svc.reqLogSvc.SetBypassOutOfScopeRequests(false)
|
||||||
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{})
|
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{})
|
||||||
|
svc.interceptSvc.UpdateSettings(intercept.Settings{
|
||||||
|
Enabled: false,
|
||||||
|
})
|
||||||
svc.senderSvc.SetActiveProjectID(ulid.ULID{})
|
svc.senderSvc.SetActiveProjectID(ulid.ULID{})
|
||||||
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{})
|
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{})
|
||||||
svc.scope.SetRules(nil)
|
svc.scope.SetRules(nil)
|
||||||
@ -157,6 +166,7 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
|
|||||||
|
|
||||||
svc.activeProjectID = project.ID
|
svc.activeProjectID = project.ID
|
||||||
|
|
||||||
|
// Request log settings.
|
||||||
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{
|
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{
|
||||||
ProjectID: project.ID,
|
ProjectID: project.ID,
|
||||||
OnlyInScope: project.Settings.ReqLogOnlyFindInScope,
|
OnlyInScope: project.Settings.ReqLogOnlyFindInScope,
|
||||||
@ -165,6 +175,12 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
|
|||||||
svc.reqLogSvc.SetBypassOutOfScopeRequests(project.Settings.ReqLogBypassOutOfScope)
|
svc.reqLogSvc.SetBypassOutOfScopeRequests(project.Settings.ReqLogBypassOutOfScope)
|
||||||
svc.reqLogSvc.SetActiveProjectID(project.ID)
|
svc.reqLogSvc.SetActiveProjectID(project.ID)
|
||||||
|
|
||||||
|
// Intercept settings.
|
||||||
|
svc.interceptSvc.UpdateSettings(intercept.Settings{
|
||||||
|
Enabled: project.Settings.InterceptEnabled,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Sender settings.
|
||||||
svc.senderSvc.SetActiveProjectID(project.ID)
|
svc.senderSvc.SetActiveProjectID(project.ID)
|
||||||
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{
|
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{
|
||||||
ProjectID: project.ID,
|
ProjectID: project.ID,
|
||||||
@ -172,6 +188,7 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
|
|||||||
SearchExpr: project.Settings.SenderSearchExpr,
|
SearchExpr: project.Settings.SenderSearchExpr,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Scope settings.
|
||||||
svc.scope.SetRules(project.Settings.ScopeRules)
|
svc.scope.SetRules(project.Settings.ScopeRules)
|
||||||
|
|
||||||
return project, nil
|
return project, nil
|
||||||
@ -269,3 +286,21 @@ func (svc *service) SetSenderRequestFindFilter(ctx context.Context, filter sende
|
|||||||
func (svc *service) IsProjectActive(projectID ulid.ULID) bool {
|
func (svc *service) IsProjectActive(projectID ulid.ULID) bool {
|
||||||
return projectID.Compare(svc.activeProjectID) == 0
|
return projectID.Compare(svc.activeProjectID) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *service) UpdateInterceptSettings(ctx context.Context, settings intercept.Settings) error {
|
||||||
|
project, err := svc.ActiveProject(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
project.Settings.InterceptEnabled = settings.Enabled
|
||||||
|
|
||||||
|
err = svc.repo.UpsertProject(ctx, project)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("proj: failed to update project: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.interceptSvc.UpdateSettings(settings)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -31,10 +31,12 @@ type Service struct {
|
|||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
requests map[ulid.ULID]Request
|
requests map[ulid.ULID]Request
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
|
Enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestIDs implements sort.Interface.
|
// RequestIDs implements sort.Interface.
|
||||||
@ -45,6 +47,7 @@ func NewService(cfg Config) *Service {
|
|||||||
mu: &sync.RWMutex{},
|
mu: &sync.RWMutex{},
|
||||||
requests: make(map[ulid.ULID]Request),
|
requests: make(map[ulid.ULID]Request),
|
||||||
logger: cfg.Logger,
|
logger: cfg.Logger,
|
||||||
|
enabled: cfg.Enabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.logger == nil {
|
if s.logger == nil {
|
||||||
@ -93,6 +96,12 @@ func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Req
|
|||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !svc.enabled {
|
||||||
|
// If intercept is disabled, return the incoming request as-is.
|
||||||
|
svc.logger.Debugw("Bypassed interception: module disabled.")
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
ch := make(chan *http.Request)
|
ch := make(chan *http.Request)
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
@ -181,6 +190,15 @@ func (svc *Service) Requests() []*http.Request {
|
|||||||
return reqs
|
return reqs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *Service) UpdateSettings(settings Settings) {
|
||||||
|
// When updating from `enabled` -> `disabled`, clear any pending reqs.
|
||||||
|
if svc.enabled && !settings.Enabled {
|
||||||
|
svc.ClearRequests()
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.enabled = settings.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
// Request returns an intercepted request by ID. It's safe for concurrent use.
|
// Request returns an intercepted request by ID. It's safe for concurrent use.
|
||||||
func (svc *Service) RequestByID(id ulid.ULID) (*http.Request, error) {
|
func (svc *Service) RequestByID(id ulid.ULID) (*http.Request, error) {
|
||||||
svc.mu.RLock()
|
svc.mu.RLock()
|
||||||
|
@ -28,7 +28,8 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
|
|
||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
svc := intercept.NewService(intercept.Config{
|
svc := intercept.NewService(intercept.Config{
|
||||||
Logger: logger.Sugar(),
|
Logger: logger.Sugar(),
|
||||||
|
Enabled: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
reqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)
|
reqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)
|
||||||
@ -44,7 +45,8 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
|
|
||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
svc := intercept.NewService(intercept.Config{
|
svc := intercept.NewService(intercept.Config{
|
||||||
Logger: logger.Sugar(),
|
Logger: logger.Sugar(),
|
||||||
|
Enabled: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@ -65,7 +67,7 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
|
|
||||||
err := svc.ModifyRequest(reqID, nil)
|
err := svc.ModifyRequest(reqID, nil)
|
||||||
if !errors.Is(err, intercept.ErrRequestDone) {
|
if !errors.Is(err, intercept.ErrRequestDone) {
|
||||||
t.Fatalf("expected `interept.ErrRequestDone`, got: %v", err)
|
t.Fatalf("expected `intercept.ErrRequestDone`, got: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -83,7 +85,8 @@ func TestRequestModifier(t *testing.T) {
|
|||||||
|
|
||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
svc := intercept.NewService(intercept.Config{
|
svc := intercept.NewService(intercept.Config{
|
||||||
Logger: logger.Sugar(),
|
Logger: logger.Sugar(),
|
||||||
|
Enabled: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
var got *http.Request
|
var got *http.Request
|
||||||
|
5
pkg/proxy/intercept/settings.go
Normal file
5
pkg/proxy/intercept/settings.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package intercept
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
Enabled bool
|
||||||
|
}
|
Reference in New Issue
Block a user