Merge pull request #2099 from automatisch/aut-1262
feat: use REST API endpoints to create and reconnect connections
This commit is contained in:
@@ -169,7 +169,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|||||||
dynamicDataKey: 'listRepos',
|
dynamicDataKey: 'listRepos',
|
||||||
parameters: {},
|
parameters: {},
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(422);
|
||||||
|
|
||||||
expect(response.body.errors).toEqual(errors);
|
expect(response.body.errors).toEqual(errors);
|
||||||
});
|
});
|
||||||
|
@@ -1,14 +1,3 @@
|
|||||||
// Converted mutations
|
const mutationResolvers = {};
|
||||||
import verifyConnection from './mutations/verify-connection.js';
|
|
||||||
import generateAuthUrl from './mutations/generate-auth-url.js';
|
|
||||||
import resetConnection from './mutations/reset-connection.js';
|
|
||||||
import updateConnection from './mutations/update-connection.js';
|
|
||||||
|
|
||||||
const mutationResolvers = {
|
|
||||||
generateAuthUrl,
|
|
||||||
resetConnection,
|
|
||||||
updateConnection,
|
|
||||||
verifyConnection,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default mutationResolvers;
|
export default mutationResolvers;
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
import globalVariable from '../../helpers/global-variable.js';
|
|
||||||
import App from '../../models/app.js';
|
|
||||||
|
|
||||||
const generateAuthUrl = async (_parent, params, context) => {
|
|
||||||
context.currentUser.can('create', 'Connection');
|
|
||||||
|
|
||||||
const connection = await context.currentUser
|
|
||||||
.$relatedQuery('connections')
|
|
||||||
.findOne({
|
|
||||||
id: params.input.id,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
if (!connection.formattedData) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const authInstance = (
|
|
||||||
await import(`../../apps/${connection.key}/auth/index.js`)
|
|
||||||
).default;
|
|
||||||
|
|
||||||
const app = await App.findOneByKey(connection.key);
|
|
||||||
|
|
||||||
const $ = await globalVariable({ connection, app });
|
|
||||||
await authInstance.generateAuthUrl($);
|
|
||||||
|
|
||||||
return connection.formattedData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default generateAuthUrl;
|
|
@@ -1,22 +0,0 @@
|
|||||||
const resetConnection = async (_parent, params, context) => {
|
|
||||||
context.currentUser.can('create', 'Connection');
|
|
||||||
|
|
||||||
let connection = await context.currentUser
|
|
||||||
.$relatedQuery('connections')
|
|
||||||
.findOne({
|
|
||||||
id: params.input.id,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
if (!connection.formattedData) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
connection = await connection.$query().patchAndFetch({
|
|
||||||
formattedData: { screenName: connection.formattedData.screenName },
|
|
||||||
});
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default resetConnection;
|
|
@@ -1,33 +0,0 @@
|
|||||||
import AppAuthClient from '../../models/app-auth-client.js';
|
|
||||||
|
|
||||||
const updateConnection = async (_parent, params, context) => {
|
|
||||||
context.currentUser.can('create', 'Connection');
|
|
||||||
|
|
||||||
let connection = await context.currentUser
|
|
||||||
.$relatedQuery('connections')
|
|
||||||
.findOne({
|
|
||||||
id: params.input.id,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
let formattedData = params.input.formattedData;
|
|
||||||
|
|
||||||
if (params.input.appAuthClientId) {
|
|
||||||
const appAuthClient = await AppAuthClient.query()
|
|
||||||
.findById(params.input.appAuthClientId)
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
formattedData = appAuthClient.formattedAuthDefaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
connection = await connection.$query().patchAndFetch({
|
|
||||||
formattedData: {
|
|
||||||
...connection.formattedData,
|
|
||||||
...formattedData,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default updateConnection;
|
|
@@ -1,29 +0,0 @@
|
|||||||
import App from '../../models/app.js';
|
|
||||||
import globalVariable from '../../helpers/global-variable.js';
|
|
||||||
|
|
||||||
const verifyConnection = async (_parent, params, context) => {
|
|
||||||
context.currentUser.can('create', 'Connection');
|
|
||||||
|
|
||||||
let connection = await context.currentUser
|
|
||||||
.$relatedQuery('connections')
|
|
||||||
.findOne({
|
|
||||||
id: params.input.id,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const app = await App.findOneByKey(connection.key);
|
|
||||||
const $ = await globalVariable({ connection, app });
|
|
||||||
await app.auth.verifyCredentials($);
|
|
||||||
|
|
||||||
connection = await connection.$query().patchAndFetch({
|
|
||||||
verified: true,
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...connection,
|
|
||||||
app,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyConnection;
|
|
@@ -1,22 +1,10 @@
|
|||||||
type Query {
|
type Query {
|
||||||
placeholderQuery(name: String): Boolean
|
placeholderQuery(name: String): Boolean
|
||||||
}
|
}
|
||||||
type Mutation {
|
|
||||||
generateAuthUrl(input: GenerateAuthUrlInput): AuthLink
|
|
||||||
resetConnection(input: ResetConnectionInput): Connection
|
|
||||||
updateConnection(input: UpdateConnectionInput): Connection
|
|
||||||
verifyConnection(input: VerifyConnectionInput): Connection
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
type Mutation {
|
||||||
Exposes a URL that specifies the behaviour of this scalar.
|
placeholderQuery(name: String): Boolean
|
||||||
"""
|
}
|
||||||
directive @specifiedBy(
|
|
||||||
"""
|
|
||||||
The URL that specifies the behaviour of this scalar.
|
|
||||||
"""
|
|
||||||
url: String!
|
|
||||||
) on SCALAR
|
|
||||||
|
|
||||||
type Trigger {
|
type Trigger {
|
||||||
name: String
|
name: String
|
||||||
@@ -130,10 +118,6 @@ type AuthenticationStepProperty {
|
|||||||
value: String
|
value: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthLink {
|
|
||||||
url: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type Connection {
|
type Connection {
|
||||||
id: String
|
id: String
|
||||||
key: String
|
key: String
|
||||||
@@ -200,24 +184,6 @@ type SamlAuthProvidersRoleMapping {
|
|||||||
remoteRoleName: String
|
remoteRoleName: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input GenerateAuthUrlInput {
|
|
||||||
id: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
input UpdateConnectionInput {
|
|
||||||
id: String!
|
|
||||||
formattedData: JSONObject
|
|
||||||
appAuthClientId: String
|
|
||||||
}
|
|
||||||
|
|
||||||
input ResetConnectionInput {
|
|
||||||
id: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
input VerifyConnectionInput {
|
|
||||||
id: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
input UserRoleInput {
|
input UserRoleInput {
|
||||||
id: String
|
id: String
|
||||||
}
|
}
|
||||||
|
@@ -27,12 +27,7 @@ const authenticationStepsWithoutAuthUrl = [
|
|||||||
{
|
{
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'verifyConnection',
|
name: 'verifyConnection',
|
||||||
arguments: [
|
arguments: [],
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -54,12 +49,7 @@ const authenticationStepsWithAuthUrl = [
|
|||||||
{
|
{
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'generateAuthUrl',
|
name: 'generateAuthUrl',
|
||||||
arguments: [
|
arguments: [],
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'openWithPopup',
|
type: 'openWithPopup',
|
||||||
@@ -75,10 +65,6 @@ const authenticationStepsWithAuthUrl = [
|
|||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'updateConnection',
|
name: 'updateConnection',
|
||||||
arguments: [
|
arguments: [
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'formattedData',
|
name: 'formattedData',
|
||||||
value: '{openAuthPopup.all}',
|
value: '{openAuthPopup.all}',
|
||||||
@@ -88,12 +74,7 @@ const authenticationStepsWithAuthUrl = [
|
|||||||
{
|
{
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'verifyConnection',
|
name: 'verifyConnection',
|
||||||
arguments: [
|
arguments: [],
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -115,12 +96,7 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
|||||||
{
|
{
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'generateAuthUrl',
|
name: 'generateAuthUrl',
|
||||||
arguments: [
|
arguments: [],
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'openWithPopup',
|
type: 'openWithPopup',
|
||||||
@@ -136,10 +112,6 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
|||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'updateConnection',
|
name: 'updateConnection',
|
||||||
arguments: [
|
arguments: [
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'formattedData',
|
name: 'formattedData',
|
||||||
value: '{openAuthPopup.all}',
|
value: '{openAuthPopup.all}',
|
||||||
@@ -149,12 +121,7 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
|||||||
{
|
{
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'verifyConnection',
|
name: 'verifyConnection',
|
||||||
arguments: [
|
arguments: [],
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: '{createConnection.id}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,54 +1,23 @@
|
|||||||
import cloneDeep from 'lodash/cloneDeep.js';
|
import cloneDeep from 'lodash/cloneDeep.js';
|
||||||
|
|
||||||
const connectionIdArgument = {
|
|
||||||
name: 'id',
|
|
||||||
value: '{connection.id}',
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetConnectionStep = {
|
const resetConnectionStep = {
|
||||||
type: 'mutation',
|
type: 'mutation',
|
||||||
name: 'resetConnection',
|
name: 'resetConnection',
|
||||||
arguments: [connectionIdArgument],
|
arguments: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
function replaceCreateConnection(string) {
|
|
||||||
return string.replace('{createConnection.id}', '{connection.id}');
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeAppKeyArgument(args) {
|
function removeAppKeyArgument(args) {
|
||||||
return args.filter((argument) => argument.name !== 'key');
|
return args.filter((argument) => argument.name !== 'key');
|
||||||
}
|
}
|
||||||
|
|
||||||
function addConnectionId(step) {
|
|
||||||
step.arguments = step.arguments.map((argument) => {
|
|
||||||
if (typeof argument.value === 'string') {
|
|
||||||
argument.value = replaceCreateConnection(argument.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argument.properties) {
|
|
||||||
argument.properties = argument.properties.map((property) => {
|
|
||||||
return {
|
|
||||||
name: property.name,
|
|
||||||
value: replaceCreateConnection(property.value),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return argument;
|
|
||||||
});
|
|
||||||
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceCreateConnectionsWithUpdate(steps) {
|
function replaceCreateConnectionsWithUpdate(steps) {
|
||||||
const updatedSteps = cloneDeep(steps);
|
const updatedSteps = cloneDeep(steps);
|
||||||
return updatedSteps.map((step) => {
|
return updatedSteps.map((step) => {
|
||||||
const updatedStep = addConnectionId(step);
|
const updatedStep = { ...step };
|
||||||
|
|
||||||
if (step.name === 'createConnection') {
|
if (step.name === 'createConnection') {
|
||||||
updatedStep.name = 'updateConnection';
|
updatedStep.name = 'updateConnection';
|
||||||
updatedStep.arguments = removeAppKeyArgument(updatedStep.arguments);
|
updatedStep.arguments = removeAppKeyArgument(updatedStep.arguments);
|
||||||
updatedStep.arguments.unshift(connectionIdArgument);
|
|
||||||
|
|
||||||
return updatedStep;
|
return updatedStep;
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ const errorHandler = (error, request, response, next) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
response.status(200).json(httpErrorPayload);
|
response.status(422).json(httpErrorPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error instanceof NotAuthorizedError) {
|
if (error instanceof NotAuthorizedError) {
|
||||||
|
@@ -26,7 +26,8 @@ function AddAppConnection(props) {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
const [error, setError] = React.useState(null);
|
const [errorMessage, setErrorMessage] = React.useState(null);
|
||||||
|
const [errorDetails, setErrorDetails] = React.useState(null);
|
||||||
const [inProgress, setInProgress] = React.useState(false);
|
const [inProgress, setInProgress] = React.useState(false);
|
||||||
const hasConnection = Boolean(connectionId);
|
const hasConnection = Boolean(connectionId);
|
||||||
const useShared = searchParams.get('shared') === 'true';
|
const useShared = searchParams.get('shared') === 'true';
|
||||||
@@ -76,7 +77,8 @@ function AddAppConnection(props) {
|
|||||||
async (data) => {
|
async (data) => {
|
||||||
if (!authenticate) return;
|
if (!authenticate) return;
|
||||||
setInProgress(true);
|
setInProgress(true);
|
||||||
setError(null);
|
setErrorMessage(null);
|
||||||
|
setErrorDetails(null);
|
||||||
try {
|
try {
|
||||||
const response = await authenticate({
|
const response = await authenticate({
|
||||||
fields: data,
|
fields: data,
|
||||||
@@ -85,21 +87,19 @@ function AddAppConnection(props) {
|
|||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: ['apps', key, 'connections'],
|
queryKey: ['apps', key, 'connections'],
|
||||||
});
|
});
|
||||||
|
|
||||||
onClose(response);
|
onClose(response);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const error = err;
|
const error = err;
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
if (error.message) {
|
setErrorMessage(error.message);
|
||||||
setError(error);
|
setErrorDetails(error?.response?.data?.errors);
|
||||||
} else {
|
|
||||||
setError(error.graphQLErrors?.[0]);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
setInProgress(false);
|
setInProgress(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[authenticate],
|
[authenticate, key, onClose, queryClient],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (useShared)
|
if (useShared)
|
||||||
@@ -134,16 +134,16 @@ function AddAppConnection(props) {
|
|||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{error && (
|
{(errorMessage || errorDetails) && (
|
||||||
<Alert
|
<Alert
|
||||||
data-test="add-connection-error"
|
data-test="add-connection-error"
|
||||||
severity="error"
|
severity="error"
|
||||||
sx={{ mt: 1, fontWeight: 500, wordBreak: 'break-all' }}
|
sx={{ mt: 1, fontWeight: 500, wordBreak: 'break-all' }}
|
||||||
>
|
>
|
||||||
{error.message}
|
{!errorDetails && errorMessage}
|
||||||
{error.details && (
|
{errorDetails && (
|
||||||
<pre style={{ whiteSpace: 'pre-wrap' }}>
|
<pre style={{ whiteSpace: 'pre-wrap' }}>
|
||||||
{JSON.stringify(error.details, null, 2)}
|
{JSON.stringify(errorDetails, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
|
@@ -6,36 +6,7 @@ const cache = new InMemoryCache({
|
|||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
mutationType: true,
|
mutationType: true,
|
||||||
fields: {
|
fields: {},
|
||||||
verifyConnection: {
|
|
||||||
merge(existing, verifiedConnection, { readField, cache }) {
|
|
||||||
const appKey = readField('key', verifiedConnection);
|
|
||||||
const appCacheId = cache.identify({
|
|
||||||
__typename: 'App',
|
|
||||||
key: appKey,
|
|
||||||
});
|
|
||||||
cache.modify({
|
|
||||||
id: appCacheId,
|
|
||||||
fields: {
|
|
||||||
connections: (existingConnections) => {
|
|
||||||
const existingConnectionIndex = existingConnections.findIndex(
|
|
||||||
(connection) => {
|
|
||||||
return connection.__ref === verifiedConnection.__ref;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const connectionExists = existingConnectionIndex !== -1;
|
|
||||||
// newly created and verified connection
|
|
||||||
if (!connectionExists) {
|
|
||||||
return [verifiedConnection, ...existingConnections];
|
|
||||||
}
|
|
||||||
return existingConnections;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return verifiedConnection;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
export const GENERATE_AUTH_URL = gql`
|
|
||||||
mutation generateAuthUrl($input: GenerateAuthUrlInput) {
|
|
||||||
generateAuthUrl(input: $input) {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,12 +0,0 @@
|
|||||||
import { UPDATE_CONNECTION } from './update-connection';
|
|
||||||
import { VERIFY_CONNECTION } from './verify-connection';
|
|
||||||
import { RESET_CONNECTION } from './reset-connection';
|
|
||||||
import { GENERATE_AUTH_URL } from './generate-auth-url';
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
updateConnection: UPDATE_CONNECTION,
|
|
||||||
verifyConnection: VERIFY_CONNECTION,
|
|
||||||
resetConnection: RESET_CONNECTION,
|
|
||||||
generateAuthUrl: GENERATE_AUTH_URL,
|
|
||||||
};
|
|
||||||
export default mutations;
|
|
@@ -1,8 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
export const RESET_CONNECTION = gql`
|
|
||||||
mutation ResetConnection($input: ResetConnectionInput) {
|
|
||||||
resetConnection(input: $input) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,13 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
export const UPDATE_CONNECTION = gql`
|
|
||||||
mutation UpdateConnection($input: UpdateConnectionInput) {
|
|
||||||
updateConnection(input: $input) {
|
|
||||||
id
|
|
||||||
key
|
|
||||||
verified
|
|
||||||
formattedData {
|
|
||||||
screenName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,17 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
export const VERIFY_CONNECTION = gql`
|
|
||||||
mutation VerifyConnection($input: VerifyConnectionInput) {
|
|
||||||
verifyConnection(input: $input) {
|
|
||||||
id
|
|
||||||
key
|
|
||||||
verified
|
|
||||||
formattedData {
|
|
||||||
screenName
|
|
||||||
}
|
|
||||||
createdAt
|
|
||||||
app {
|
|
||||||
key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,20 +1,3 @@
|
|||||||
import apolloClient from 'graphql/client';
|
|
||||||
import MUTATIONS from 'graphql/mutations';
|
|
||||||
|
|
||||||
export const processMutation = async (mutationName, variables) => {
|
|
||||||
const mutation = MUTATIONS[mutationName];
|
|
||||||
const mutationResponse = await apolloClient.mutate({
|
|
||||||
mutation,
|
|
||||||
variables: { input: variables },
|
|
||||||
context: {
|
|
||||||
autoSnackbar: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const responseData = mutationResponse.data[mutationName];
|
|
||||||
|
|
||||||
return responseData;
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseUrlSearchParams = (event) => {
|
const parseUrlSearchParams = (event) => {
|
||||||
const searchParams = new URLSearchParams(event.data.payload.search);
|
const searchParams = new URLSearchParams(event.data.payload.search);
|
||||||
const hashParams = new URLSearchParams(event.data.payload.hash.substring(1));
|
const hashParams = new URLSearchParams(event.data.payload.hash.substring(1));
|
||||||
|
@@ -1,27 +1,35 @@
|
|||||||
import template from 'lodash/template';
|
import template from 'lodash/template';
|
||||||
const interpolate = /{([\s\S]+?)}/g;
|
const interpolate = /{([\s\S]+?)}/g;
|
||||||
|
|
||||||
const computeAuthStepVariables = (variableSchema, aggregatedData) => {
|
const computeAuthStepVariables = (variableSchema, aggregatedData) => {
|
||||||
const variables = {};
|
const variables = {};
|
||||||
|
|
||||||
for (const variable of variableSchema) {
|
for (const variable of variableSchema) {
|
||||||
if (variable.properties) {
|
if (variable.properties) {
|
||||||
variables[variable.name] = computeAuthStepVariables(
|
variables[variable.name] = computeAuthStepVariables(
|
||||||
variable.properties,
|
variable.properties,
|
||||||
aggregatedData
|
aggregatedData,
|
||||||
);
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variable.value) {
|
if (variable.value) {
|
||||||
if (variable.value.endsWith('.all}')) {
|
if (variable.value.endsWith('.all}')) {
|
||||||
const key = variable.value.replace('{', '').replace('.all}', '');
|
const key = variable.value.replace('{', '').replace('.all}', '');
|
||||||
variables[variable.name] = aggregatedData[key];
|
variables[variable.name] = aggregatedData[key];
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const computedVariable = template(variable.value, { interpolate })(
|
const computedVariable = template(variable.value, { interpolate })(
|
||||||
aggregatedData
|
aggregatedData,
|
||||||
);
|
);
|
||||||
|
|
||||||
variables[variable.name] = computedVariable;
|
variables[variable.name] = computedVariable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return variables;
|
return variables;
|
||||||
};
|
};
|
||||||
export default computeAuthStepVariables;
|
export default computeAuthStepVariables;
|
||||||
|
@@ -1,14 +1,18 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
processMutation,
|
|
||||||
processOpenWithPopup,
|
processOpenWithPopup,
|
||||||
processPopupMessage,
|
processPopupMessage,
|
||||||
} from 'helpers/authenticationSteps';
|
} from 'helpers/authenticationSteps';
|
||||||
import computeAuthStepVariables from 'helpers/computeAuthStepVariables';
|
import computeAuthStepVariables from 'helpers/computeAuthStepVariables';
|
||||||
|
import useFormatMessage from './useFormatMessage';
|
||||||
import useAppAuth from './useAppAuth';
|
import useAppAuth from './useAppAuth';
|
||||||
import useCreateConnection from './useCreateConnection';
|
import useCreateConnection from './useCreateConnection';
|
||||||
import useFormatMessage from './useFormatMessage';
|
import useCreateConnectionAuthUrl from './useCreateConnectionAuthUrl';
|
||||||
|
import useUpdateConnection from './useUpdateConnection';
|
||||||
|
import useResetConnection from './useResetConnection';
|
||||||
|
import useVerifyConnection from './useVerifyConnection';
|
||||||
|
|
||||||
function getSteps(auth, hasConnection, useShared) {
|
function getSteps(auth, hasConnection, useShared) {
|
||||||
if (hasConnection) {
|
if (hasConnection) {
|
||||||
@@ -28,11 +32,16 @@ function getSteps(auth, hasConnection, useShared) {
|
|||||||
export default function useAuthenticateApp(payload) {
|
export default function useAuthenticateApp(payload) {
|
||||||
const { appKey, appAuthClientId, connectionId, useShared = false } = payload;
|
const { appKey, appAuthClientId, connectionId, useShared = false } = payload;
|
||||||
const { data: auth } = useAppAuth(appKey);
|
const { data: auth } = useAppAuth(appKey);
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { mutateAsync: createConnection } = useCreateConnection(appKey);
|
const { mutateAsync: createConnection } = useCreateConnection(appKey);
|
||||||
|
const { mutateAsync: createConnectionAuthUrl } = useCreateConnectionAuthUrl();
|
||||||
|
const { mutateAsync: updateConnection } = useUpdateConnection();
|
||||||
|
const { mutateAsync: resetConnection } = useResetConnection();
|
||||||
const [authenticationInProgress, setAuthenticationInProgress] =
|
const [authenticationInProgress, setAuthenticationInProgress] =
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
const steps = getSteps(auth?.data, !!connectionId, useShared);
|
const steps = getSteps(auth?.data, !!connectionId, useShared);
|
||||||
|
const { mutateAsync: verifyConnection } = useVerifyConnection();
|
||||||
|
|
||||||
const authenticate = React.useMemo(() => {
|
const authenticate = React.useMemo(() => {
|
||||||
if (!steps?.length) return;
|
if (!steps?.length) return;
|
||||||
@@ -44,9 +53,7 @@ export default function useAuthenticateApp(payload) {
|
|||||||
const response = {
|
const response = {
|
||||||
key: appKey,
|
key: appKey,
|
||||||
appAuthClientId: appAuthClientId || payload.appAuthClientId,
|
appAuthClientId: appAuthClientId || payload.appAuthClientId,
|
||||||
connection: {
|
connectionId,
|
||||||
id: connectionId,
|
|
||||||
},
|
|
||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
let stepIndex = 0;
|
let stepIndex = 0;
|
||||||
@@ -69,10 +76,29 @@ export default function useAuthenticateApp(payload) {
|
|||||||
if (step.type === 'mutation') {
|
if (step.type === 'mutation') {
|
||||||
if (step.name === 'createConnection') {
|
if (step.name === 'createConnection') {
|
||||||
const stepResponse = await createConnection(variables);
|
const stepResponse = await createConnection(variables);
|
||||||
|
response[step.name] = stepResponse.data;
|
||||||
|
response.connectionId = stepResponse.data.id;
|
||||||
|
} else if (step.name === 'generateAuthUrl') {
|
||||||
|
const stepResponse = await createConnectionAuthUrl(
|
||||||
|
response.connectionId,
|
||||||
|
);
|
||||||
|
response[step.name] = stepResponse.data;
|
||||||
|
} else if (step.name === 'updateConnection') {
|
||||||
|
const stepResponse = await updateConnection({
|
||||||
|
...variables,
|
||||||
|
connectionId: response.connectionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
response[step.name] = stepResponse.data;
|
||||||
|
} else if (step.name === 'resetConnection') {
|
||||||
|
const stepResponse = await resetConnection(response.connectionId);
|
||||||
|
|
||||||
|
response[step.name] = stepResponse.data;
|
||||||
|
} else if (step.name === 'verifyConnection') {
|
||||||
|
const stepResponse = await verifyConnection(
|
||||||
|
response.connectionId,
|
||||||
|
);
|
||||||
response[step.name] = stepResponse?.data;
|
response[step.name] = stepResponse?.data;
|
||||||
} else {
|
|
||||||
const stepResponse = await processMutation(step.name, variables);
|
|
||||||
response[step.name] = stepResponse;
|
|
||||||
}
|
}
|
||||||
} else if (step.type === 'openWithPopup') {
|
} else if (step.type === 'openWithPopup') {
|
||||||
const stepResponse = await processPopupMessage(popup);
|
const stepResponse = await processPopupMessage(popup);
|
||||||
@@ -81,17 +107,38 @@ export default function useAuthenticateApp(payload) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
setAuthenticationInProgress(false);
|
setAuthenticationInProgress(false);
|
||||||
|
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ['apps', appKey, 'connections'],
|
||||||
|
});
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
stepIndex++;
|
|
||||||
|
|
||||||
if (stepIndex === steps.length) {
|
stepIndex++;
|
||||||
return response;
|
|
||||||
}
|
|
||||||
setAuthenticationInProgress(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await queryClient.invalidateQueries({
|
||||||
|
queryKey: ['apps', appKey, 'connections'],
|
||||||
|
});
|
||||||
|
|
||||||
|
setAuthenticationInProgress(false);
|
||||||
|
|
||||||
|
return response;
|
||||||
};
|
};
|
||||||
}, [steps, appKey, appAuthClientId, connectionId, formatMessage]);
|
}, [
|
||||||
|
steps,
|
||||||
|
appKey,
|
||||||
|
appAuthClientId,
|
||||||
|
connectionId,
|
||||||
|
queryClient,
|
||||||
|
formatMessage,
|
||||||
|
createConnection,
|
||||||
|
createConnectionAuthUrl,
|
||||||
|
updateConnection,
|
||||||
|
resetConnection,
|
||||||
|
verifyConnection,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authenticate,
|
authenticate,
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
|
||||||
import api from 'helpers/api';
|
import api from 'helpers/api';
|
||||||
|
|
||||||
export default function useCreateConnection(appKey) {
|
export default function useCreateConnection(appKey) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const query = useMutation({
|
const query = useMutation({
|
||||||
mutationFn: async ({ appAuthClientId, formattedData }) => {
|
mutationFn: async ({ appAuthClientId, formattedData }) => {
|
||||||
const { data } = await api.post(`/v1/apps/${appKey}/connections`, {
|
const { data } = await api.post(`/v1/apps/${appKey}/connections`, {
|
||||||
@@ -14,12 +12,6 @@ export default function useCreateConnection(appKey) {
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: ['apps', appKey, 'connections'],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
17
packages/web/src/hooks/useCreateConnectionAuthUrl.js
Normal file
17
packages/web/src/hooks/useCreateConnectionAuthUrl.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import api from 'helpers/api';
|
||||||
|
|
||||||
|
export default function useCreateConnectionAuthUrl() {
|
||||||
|
const query = useMutation({
|
||||||
|
mutationFn: async (connectionId) => {
|
||||||
|
const { data } = await api.post(
|
||||||
|
`/v1/connections/${connectionId}/auth-url`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
15
packages/web/src/hooks/useResetConnection.js
Normal file
15
packages/web/src/hooks/useResetConnection.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import api from 'helpers/api';
|
||||||
|
|
||||||
|
export default function useResetConnection() {
|
||||||
|
const query = useMutation({
|
||||||
|
mutationFn: async (connectionId) => {
|
||||||
|
const { data } = await api.post(`/v1/connections/${connectionId}/reset`);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
18
packages/web/src/hooks/useUpdateConnection.js
Normal file
18
packages/web/src/hooks/useUpdateConnection.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import api from 'helpers/api';
|
||||||
|
|
||||||
|
export default function useUpdateConnection() {
|
||||||
|
const query = useMutation({
|
||||||
|
mutationFn: async ({ connectionId, formattedData, appAuthClientId }) => {
|
||||||
|
const { data } = await api.patch(`/v1/connections/${connectionId}`, {
|
||||||
|
formattedData,
|
||||||
|
appAuthClientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
24
packages/web/src/hooks/useVerifyConnection.js
Normal file
24
packages/web/src/hooks/useVerifyConnection.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import api from 'helpers/api';
|
||||||
|
|
||||||
|
export default function useVerifyConnection() {
|
||||||
|
const query = useMutation({
|
||||||
|
mutationFn: async (connectionId) => {
|
||||||
|
try {
|
||||||
|
const { data } = await api.post(
|
||||||
|
`/v1/connections/${connectionId}/verify`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response.status === 500) {
|
||||||
|
throw new Error('Failed while verifying connection!');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
Reference in New Issue
Block a user