Merge pull request #688 from automatisch/revise-custom-errors

Revise custom errors
This commit is contained in:
Ömer Faruk Aydın
2022-11-07 22:56:31 +01:00
committed by GitHub
18 changed files with 197 additions and 207 deletions

View File

@@ -3,26 +3,20 @@ import { URLSearchParams } from 'url';
import scopes from '../common/scopes'; import scopes from '../common/scopes';
export default async function createAuthData($: IGlobalVariable) { export default async function createAuthData($: IGlobalVariable) {
try { const oauthRedirectUrlField = $.app.auth.fields.find(
const oauthRedirectUrlField = $.app.auth.fields.find( (field: IField) => field.key == 'oAuthRedirectUrl'
(field: IField) => field.key == 'oAuthRedirectUrl' );
); const callbackUrl = oauthRedirectUrlField.value as string;
const callbackUrl = oauthRedirectUrlField.value as string;
const searchParams = new URLSearchParams({ const searchParams = new URLSearchParams({
client_id: $.auth.data.consumerKey as string, client_id: $.auth.data.consumerKey as string,
redirect_uri: callbackUrl, redirect_uri: callbackUrl,
response_type: 'code', response_type: 'code',
permissions: '2146958591', permissions: '2146958591',
scope: scopes.join(' '), scope: scopes.join(' '),
}); });
const url = `${ const url = `${$.app.apiBaseUrl}/oauth2/authorize?${searchParams.toString()}`;
$.app.apiBaseUrl
}/oauth2/authorize?${searchParams.toString()}`;
await $.auth.set({ url }); await $.auth.set({ url });
} catch (error) {
throw new Error(`Error occured while verifying credentials: ${error}`);
}
} }

View File

@@ -1,31 +1,21 @@
import { IJSONObject, IField, IGlobalVariable } from '@automatisch/types'; import { IField, IGlobalVariable } from '@automatisch/types';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
export default async function createAuthData($: IGlobalVariable) { export default async function createAuthData($: IGlobalVariable) {
try { const oauthRedirectUrlField = $.app.auth.fields.find(
const oauthRedirectUrlField = $.app.auth.fields.find( (field: IField) => field.key == 'oAuthRedirectUrl'
(field: IField) => field.key == 'oAuthRedirectUrl' );
);
const callbackUrl = oauthRedirectUrlField.value; const callbackUrl = oauthRedirectUrlField.value;
const requestPath = '/oauth/request_token'; const requestPath = '/oauth/request_token';
const data = { oauth_callback: callbackUrl }; const data = { oauth_callback: callbackUrl };
const response = await $.http.post(requestPath, data); const response = await $.http.post(requestPath, data);
const responseData = Object.fromEntries(new URLSearchParams(response.data)); const responseData = Object.fromEntries(new URLSearchParams(response.data));
await $.auth.set({ await $.auth.set({
url: `${$.app.apiBaseUrl}/oauth/authorize?oauth_token=${responseData.oauth_token}&perms=delete`, url: `${$.app.apiBaseUrl}/oauth/authorize?oauth_token=${responseData.oauth_token}&perms=delete`,
accessToken: responseData.oauth_token, accessToken: responseData.oauth_token,
accessSecret: responseData.oauth_token_secret, accessSecret: responseData.oauth_token_secret,
}); });
} catch (error) {
const errorMessages = error.response.data.errors
.map((error: IJSONObject) => error.message)
.join(' ');
throw new Error(
`Error occured while verifying credentials: ${errorMessages}`
);
}
} }

View File

@@ -2,25 +2,21 @@ import { IGlobalVariable } from '@automatisch/types';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
const verifyCredentials = async ($: IGlobalVariable) => { const verifyCredentials = async ($: IGlobalVariable) => {
try { const response = await $.http.post(
const response = await $.http.post( `/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`,
`/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`, null
null );
);
const responseData = Object.fromEntries(new URLSearchParams(response.data)); const responseData = Object.fromEntries(new URLSearchParams(response.data));
await $.auth.set({ await $.auth.set({
consumerKey: $.auth.data.consumerKey, consumerKey: $.auth.data.consumerKey,
consumerSecret: $.auth.data.consumerSecret, consumerSecret: $.auth.data.consumerSecret,
accessToken: responseData.oauth_token, accessToken: responseData.oauth_token,
accessSecret: responseData.oauth_token_secret, accessSecret: responseData.oauth_token_secret,
userId: responseData.user_nsid, userId: responseData.user_nsid,
screenName: responseData.fullname, screenName: responseData.fullname,
}); });
} catch (error) {
throw new Error(error.response.data);
}
}; };
export default verifyCredentials; export default verifyCredentials;

View File

@@ -2,39 +2,35 @@ import { IGlobalVariable } from '@automatisch/types';
import getCurrentUser from '../common/get-current-user'; import getCurrentUser from '../common/get-current-user';
const verifyCredentials = async ($: IGlobalVariable) => { const verifyCredentials = async ($: IGlobalVariable) => {
try { const response = await $.http.post(
const response = await $.http.post( `${$.app.baseUrl}/login/oauth/access_token`,
`${$.app.baseUrl}/login/oauth/access_token`, {
{ client_id: $.auth.data.consumerKey,
client_id: $.auth.data.consumerKey, client_secret: $.auth.data.consumerSecret,
client_secret: $.auth.data.consumerSecret, code: $.auth.data.oauthVerifier,
code: $.auth.data.oauthVerifier, },
{
headers: {
Accept: 'application/json',
}, },
{ }
headers: { );
Accept: 'application/json',
},
}
);
const data = response.data; const data = response.data;
$.auth.data.accessToken = data.access_token; $.auth.data.accessToken = data.access_token;
const currentUser = await getCurrentUser($); const currentUser = await getCurrentUser($);
await $.auth.set({ await $.auth.set({
consumerKey: $.auth.data.consumerKey, consumerKey: $.auth.data.consumerKey,
consumerSecret: $.auth.data.consumerSecret, consumerSecret: $.auth.data.consumerSecret,
accessToken: data.access_token, accessToken: data.access_token,
scope: data.scope, scope: data.scope,
tokenType: data.token_type, tokenType: data.token_type,
userId: currentUser.id, userId: currentUser.id,
screenName: currentUser.login, screenName: currentUser.login,
}); });
} catch (error) {
throw new Error(error.response.data);
}
}; };
export default verifyCredentials; export default verifyCredentials;

View File

@@ -2,21 +2,17 @@ import { IField, IGlobalVariable } from '@automatisch/types';
import qs from 'qs'; import qs from 'qs';
export default async function createAuthData($: IGlobalVariable) { export default async function createAuthData($: IGlobalVariable) {
try { const oauthRedirectUrlField = $.app.auth.fields.find(
const oauthRedirectUrlField = $.app.auth.fields.find( (field: IField) => field.key == 'oAuthRedirectUrl'
(field: IField) => field.key == 'oAuthRedirectUrl' );
); const redirectUri = oauthRedirectUrlField.value;
const redirectUri = oauthRedirectUrlField.value; const searchParams = qs.stringify({
const searchParams = qs.stringify({ client_id: $.auth.data.consumerKey as string,
client_id: $.auth.data.consumerKey as string, redirect_uri: redirectUri,
redirect_uri: redirectUri, response_type: 'code',
response_type: 'code', });
});
await $.auth.set({ await $.auth.set({
url: `${$.auth.data.oauth2Url}/authorize?${searchParams}`, url: `${$.auth.data.oauth2Url}/authorize?${searchParams}`,
}); });
} catch (error) {
throw new Error(`Error occured while verifying credentials: ${error}`);
}
} }

View File

@@ -3,39 +3,35 @@ import getCurrentUser from '../common/get-current-user';
import qs from 'qs'; import qs from 'qs';
const verifyCredentials = async ($: IGlobalVariable) => { const verifyCredentials = async ($: IGlobalVariable) => {
try { const oauthRedirectUrlField = $.app.auth.fields.find(
const oauthRedirectUrlField = $.app.auth.fields.find( (field) => field.key == 'oAuthRedirectUrl'
(field) => field.key == 'oAuthRedirectUrl' );
); const redirectUri = oauthRedirectUrlField.value;
const redirectUri = oauthRedirectUrlField.value; const searchParams = qs.stringify({
const searchParams = qs.stringify({ code: $.auth.data.code,
code: $.auth.data.code, grant_type: 'authorization_code',
grant_type: 'authorization_code', client_id: $.auth.data.consumerKey as string,
client_id: $.auth.data.consumerKey as string, client_secret: $.auth.data.consumerSecret as string,
client_secret: $.auth.data.consumerSecret as string, redirect_uri: redirectUri,
redirect_uri: redirectUri, });
}); const { data } = await $.http.post(
const { data } = await $.http.post( `${$.auth.data.oauth2Url}/token?${searchParams}`
`${$.auth.data.oauth2Url}/token?${searchParams}` );
);
await $.auth.set({ await $.auth.set({
accessToken: data.access_token, accessToken: data.access_token,
tokenType: data.token_type, tokenType: data.token_type,
instanceUrl: data.instance_url, instanceUrl: data.instance_url,
signature: data.signature, signature: data.signature,
userId: data.id, userId: data.id,
screenName: data.instance_url, screenName: data.instance_url,
}); });
const currentUser = await getCurrentUser($); const currentUser = await getCurrentUser($);
await $.auth.set({ await $.auth.set({
screenName: `${currentUser.displayName} - ${data.instance_url}`, screenName: `${currentUser.displayName} - ${data.instance_url}`,
}); });
} catch (error) {
throw new Error(error.response.data);
}
}; };
export default verifyCredentials; export default verifyCredentials;

View File

@@ -1,15 +1,11 @@
import { IGlobalVariable } from '@automatisch/types'; import { IGlobalVariable } from '@automatisch/types';
const verifyCredentials = async ($: IGlobalVariable) => { const verifyCredentials = async ($: IGlobalVariable) => {
try { await $.http.get('/2010-04-01/Accounts.json?PageSize=1');
await $.http.get('/2010-04-01/Accounts.json?PageSize=1');
await $.auth.set({ await $.auth.set({
screenName: $.auth.data.accountSid, screenName: $.auth.data.accountSid,
}); });
} catch (error) {
throw new Error(JSON.stringify(error.response.data));
}
}; };
export default verifyCredentials; export default verifyCredentials;

View File

@@ -1,31 +1,21 @@
import { IJSONObject, IField, IGlobalVariable } from '@automatisch/types'; import { IField, IGlobalVariable } from '@automatisch/types';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
export default async function createAuthData($: IGlobalVariable) { export default async function createAuthData($: IGlobalVariable) {
try { const oauthRedirectUrlField = $.app.auth.fields.find(
const oauthRedirectUrlField = $.app.auth.fields.find( (field: IField) => field.key == 'oAuthRedirectUrl'
(field: IField) => field.key == 'oAuthRedirectUrl' );
);
const callbackUrl = oauthRedirectUrlField.value; const callbackUrl = oauthRedirectUrlField.value;
const requestPath = '/oauth/request_token'; const requestPath = '/oauth/request_token';
const data = { oauth_callback: callbackUrl }; const data = { oauth_callback: callbackUrl };
const response = await $.http.post(requestPath, data); const response = await $.http.post(requestPath, data);
const responseData = Object.fromEntries(new URLSearchParams(response.data)); const responseData = Object.fromEntries(new URLSearchParams(response.data));
await $.auth.set({ await $.auth.set({
url: `${$.app.baseUrl}/oauth/authorize?oauth_token=${responseData.oauth_token}`, url: `${$.app.baseUrl}/oauth/authorize?oauth_token=${responseData.oauth_token}`,
accessToken: responseData.oauth_token, accessToken: responseData.oauth_token,
accessSecret: responseData.oauth_token_secret, accessSecret: responseData.oauth_token_secret,
}); });
} catch (error) {
const errorMessages = error.response.data.errors
.map((error: IJSONObject) => error.message)
.join(' ');
throw new Error(
`Error occured while verifying credentials: ${errorMessages}`
);
}
} }

View File

@@ -2,23 +2,19 @@ import { IGlobalVariable } from '@automatisch/types';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
const verifyCredentials = async ($: IGlobalVariable) => { const verifyCredentials = async ($: IGlobalVariable) => {
try { const response = await $.http.post(
const response = await $.http.post( `/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`,
`/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`, null
null );
);
const responseData = Object.fromEntries(new URLSearchParams(response.data)); const responseData = Object.fromEntries(new URLSearchParams(response.data));
await $.auth.set({ await $.auth.set({
accessToken: responseData.oauth_token, accessToken: responseData.oauth_token,
accessSecret: responseData.oauth_token_secret, accessSecret: responseData.oauth_token_secret,
userId: responseData.user_id, userId: responseData.user_id,
screenName: responseData.screen_name, screenName: responseData.screen_name,
}); });
} catch (error) {
throw new Error(error.response.data);
}
}; };
export default verifyCredentials; export default verifyCredentials;

View File

@@ -1,17 +1,32 @@
import { IJSONObject } from '@automatisch/types'; import { IJSONObject } from '@automatisch/types';
export default class BaseError extends Error { export default class BaseError extends Error {
error = {}; details = {};
constructor(error?: string | IJSONObject) { constructor(error?: string | IJSONObject) {
super(); let computedError: Record<string, unknown>;
try { try {
this.error = JSON.parse(error as string); computedError = JSON.parse(error as string);
} catch { } catch {
this.error = typeof error === 'string' ? { error } : error; computedError = typeof error === 'string' ? { error } : error;
} }
let computedMessage: string;
try {
// challenge to input to see if it is stringified JSON
JSON.parse(error as string);
computedMessage = error as string;
} catch {
if (typeof error === 'string') {
computedMessage = error;
} else {
computedMessage = JSON.stringify(error, null, 2);
}
}
super(computedMessage);
this.details = computedError;
this.name = this.constructor.name; this.name = this.constructor.name;
} }
} }

View File

@@ -0,0 +1,14 @@
import { IJSONObject } from '@automatisch/types';
import BaseError from './base';
export default class CreateAuthDataError extends BaseError {
constructor(error: IJSONObject) {
const computedError =
((error.response as IJSONObject)?.data as IJSONObject) ||
(error.message as string);
super(computedError);
this.message = `Error occured while creating authorization URL!`;
}
}

View File

@@ -1,3 +0,0 @@
import BaseError from './base';
export default class HttpError extends BaseError {}

View File

@@ -0,0 +1,12 @@
import { IJSONObject } from '@automatisch/types';
import BaseError from './base';
export default class HttpError extends BaseError {
constructor(error: IJSONObject) {
const computedError =
((error.response as IJSONObject)?.data as IJSONObject) ||
(error.message as string);
super(computedError);
}
}

View File

@@ -2,6 +2,7 @@ import Context from '../../types/express/context';
import axios from 'axios'; import axios from 'axios';
import globalVariable from '../../helpers/global-variable'; import globalVariable from '../../helpers/global-variable';
import App from '../../models/app'; import App from '../../models/app';
import CreateAuthDataError from '../../errors/create-auth-data';
type Params = { type Params = {
input: { input: {
@@ -30,12 +31,11 @@ const createAuthData = async (
const app = await App.findOneByKey(connection.key); const app = await App.findOneByKey(connection.key);
const $ = await globalVariable({ connection, app }); const $ = await globalVariable({ connection, app });
await authInstance.createAuthData($);
try { try {
await authInstance.createAuthData($);
await axios.get(connection.formattedData.url as string); await axios.get(connection.formattedData.url as string);
} catch (error) { } catch (error) {
throw new Error('Error occured while creating authorization URL!'); throw new CreateAuthDataError(error);
} }
return connection.formattedData; return connection.formattedData;

View File

@@ -23,10 +23,7 @@ const graphQLInstance = graphqlHTTP({
customFormatErrorFn: (error) => { customFormatErrorFn: (error) => {
logger.error(error.path + ' : ' + error.message + '\n' + error.stack); logger.error(error.path + ' : ' + error.message + '\n' + error.stack);
return { return error.originalError;
message: error.message,
locations: error.locations,
};
}, },
}); });

View File

@@ -2,7 +2,7 @@ import axios, { AxiosRequestConfig } from 'axios';
export { AxiosInstance as IHttpClient } from 'axios'; export { AxiosInstance as IHttpClient } from 'axios';
import { IHttpClientParams } from '@automatisch/types'; import { IHttpClientParams } from '@automatisch/types';
import { URL } from 'url'; import { URL } from 'url';
import HttpError from '../../errors/http-error'; import HttpError from '../../errors/http';
const removeBaseUrlForAbsoluteUrls = ( const removeBaseUrlForAbsoluteUrls = (
requestConfig: AxiosRequestConfig requestConfig: AxiosRequestConfig
@@ -40,7 +40,7 @@ export default function createHttpClient({
instance.interceptors.response.use( instance.interceptors.response.use(
(response) => response, (response) => response,
(error) => { (error) => {
throw new HttpError(error.response.data); throw new HttpError(error);
} }
); );

View File

@@ -1,7 +1,7 @@
import Flow from '../models/flow'; import Flow from '../models/flow';
import globalVariable from '../helpers/global-variable'; import globalVariable from '../helpers/global-variable';
import EarlyExitError from '../errors/early-exit'; import EarlyExitError from '../errors/early-exit';
import HttpError from '../errors/http-error'; import HttpError from '../errors/http';
type ProcessFlowOptions = { type ProcessFlowOptions = {
flowId: string; flowId: string;
@@ -27,7 +27,7 @@ export const processFlow = async (options: ProcessFlowOptions) => {
} catch (error) { } catch (error) {
if (error instanceof EarlyExitError === false) { if (error instanceof EarlyExitError === false) {
if (error instanceof HttpError) { if (error instanceof HttpError) {
$.triggerOutput.error = error.error; $.triggerOutput.error = error.details;
} else { } else {
try { try {
$.triggerOutput.error = JSON.parse(error.message); $.triggerOutput.error = JSON.parse(error.message);

View File

@@ -6,6 +6,7 @@ import DialogContentText from '@mui/material/DialogContentText';
import Dialog from '@mui/material/Dialog'; import Dialog from '@mui/material/Dialog';
import LoadingButton from '@mui/lab/LoadingButton'; import LoadingButton from '@mui/lab/LoadingButton';
import { FieldValues, SubmitHandler } from 'react-hook-form'; import { FieldValues, SubmitHandler } from 'react-hook-form';
import { IJSONObject } from '@automatisch/types';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import computeAuthStepVariables from 'helpers/computeAuthStepVariables'; import computeAuthStepVariables from 'helpers/computeAuthStepVariables';
@@ -37,7 +38,7 @@ export default function AddAppConnection(
const { application, connectionId, onClose } = props; const { application, connectionId, onClose } = props;
const { name, authDocUrl, key, auth } = application; const { name, authDocUrl, key, auth } = application;
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
const [errorMessage, setErrorMessage] = React.useState<string | null>(null); const [error, setError] = React.useState<IJSONObject | null>(null);
const [inProgress, setInProgress] = React.useState(false); const [inProgress, setInProgress] = React.useState(false);
const hasConnection = Boolean(connectionId); const hasConnection = Boolean(connectionId);
const steps = hasConnection const steps = hasConnection
@@ -59,7 +60,7 @@ export default function AddAppConnection(
if (!steps) return; if (!steps) return;
setInProgress(true); setInProgress(true);
setErrorMessage(null); setError(null);
const response: Response = { const response: Response = {
key, key,
@@ -79,9 +80,9 @@ export default function AddAppConnection(
response[step.name] = stepResponse; response[step.name] = stepResponse;
} catch (err) { } catch (err) {
const error = err as Error; const error = err as IJSONObject;
console.log(error); console.log(error);
setErrorMessage(error.message); setError((error.graphQLErrors as IJSONObject[])?.[0]);
setInProgress(false); setInProgress(false);
break; break;
@@ -116,9 +117,13 @@ export default function AddAppConnection(
</Alert> </Alert>
)} )}
{errorMessage && ( {error && (
<Alert severity="error" sx={{ mt: 1, fontWeight: 500 }}> <Alert
{errorMessage} severity="error"
sx={{ mt: 1, fontWeight: 500, wordBreak: 'break-all' }}
>
{error.message}
<pre>{JSON.stringify(error.details, null, 2)}</pre>
</Alert> </Alert>
)} )}