Compare commits
3 Commits
remove-typ
...
custom-ais
Author | SHA1 | Date | |
---|---|---|---|
![]() |
74494989d2 | ||
![]() |
e122ad4178 | ||
![]() |
a8b85cdb0d |
@@ -1,28 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.test.ts', '**/test/**/*.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/ban-ts-comment': ['off'],
|
||||
'@typescript-eslint/no-explicit-any': ['off'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': ['off'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@@ -6,9 +6,10 @@ import Role from '../../src/models/role';
|
||||
import '../../src/config/orm';
|
||||
|
||||
async function fetchAdminRole() {
|
||||
const role = await Role.query()
|
||||
const role = await Role
|
||||
.query()
|
||||
.where({
|
||||
key: 'admin',
|
||||
key: 'admin'
|
||||
})
|
||||
.limit(1)
|
||||
.first();
|
||||
@@ -40,7 +41,7 @@ export async function createUser(
|
||||
logger.info('No need to seed a user.');
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.nativeError.code !== UNIQUE_VIOLATION_CODE) {
|
||||
if ((err as any).nativeError.code !== UNIQUE_VIOLATION_CODE) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ export const createDatabase = async (database = appConfig.postgresDatabase) => {
|
||||
await client.query(`CREATE DATABASE ${database}`);
|
||||
logger.info(`Database: ${database} created!`);
|
||||
} catch (err) {
|
||||
if (err.code !== DUPLICATE_DB_CODE) {
|
||||
if ((err as any).code !== DUPLICATE_DB_CODE) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ export const createDatabaseUser = async (user = appConfig.postgresUsername) => {
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
if (err.code !== DUPLICATE_OBJECT_CODE) {
|
||||
if ((err as any).code !== DUPLICATE_OBJECT_CODE) {
|
||||
throw err;
|
||||
}
|
||||
|
3
packages/backend/src/apps/azure-openai/actions/index.ts
Normal file
3
packages/backend/src/apps/azure-openai/actions/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import sendPrompt from './send-prompt';
|
||||
|
||||
export default [sendPrompt];
|
@@ -0,0 +1,87 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
const castFloatOrUndefined = (value: string | null) => {
|
||||
return value === '' ? undefined : parseFloat(value);
|
||||
}
|
||||
|
||||
export default defineAction({
|
||||
name: 'Send prompt',
|
||||
key: 'sendPrompt',
|
||||
description: 'Creates a completion for the provided prompt and parameters.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Prompt',
|
||||
key: 'prompt',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
description: 'The text to analyze.'
|
||||
},
|
||||
{
|
||||
label: 'Temperature',
|
||||
key: 'temperature',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'What sampling temperature to use, between 0 and 2. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. We generally recommend altering this or Top P but not both.'
|
||||
},
|
||||
{
|
||||
label: 'Maximum tokens',
|
||||
key: 'maxTokens',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'The maximum number of tokens to generate in the completion.'
|
||||
},
|
||||
{
|
||||
label: 'Stop Sequence',
|
||||
key: 'stopSequence',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'Single stop sequence where the API will stop generating further tokens. The returned text will not contain the stop sequence.'
|
||||
},
|
||||
{
|
||||
label: 'Top P',
|
||||
key: 'topP',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or temperature but not both.'
|
||||
},
|
||||
{
|
||||
label: 'Frequency Penalty',
|
||||
key: 'frequencyPenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
||||
},
|
||||
{
|
||||
label: 'Presence Penalty',
|
||||
key: 'presencePenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.`
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const payload = {
|
||||
model: $.step.parameters.model as string,
|
||||
prompt: $.step.parameters.prompt as string,
|
||||
temperature: castFloatOrUndefined($.step.parameters.temperature as string),
|
||||
max_tokens: castFloatOrUndefined($.step.parameters.maxTokens as string),
|
||||
stop: ($.step.parameters.stopSequence as string || null),
|
||||
top_p: castFloatOrUndefined($.step.parameters.topP as string),
|
||||
frequency_penalty: castFloatOrUndefined($.step.parameters.frequencyPenalty as string),
|
||||
presence_penalty: castFloatOrUndefined($.step.parameters.presencePenalty as string),
|
||||
};
|
||||
const { data } = await $.http.post(`/deployments/${$.auth.data.deploymentId}/completions`, payload);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
},
|
||||
});
|
@@ -0,0 +1,6 @@
|
||||
<svg width="256px" height="260px" viewBox="0 0 256 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<title>OpenAI</title>
|
||||
<g>
|
||||
<path d="M239.183914,106.202783 C245.054304,88.5242096 243.02228,69.1733805 233.607599,53.0998864 C219.451678,28.4588021 190.999703,15.7836129 163.213007,21.739505 C147.554077,4.32145883 123.794909,-3.42398554 100.87901,1.41873898 C77.9631105,6.26146349 59.3690093,22.9572536 52.0959621,45.2214219 C33.8436494,48.9644867 18.0901721,60.392749 8.86672513,76.5818033 C-5.443491,101.182962 -2.19544431,132.215255 16.8986662,153.320094 C11.0060865,170.990656 13.0197283,190.343991 22.4238231,206.422991 C36.5975553,231.072344 65.0680342,243.746566 92.8695738,237.783372 C105.235639,251.708249 123.001113,259.630942 141.623968,259.52692 C170.105359,259.552169 195.337611,241.165718 204.037777,214.045661 C222.28734,210.296356 238.038489,198.869783 247.267014,182.68528 C261.404453,158.127515 258.142494,127.262775 239.183914,106.202783 L239.183914,106.202783 Z M141.623968,242.541207 C130.255682,242.559177 119.243876,238.574642 110.519381,231.286197 L112.054146,230.416496 L163.724595,200.590881 C166.340648,199.056444 167.954321,196.256818 167.970781,193.224005 L167.970781,120.373788 L189.815614,133.010026 C190.034132,133.121423 190.186235,133.330564 190.224885,133.572774 L190.224885,193.940229 C190.168603,220.758427 168.442166,242.484864 141.623968,242.541207 Z M37.1575749,197.93062 C31.456498,188.086359 29.4094818,176.546984 31.3766237,165.342426 L32.9113895,166.263285 L84.6329973,196.088901 C87.2389349,197.618207 90.4682717,197.618207 93.0742093,196.088901 L156.255402,159.663793 L156.255402,184.885111 C156.243557,185.149771 156.111725,185.394602 155.89729,185.550176 L103.561776,215.733903 C80.3054953,229.131632 50.5924954,221.165435 37.1575749,197.93062 Z M23.5493181,85.3811273 C29.2899861,75.4733097 38.3511911,67.9162648 49.1287482,64.0478825 L49.1287482,125.438515 C49.0891492,128.459425 50.6965386,131.262556 53.3237748,132.754232 L116.198014,169.025864 L94.3531808,181.662102 C94.1132325,181.789434 93.8257461,181.789434 93.5857979,181.662102 L41.3526015,151.529534 C18.1419426,138.076098 10.1817681,108.385562 23.5493181,85.125333 L23.5493181,85.3811273 Z M203.0146,127.075598 L139.935725,90.4458545 L161.7294,77.8607748 C161.969348,77.7334434 162.256834,77.7334434 162.496783,77.8607748 L214.729979,108.044502 C231.032329,117.451747 240.437294,135.426109 238.871504,154.182739 C237.305714,172.939368 225.050719,189.105572 207.414262,195.67963 L207.414262,134.288998 C207.322521,131.276867 205.650697,128.535853 203.0146,127.075598 Z M224.757116,94.3850867 L223.22235,93.4642272 L171.60306,63.3828173 C168.981293,61.8443751 165.732456,61.8443751 163.110689,63.3828173 L99.9806554,99.8079259 L99.9806554,74.5866077 C99.9533004,74.3254088 100.071095,74.0701869 100.287609,73.9215426 L152.520805,43.7889738 C168.863098,34.3743518 189.174256,35.2529043 204.642579,46.0434841 C220.110903,56.8340638 227.949269,75.5923959 224.757116,94.1804513 L224.757116,94.3850867 Z M88.0606409,139.097931 L66.2158076,126.512851 C65.9950399,126.379091 65.8450965,126.154176 65.8065367,125.898945 L65.8065367,65.684966 C65.8314495,46.8285367 76.7500605,29.6846032 93.8270852,21.6883055 C110.90411,13.6920079 131.063833,16.2835462 145.5632,28.338998 L144.028434,29.2086986 L92.3579852,59.0343142 C89.7419327,60.5687513 88.1282597,63.3683767 88.1117998,66.4011901 L88.0606409,139.097931 Z M99.9294965,113.5185 L128.06687,97.3011417 L156.255402,113.5185 L156.255402,145.953218 L128.169187,162.170577 L99.9806554,145.953218 L99.9294965,113.5185 Z" fill="#000000"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
58
packages/backend/src/apps/azure-openai/auth/index.ts
Normal file
58
packages/backend/src/apps/azure-openai/auth/index.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import verifyCredentials from './verify-credentials';
|
||||
import isStillVerified from './is-still-verified';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
{
|
||||
key: 'screenName',
|
||||
label: 'Screen Name',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description:
|
||||
'Screen name of your connection to be used on Automatisch UI.',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'yourResourceName',
|
||||
label: 'Your Resource Name',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: 'The name of your Azure OpenAI Resource.',
|
||||
docUrl: 'https://automatisch.io/docs/azure-openai#your-resource-name',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'deploymentId',
|
||||
label: 'Deployment ID',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: 'The deployment name you chose when you deployed the model.',
|
||||
docUrl: 'https://automatisch.io/docs/azure-openai#deployment-id',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'apiKey',
|
||||
label: 'API Key',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description: 'Azure OpenAI API key of your account.',
|
||||
docUrl: 'https://automatisch.io/docs/azure-openai#api-key',
|
||||
clickToCopy: false,
|
||||
},
|
||||
],
|
||||
|
||||
verifyCredentials,
|
||||
isStillVerified,
|
||||
};
|
@@ -0,0 +1,8 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
await $.http.get('/fine_tuning/jobs');
|
||||
return true;
|
||||
};
|
||||
|
||||
export default isStillVerified;
|
@@ -0,0 +1,7 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
await $.http.get('/fine_tuning/jobs');
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
@@ -0,0 +1,15 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data?.apiKey) {
|
||||
requestConfig.headers['api-key'] = $.auth.data.apiKey as string;
|
||||
}
|
||||
|
||||
requestConfig.params = {
|
||||
'api-version': '2023-10-01-preview'
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default addAuthHeader;
|
@@ -0,0 +1,13 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const setBaseUrl: TBeforeRequest = ($, requestConfig) => {
|
||||
const yourResourceName = $.auth.data.yourResourceName as string;
|
||||
|
||||
if (yourResourceName) {
|
||||
requestConfig.baseURL = `https://${yourResourceName}.openai.azure.com/openai`;
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default setBaseUrl;
|
0
packages/backend/src/apps/azure-openai/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/azure-openai/index.d.ts
vendored
Normal file
19
packages/backend/src/apps/azure-openai/index.ts
Normal file
19
packages/backend/src/apps/azure-openai/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import setBaseUrl from './common/set-base-url';
|
||||
import addAuthHeader from './common/add-auth-header';
|
||||
import auth from './auth';
|
||||
import actions from './actions';
|
||||
|
||||
export default defineApp({
|
||||
name: 'Azure OpenAI',
|
||||
key: 'azure-openai',
|
||||
baseUrl: 'https://azure.microsoft.com/en-us/products/ai-services/openai-service',
|
||||
apiBaseUrl: '',
|
||||
iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/azure-openai/connection',
|
||||
primaryColor: '000000',
|
||||
supportsConnections: true,
|
||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||
auth,
|
||||
actions,
|
||||
});
|
@@ -1,3 +1,4 @@
|
||||
import qs from 'qs';
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
@@ -18,8 +19,7 @@ export default defineAction({
|
||||
key: 'message',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description:
|
||||
'Message body to be sent, set to triggered if empty or not passed.',
|
||||
description: 'Message body to be sent, set to triggered if empty or not passed.',
|
||||
variables: true,
|
||||
},
|
||||
{
|
||||
@@ -67,15 +67,22 @@ export default defineAction({
|
||||
key: 'delay',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
description:
|
||||
'Timestamp or duration for delayed delivery. For example, 30min or 9am.',
|
||||
description: 'Timestamp or duration for delayed delivery. For example, 30min or 9am.',
|
||||
variables: true,
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const { topic, message, title, email, click, attach, filename, delay } =
|
||||
$.step.parameters;
|
||||
const {
|
||||
topic,
|
||||
message,
|
||||
title,
|
||||
email,
|
||||
click,
|
||||
attach,
|
||||
filename,
|
||||
delay
|
||||
} = $.step.parameters;
|
||||
const payload = {
|
||||
topic,
|
||||
message,
|
||||
@@ -84,7 +91,7 @@ export default defineAction({
|
||||
click,
|
||||
attach,
|
||||
filename,
|
||||
delay,
|
||||
delay
|
||||
};
|
||||
|
||||
const response = await $.http.post('/', payload);
|
||||
|
@@ -105,7 +105,7 @@ export default defineAction({
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
||||
},
|
||||
{
|
||||
label: 'presencePenalty',
|
||||
label: 'Presence Penalty',
|
||||
key: 'presencePenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
|
@@ -75,7 +75,7 @@ export default defineAction({
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
||||
},
|
||||
{
|
||||
label: 'presencePenalty',
|
||||
label: 'Presence Penalty',
|
||||
key: 'presencePenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
|
@@ -0,0 +1,4 @@
|
||||
import sendPrompt from './send-prompt';
|
||||
import sendChatPrompt from './send-chat-prompt';
|
||||
|
||||
export default [sendChatPrompt, sendPrompt];
|
@@ -0,0 +1,137 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
type TMessage = {
|
||||
role: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
const castFloatOrUndefined = (value: string | null) => {
|
||||
return value === '' ? undefined : parseFloat(value);
|
||||
}
|
||||
|
||||
export default defineAction({
|
||||
name: 'Send chat prompt',
|
||||
key: 'sendChatPrompt',
|
||||
description: 'Creates a completion for the provided prompt and parameters.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Model',
|
||||
key: 'model',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listModels',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Messages',
|
||||
key: 'messages',
|
||||
type: 'dynamic' as const,
|
||||
required: true,
|
||||
description: 'Add or remove messages as needed',
|
||||
value: [{ role: 'system', body: '' }],
|
||||
fields: [
|
||||
{
|
||||
label: 'Role',
|
||||
key: 'role',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
label: 'System',
|
||||
value: 'system',
|
||||
},
|
||||
{
|
||||
label: 'User',
|
||||
value: 'user',
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Content',
|
||||
key: 'content',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Temperature',
|
||||
key: 'temperature',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'What sampling temperature to use. Higher values mean the model will take more risk. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer. We generally recommend altering this or Top P but not both.'
|
||||
},
|
||||
{
|
||||
label: 'Maximum tokens',
|
||||
key: 'maxTokens',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'The maximum number of tokens to generate in the completion.'
|
||||
},
|
||||
{
|
||||
label: 'Stop Sequence',
|
||||
key: 'stopSequence',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'Single stop sequence where the API will stop generating further tokens. The returned text will not contain the stop sequence.'
|
||||
},
|
||||
{
|
||||
label: 'Top P',
|
||||
key: 'topP',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with Top P probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.'
|
||||
},
|
||||
{
|
||||
label: 'Frequency Penalty',
|
||||
key: 'frequencyPenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
||||
},
|
||||
{
|
||||
label: 'Presence Penalty',
|
||||
key: 'presencePenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.`
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const payload = {
|
||||
model: $.step.parameters.model as string,
|
||||
temperature: castFloatOrUndefined($.step.parameters.temperature as string),
|
||||
max_tokens: castFloatOrUndefined($.step.parameters.maxTokens as string),
|
||||
stop: ($.step.parameters.stopSequence as string || null),
|
||||
top_p: castFloatOrUndefined($.step.parameters.topP as string),
|
||||
frequency_penalty: castFloatOrUndefined($.step.parameters.frequencyPenalty as string),
|
||||
presence_penalty: castFloatOrUndefined($.step.parameters.presencePenalty as string),
|
||||
messages: ($.step.parameters.messages as TMessage[]).map(message => ({
|
||||
role: message.role,
|
||||
content: message.content,
|
||||
})),
|
||||
};
|
||||
const { data } = await $.http.post('/v1/chat/completions', payload);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
},
|
||||
});
|
@@ -0,0 +1,104 @@
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
const castFloatOrUndefined = (value: string | null) => {
|
||||
return value === '' ? undefined : parseFloat(value);
|
||||
}
|
||||
|
||||
export default defineAction({
|
||||
name: 'Send prompt',
|
||||
key: 'sendPrompt',
|
||||
description: 'Creates a completion for the provided prompt and parameters.',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Model',
|
||||
key: 'model',
|
||||
type: 'dropdown' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
source: {
|
||||
type: 'query',
|
||||
name: 'getDynamicData',
|
||||
arguments: [
|
||||
{
|
||||
name: 'key',
|
||||
value: 'listModels',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Prompt',
|
||||
key: 'prompt',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
variables: true,
|
||||
description: 'The text to analyze.'
|
||||
},
|
||||
{
|
||||
label: 'Temperature',
|
||||
key: 'temperature',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'What sampling temperature to use. Higher values mean the model will take more risk. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer. We generally recommend altering this or Top P but not both.'
|
||||
},
|
||||
{
|
||||
label: 'Maximum tokens',
|
||||
key: 'maxTokens',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'The maximum number of tokens to generate in the completion.'
|
||||
},
|
||||
{
|
||||
label: 'Stop Sequence',
|
||||
key: 'stopSequence',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'Single stop sequence where the API will stop generating further tokens. The returned text will not contain the stop sequence.'
|
||||
},
|
||||
{
|
||||
label: 'Top P',
|
||||
key: 'topP',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with Top P probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.'
|
||||
},
|
||||
{
|
||||
label: 'Frequency Penalty',
|
||||
key: 'frequencyPenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
||||
},
|
||||
{
|
||||
label: 'Presence Penalty',
|
||||
key: 'presencePenalty',
|
||||
type: 'string' as const,
|
||||
required: false,
|
||||
variables: true,
|
||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.`
|
||||
},
|
||||
],
|
||||
|
||||
async run($) {
|
||||
const payload = {
|
||||
model: $.step.parameters.model as string,
|
||||
prompt: $.step.parameters.prompt as string,
|
||||
temperature: castFloatOrUndefined($.step.parameters.temperature as string),
|
||||
max_tokens: castFloatOrUndefined($.step.parameters.maxTokens as string),
|
||||
stop: ($.step.parameters.stopSequence as string || null),
|
||||
top_p: castFloatOrUndefined($.step.parameters.topP as string),
|
||||
frequency_penalty: castFloatOrUndefined($.step.parameters.frequencyPenalty as string),
|
||||
presence_penalty: castFloatOrUndefined($.step.parameters.presencePenalty as string),
|
||||
};
|
||||
const { data } = await $.http.post('/v1/completions', payload);
|
||||
|
||||
$.setActionItem({
|
||||
raw: data,
|
||||
});
|
||||
},
|
||||
});
|
@@ -0,0 +1,6 @@
|
||||
<svg width="256px" height="260px" viewBox="0 0 256 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<title>OpenAI</title>
|
||||
<g>
|
||||
<path d="M239.183914,106.202783 C245.054304,88.5242096 243.02228,69.1733805 233.607599,53.0998864 C219.451678,28.4588021 190.999703,15.7836129 163.213007,21.739505 C147.554077,4.32145883 123.794909,-3.42398554 100.87901,1.41873898 C77.9631105,6.26146349 59.3690093,22.9572536 52.0959621,45.2214219 C33.8436494,48.9644867 18.0901721,60.392749 8.86672513,76.5818033 C-5.443491,101.182962 -2.19544431,132.215255 16.8986662,153.320094 C11.0060865,170.990656 13.0197283,190.343991 22.4238231,206.422991 C36.5975553,231.072344 65.0680342,243.746566 92.8695738,237.783372 C105.235639,251.708249 123.001113,259.630942 141.623968,259.52692 C170.105359,259.552169 195.337611,241.165718 204.037777,214.045661 C222.28734,210.296356 238.038489,198.869783 247.267014,182.68528 C261.404453,158.127515 258.142494,127.262775 239.183914,106.202783 L239.183914,106.202783 Z M141.623968,242.541207 C130.255682,242.559177 119.243876,238.574642 110.519381,231.286197 L112.054146,230.416496 L163.724595,200.590881 C166.340648,199.056444 167.954321,196.256818 167.970781,193.224005 L167.970781,120.373788 L189.815614,133.010026 C190.034132,133.121423 190.186235,133.330564 190.224885,133.572774 L190.224885,193.940229 C190.168603,220.758427 168.442166,242.484864 141.623968,242.541207 Z M37.1575749,197.93062 C31.456498,188.086359 29.4094818,176.546984 31.3766237,165.342426 L32.9113895,166.263285 L84.6329973,196.088901 C87.2389349,197.618207 90.4682717,197.618207 93.0742093,196.088901 L156.255402,159.663793 L156.255402,184.885111 C156.243557,185.149771 156.111725,185.394602 155.89729,185.550176 L103.561776,215.733903 C80.3054953,229.131632 50.5924954,221.165435 37.1575749,197.93062 Z M23.5493181,85.3811273 C29.2899861,75.4733097 38.3511911,67.9162648 49.1287482,64.0478825 L49.1287482,125.438515 C49.0891492,128.459425 50.6965386,131.262556 53.3237748,132.754232 L116.198014,169.025864 L94.3531808,181.662102 C94.1132325,181.789434 93.8257461,181.789434 93.5857979,181.662102 L41.3526015,151.529534 C18.1419426,138.076098 10.1817681,108.385562 23.5493181,85.125333 L23.5493181,85.3811273 Z M203.0146,127.075598 L139.935725,90.4458545 L161.7294,77.8607748 C161.969348,77.7334434 162.256834,77.7334434 162.496783,77.8607748 L214.729979,108.044502 C231.032329,117.451747 240.437294,135.426109 238.871504,154.182739 C237.305714,172.939368 225.050719,189.105572 207.414262,195.67963 L207.414262,134.288998 C207.322521,131.276867 205.650697,128.535853 203.0146,127.075598 Z M224.757116,94.3850867 L223.22235,93.4642272 L171.60306,63.3828173 C168.981293,61.8443751 165.732456,61.8443751 163.110689,63.3828173 L99.9806554,99.8079259 L99.9806554,74.5866077 C99.9533004,74.3254088 100.071095,74.0701869 100.287609,73.9215426 L152.520805,43.7889738 C168.863098,34.3743518 189.174256,35.2529043 204.642579,46.0434841 C220.110903,56.8340638 227.949269,75.5923959 224.757116,94.1804513 L224.757116,94.3850867 Z M88.0606409,139.097931 L66.2158076,126.512851 C65.9950399,126.379091 65.8450965,126.154176 65.8065367,125.898945 L65.8065367,65.684966 C65.8314495,46.8285367 76.7500605,29.6846032 93.8270852,21.6883055 C110.90411,13.6920079 131.063833,16.2835462 145.5632,28.338998 L144.028434,29.2086986 L92.3579852,59.0343142 C89.7419327,60.5687513 88.1282597,63.3683767 88.1117998,66.4011901 L88.0606409,139.097931 Z M99.9294965,113.5185 L128.06687,97.3011417 L156.255402,113.5185 L156.255402,145.953218 L128.169187,162.170577 L99.9806554,145.953218 L99.9294965,113.5185 Z" fill="#000000"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
44
packages/backend/src/apps/self-hosted-llm/auth/index.ts
Normal file
44
packages/backend/src/apps/self-hosted-llm/auth/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import verifyCredentials from './verify-credentials';
|
||||
import isStillVerified from './is-still-verified';
|
||||
|
||||
export default {
|
||||
fields: [
|
||||
{
|
||||
key: 'screenName',
|
||||
label: 'Screen Name',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
description:
|
||||
'Screen name of your connection to be used on Automatisch UI.',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'apiUrl',
|
||||
label: 'API URL',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
docUrl: 'https://automatisch.io/docs/self-hosted-llm#api-url',
|
||||
clickToCopy: false,
|
||||
},
|
||||
{
|
||||
key: 'apiKey',
|
||||
label: 'API Key',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
readOnly: false,
|
||||
value: null,
|
||||
placeholder: null,
|
||||
docUrl: 'https://automatisch.io/docs/self-hosted-llm#api-key',
|
||||
clickToCopy: false,
|
||||
},
|
||||
],
|
||||
|
||||
verifyCredentials,
|
||||
isStillVerified,
|
||||
};
|
@@ -0,0 +1,8 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
const r = await $.http.get('/v1/models');
|
||||
return true;
|
||||
};
|
||||
|
||||
export default isStillVerified;
|
@@ -0,0 +1,7 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
await $.http.get('/v1/models');
|
||||
};
|
||||
|
||||
export default verifyCredentials;
|
@@ -0,0 +1,11 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data?.apiKey) {
|
||||
requestConfig.headers.Authorization = `Bearer ${$.auth.data.apiKey}`;
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default addAuthHeader;
|
@@ -0,0 +1,11 @@
|
||||
import { TBeforeRequest } from '@automatisch/types';
|
||||
|
||||
const setBaseUrl: TBeforeRequest = ($, requestConfig) => {
|
||||
if ($.auth.data.apiUrl) {
|
||||
requestConfig.baseURL = $.auth.data.apiUrl as string;
|
||||
}
|
||||
|
||||
return requestConfig;
|
||||
};
|
||||
|
||||
export default setBaseUrl;
|
@@ -0,0 +1,3 @@
|
||||
import listModels from './list-models';
|
||||
|
||||
export default [listModels];
|
@@ -0,0 +1,19 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
export default {
|
||||
name: 'List models',
|
||||
key: 'listModels',
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
const response = await $.http.get('/v1/models');
|
||||
|
||||
const models = response.data.data.map((model: { id: string }) => {
|
||||
return {
|
||||
value: model.id,
|
||||
name: model.id,
|
||||
};
|
||||
});
|
||||
|
||||
return { data: models };
|
||||
},
|
||||
};
|
0
packages/backend/src/apps/self-hosted-llm/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/self-hosted-llm/index.d.ts
vendored
Normal file
21
packages/backend/src/apps/self-hosted-llm/index.ts
Normal file
21
packages/backend/src/apps/self-hosted-llm/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import addAuthHeader from './common/add-auth-header';
|
||||
import setBaseUrl from './common/set-base-url';
|
||||
import auth from './auth';
|
||||
import actions from './actions';
|
||||
import dynamicData from './dynamic-data';
|
||||
|
||||
export default defineApp({
|
||||
name: 'Self-hosted LLM',
|
||||
key: 'self-hosted-llm',
|
||||
baseUrl: '',
|
||||
apiBaseUrl: '',
|
||||
iconUrl: '{BASE_URL}/apps/self-hosted-llm/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/self-hosted-llm/connection',
|
||||
primaryColor: '000000',
|
||||
supportsConnections: true,
|
||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||
auth,
|
||||
actions,
|
||||
dynamicData,
|
||||
});
|
@@ -1,3 +1,4 @@
|
||||
import qs from 'qs';
|
||||
import defineAction from '../../../../helpers/define-action';
|
||||
|
||||
export default defineAction({
|
||||
@@ -10,8 +11,7 @@ export default defineAction({
|
||||
key: 'chatId',
|
||||
type: 'string' as const,
|
||||
required: true,
|
||||
description:
|
||||
'Unique identifier for the target chat or username of the target channel (in the format @channelusername).',
|
||||
description: 'Unique identifier for the target chat or username of the target channel (in the format @channelusername).',
|
||||
variables: true,
|
||||
},
|
||||
{
|
||||
@@ -28,8 +28,7 @@ export default defineAction({
|
||||
type: 'dropdown' as const,
|
||||
required: false,
|
||||
value: false,
|
||||
description:
|
||||
'Sends the message silently. Users will receive a notification with no sound.',
|
||||
description: 'Sends the message silently. Users will receive a notification with no sound.',
|
||||
variables: true,
|
||||
options: [
|
||||
{
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { URL } from 'node:url';
|
||||
import * as dotenv from 'dotenv';
|
||||
import path from 'path';
|
||||
import process from 'node:process';
|
||||
|
||||
if (process.env.APP_ENV === 'test') {
|
||||
dotenv.config({ path: path.resolve(__dirname, '../../.env.test') });
|
||||
@@ -9,6 +8,57 @@ if (process.env.APP_ENV === 'test') {
|
||||
dotenv.config();
|
||||
}
|
||||
|
||||
type AppConfig = {
|
||||
host: string;
|
||||
protocol: string;
|
||||
port: string;
|
||||
webAppUrl: string;
|
||||
webhookUrl: string;
|
||||
appEnv: string;
|
||||
logLevel: string;
|
||||
isDev: boolean;
|
||||
isTest: boolean;
|
||||
isProd: boolean;
|
||||
postgresDatabase: string;
|
||||
postgresSchema: string;
|
||||
postgresPort: number;
|
||||
postgresHost: string;
|
||||
postgresUsername: string;
|
||||
postgresPassword?: string;
|
||||
version: string;
|
||||
postgresEnableSsl: boolean;
|
||||
baseUrl: string;
|
||||
encryptionKey: string;
|
||||
webhookSecretKey: string;
|
||||
appSecretKey: string;
|
||||
serveWebAppSeparately: boolean;
|
||||
redisHost: string;
|
||||
redisPort: number;
|
||||
redisUsername: string;
|
||||
redisPassword: string;
|
||||
redisTls: boolean;
|
||||
enableBullMQDashboard: boolean;
|
||||
bullMQDashboardUsername: string;
|
||||
bullMQDashboardPassword: string;
|
||||
telemetryEnabled: boolean;
|
||||
requestBodySizeLimit: string;
|
||||
smtpHost: string;
|
||||
smtpPort: number;
|
||||
smtpSecure: boolean;
|
||||
smtpUser: string;
|
||||
smtpPassword: string;
|
||||
fromEmail: string;
|
||||
isCloud: boolean;
|
||||
isMation: boolean;
|
||||
isSelfHosted: boolean;
|
||||
paddleVendorId: number;
|
||||
paddleVendorAuthCode: string;
|
||||
paddlePublicKey: string;
|
||||
licenseKey: string;
|
||||
sentryDsn: string;
|
||||
CI: boolean;
|
||||
};
|
||||
|
||||
const host = process.env.HOST || 'localhost';
|
||||
const protocol = process.env.PROTOCOL || 'http';
|
||||
const port = process.env.PORT || '3000';
|
||||
@@ -35,7 +85,7 @@ webhookUrl = webhookUrl.substring(0, webhookUrl.length - 1);
|
||||
|
||||
const appEnv = process.env.APP_ENV || 'development';
|
||||
|
||||
const appConfig = {
|
||||
const appConfig: AppConfig = {
|
||||
host,
|
||||
protocol,
|
||||
port,
|
@@ -4,10 +4,11 @@ import process from 'process';
|
||||
import pg from 'pg';
|
||||
pg.types.setTypeParser(20, 'text', parseInt);
|
||||
import knex from 'knex';
|
||||
import type { Knex } from 'knex';
|
||||
import knexConfig from '../../knexfile';
|
||||
import logger from '../helpers/logger';
|
||||
|
||||
export const client = knex(knexConfig);
|
||||
export const client: Knex = knex(knexConfig);
|
||||
|
||||
const CONNECTION_REFUSED = 'ECONNREFUSED';
|
||||
|
@@ -1,6 +1,16 @@
|
||||
import appConfig from './app';
|
||||
|
||||
const redisConfig = {
|
||||
type TRedisConfig = {
|
||||
host: string,
|
||||
port: number,
|
||||
username?: string,
|
||||
password?: string,
|
||||
tls?: Record<string, unknown>,
|
||||
enableReadyCheck?: boolean,
|
||||
enableOfflineQueue: boolean,
|
||||
}
|
||||
|
||||
const redisConfig: TRedisConfig = {
|
||||
host: appConfig.redisHost,
|
||||
port: appConfig.redisPort,
|
||||
username: appConfig.redisUsername,
|
@@ -1,9 +1,11 @@
|
||||
import { Response } from 'express';
|
||||
import { IJSONObject, IRequest } from '@automatisch/types';
|
||||
import crypto from 'crypto';
|
||||
import { serialize } from 'php-serialize';
|
||||
import Billing from '../../helpers/billing/index.ee';
|
||||
import appConfig from '../../config/app';
|
||||
|
||||
export default async (request, response) => {
|
||||
export default async (request: IRequest, response: Response) => {
|
||||
if (!verifyWebhook(request)) {
|
||||
return response.sendStatus(401);
|
||||
}
|
||||
@@ -21,14 +23,14 @@ export default async (request, response) => {
|
||||
return response.sendStatus(200);
|
||||
};
|
||||
|
||||
const verifyWebhook = (request) => {
|
||||
const verifyWebhook = (request: IRequest) => {
|
||||
const signature = request.body.p_signature;
|
||||
|
||||
const keys = Object.keys(request.body)
|
||||
.filter((key) => key !== 'p_signature')
|
||||
.sort();
|
||||
|
||||
const sorted = {};
|
||||
const sorted: IJSONObject = {};
|
||||
keys.forEach((key) => {
|
||||
sorted[key] = request.body[key];
|
||||
});
|
@@ -1,10 +1,12 @@
|
||||
import path from 'node:path';
|
||||
import { Response } from 'express';
|
||||
import { IRequest } from '@automatisch/types';
|
||||
|
||||
import Connection from '../../models/connection';
|
||||
import logger from '../../helpers/logger';
|
||||
import handler from '../../helpers/webhook-handler';
|
||||
|
||||
export default async (request, response) => {
|
||||
export default async (request: IRequest, response: Response) => {
|
||||
const computedRequestPayload = {
|
||||
headers: request.headers,
|
||||
body: request.body,
|
||||
@@ -20,7 +22,7 @@ export default async (request, response) => {
|
||||
.findById(connectionId)
|
||||
.throwIfNotFound();
|
||||
|
||||
if (!(await connection.verifyWebhook(request))) {
|
||||
if (!await connection.verifyWebhook(request)) {
|
||||
return response.sendStatus(401);
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
import { Response } from 'express';
|
||||
import { IRequest } from '@automatisch/types';
|
||||
|
||||
import Flow from '../../models/flow';
|
||||
import logger from '../../helpers/logger';
|
||||
import handler from '../../helpers/webhook-handler';
|
||||
|
||||
export default async (request, response) => {
|
||||
export default async (request: IRequest, response: Response) => {
|
||||
const computedRequestPayload = {
|
||||
headers: request.headers,
|
||||
body: request.body,
|
@@ -1,22 +1,22 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
|
||||
export default class BaseError extends Error {
|
||||
details = {};
|
||||
statusCode?: number;
|
||||
|
||||
constructor(error) {
|
||||
let computedError;
|
||||
|
||||
constructor(error?: string | IJSONObject) {
|
||||
let computedError: Record<string, unknown>;
|
||||
try {
|
||||
computedError = JSON.parse(error);
|
||||
computedError = JSON.parse(error as string);
|
||||
} catch {
|
||||
computedError =
|
||||
typeof error === 'string' || Array.isArray(error) ? { error } : error;
|
||||
computedError = (typeof error === 'string' || Array.isArray(error)) ? { error } : error;
|
||||
}
|
||||
|
||||
let computedMessage;
|
||||
|
||||
let computedMessage: string;
|
||||
try {
|
||||
// challenge to input to see if it is stringified JSON
|
||||
JSON.parse(error);
|
||||
computedMessage = error;
|
||||
JSON.parse(error as string);
|
||||
computedMessage = error as string;
|
||||
} catch {
|
||||
if (typeof error === 'string') {
|
||||
computedMessage = error;
|
@@ -1,10 +0,0 @@
|
||||
import BaseError from './base';
|
||||
|
||||
export default class GenerateAuthUrlError extends BaseError {
|
||||
constructor(error) {
|
||||
const computedError = error.response?.data || error.message;
|
||||
super(computedError);
|
||||
|
||||
this.message = `Error occured while creating authorization URL!`;
|
||||
}
|
||||
}
|
14
packages/backend/src/errors/generate-auth-url.ts
Normal file
14
packages/backend/src/errors/generate-auth-url.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import BaseError from './base';
|
||||
|
||||
export default class GenerateAuthUrlError 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!`;
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
import BaseError from './base';
|
||||
|
||||
export default class HttpError extends BaseError {
|
||||
constructor(error) {
|
||||
const computedError = error.response?.data || error.message;
|
||||
super(computedError);
|
||||
|
||||
this.response = error.response;
|
||||
}
|
||||
}
|
17
packages/backend/src/errors/http.ts
Normal file
17
packages/backend/src/errors/http.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { AxiosResponse, AxiosError } from 'axios';
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import BaseError from './base';
|
||||
|
||||
export default class HttpError extends BaseError {
|
||||
response: AxiosResponse;
|
||||
|
||||
constructor(error: AxiosError) {
|
||||
const computedError =
|
||||
error.response?.data as IJSONObject ||
|
||||
error.message as string;
|
||||
|
||||
super(computedError);
|
||||
|
||||
this.response = error.response;
|
||||
}
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
|
||||
const createAppAuthClient = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const appConfig = await AppConfig.query()
|
||||
.findById(params.input.appConfigId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const appAuthClient = await appConfig
|
||||
.$relatedQuery('appAuthClients')
|
||||
.insert(params.input);
|
||||
|
||||
return appAuthClient;
|
||||
};
|
||||
|
||||
export default createAppAuthClient;
|
@@ -0,0 +1,35 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
appConfigId: string;
|
||||
name: string;
|
||||
formattedAuthDefaults?: IJSONObject;
|
||||
active?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const createAppAuthClient = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const appConfig = await AppConfig
|
||||
.query()
|
||||
.findById(params.input.appConfigId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const appAuthClient = await appConfig
|
||||
.$relatedQuery('appAuthClients')
|
||||
.insert(
|
||||
params.input
|
||||
);
|
||||
|
||||
return appAuthClient;
|
||||
};
|
||||
|
||||
export default createAppAuthClient;
|
@@ -1,18 +0,0 @@
|
||||
import App from '../../models/app';
|
||||
import AppConfig from '../../models/app-config';
|
||||
|
||||
const createAppConfig = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const key = params.input.key;
|
||||
|
||||
const app = await App.findOneByKey(key);
|
||||
|
||||
if (!app) throw new Error('The app cannot be found!');
|
||||
|
||||
const appConfig = await AppConfig.query().insert(params.input);
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default createAppConfig;
|
@@ -0,0 +1,36 @@
|
||||
import App from '../../models/app';
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
key: string;
|
||||
allowCustomConnection?: boolean;
|
||||
shared?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const createAppConfig = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const key = params.input.key;
|
||||
|
||||
const app = await App.findOneByKey(key);
|
||||
|
||||
if (!app) throw new Error('The app cannot be found!');
|
||||
|
||||
const appConfig = await AppConfig
|
||||
.query()
|
||||
.insert(
|
||||
params.input
|
||||
);
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default createAppConfig;
|
@@ -1,7 +1,21 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import App from '../../models/app';
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const createConnection = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
key: string;
|
||||
appAuthClientId: string;
|
||||
formattedData: IJSONObject;
|
||||
};
|
||||
};
|
||||
|
||||
const createConnection = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const { key, appAuthClientId } = params.input;
|
||||
@@ -12,20 +26,16 @@ const createConnection = async (_parent, params, context) => {
|
||||
|
||||
let formattedData = params.input.formattedData;
|
||||
if (appConfig) {
|
||||
if (appConfig.disabled)
|
||||
throw new Error(
|
||||
'This application has been disabled for new connections!'
|
||||
);
|
||||
if (appConfig.disabled) throw new Error('This application has been disabled for new connections!');
|
||||
|
||||
if (!appConfig.allowCustomConnection && formattedData)
|
||||
throw new Error(`Custom connections cannot be created for ${app.name}!`);
|
||||
if (!appConfig.allowCustomConnection && formattedData) throw new Error(`Custom connections cannot be created for ${app.name}!`);
|
||||
|
||||
if (appConfig.shared && !formattedData) {
|
||||
const authClient = await appConfig
|
||||
.$relatedQuery('appAuthClients')
|
||||
.findById(appAuthClientId)
|
||||
.where({
|
||||
active: true,
|
||||
active: true
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -33,7 +43,8 @@ const createConnection = async (_parent, params, context) => {
|
||||
}
|
||||
}
|
||||
|
||||
const createdConnection = await context.currentUser
|
||||
const createdConnection = await context
|
||||
.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.insert({
|
||||
key,
|
@@ -1,7 +1,19 @@
|
||||
import App from '../../models/app';
|
||||
import Step from '../../models/step';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const createFlow = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
triggerAppKey: string;
|
||||
connectionId: string;
|
||||
};
|
||||
};
|
||||
|
||||
const createFlow = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Flow');
|
||||
|
||||
const connectionId = params?.input?.connectionId;
|
@@ -1,29 +0,0 @@
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
import Role from '../../models/role';
|
||||
|
||||
const createRole = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Role');
|
||||
|
||||
const { name, description, permissions } = params.input;
|
||||
const key = kebabCase(name);
|
||||
|
||||
const existingRole = await Role.query().findOne({ key });
|
||||
|
||||
if (existingRole) {
|
||||
throw new Error('Role already exists!');
|
||||
}
|
||||
|
||||
return await Role.query()
|
||||
.insertGraph(
|
||||
{
|
||||
key,
|
||||
name,
|
||||
description,
|
||||
permissions,
|
||||
},
|
||||
{ relate: ['permissions'] }
|
||||
)
|
||||
.returning('*');
|
||||
};
|
||||
|
||||
export default createRole;
|
34
packages/backend/src/graphql/mutations/create-role.ee.ts
Normal file
34
packages/backend/src/graphql/mutations/create-role.ee.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
import Permission from '../../models/permission';
|
||||
import Role from '../../models/role';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
name: string;
|
||||
description: string;
|
||||
permissions: Permission[];
|
||||
};
|
||||
};
|
||||
|
||||
const createRole = async (_parent: unknown, params: Params, context: Context) => {
|
||||
context.currentUser.can('create', 'Role');
|
||||
|
||||
const { name, description, permissions } = params.input;
|
||||
const key = kebabCase(name);
|
||||
|
||||
const existingRole = await Role.query().findOne({ key });
|
||||
|
||||
if (existingRole) {
|
||||
throw new Error('Role already exists!');
|
||||
}
|
||||
|
||||
return await Role.query().insertGraph({
|
||||
key,
|
||||
name,
|
||||
description,
|
||||
permissions,
|
||||
}, { relate: ['permissions'] }).returning('*');
|
||||
};
|
||||
|
||||
export default createRole;
|
@@ -1,7 +1,28 @@
|
||||
import App from '../../models/app';
|
||||
import Flow from '../../models/flow';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const createStep = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
key: string;
|
||||
appKey: string;
|
||||
flow: {
|
||||
id: string;
|
||||
};
|
||||
connection: {
|
||||
id: string;
|
||||
};
|
||||
previousStep: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const createStep = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const conditions = context.currentUser.can('update', 'Flow');
|
||||
const userFlows = context.currentUser.$relatedQuery('flows');
|
||||
const allFlows = Flow.query();
|
@@ -1,7 +1,23 @@
|
||||
import User from '../../models/user';
|
||||
import Role from '../../models/role';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const createUser = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
fullName: string;
|
||||
email: string;
|
||||
password: string;
|
||||
role: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const createUser = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'User');
|
||||
|
||||
const { fullName, email, password } = params.input;
|
||||
@@ -14,7 +30,7 @@ const createUser = async (_parent, params, context) => {
|
||||
throw new Error('User already exists!');
|
||||
}
|
||||
|
||||
const userPayload = {
|
||||
const userPayload: Partial<User> = {
|
||||
fullName,
|
||||
email,
|
||||
password,
|
@@ -1,9 +1,21 @@
|
||||
import Context from '../../types/express/context';
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
|
||||
const deleteAppAuthClient = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteAppAuthClient = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('delete', 'App');
|
||||
|
||||
await AppAuthClient.query()
|
||||
await AppAuthClient
|
||||
.query()
|
||||
.delete()
|
||||
.findOne({
|
||||
id: params.input.id,
|
@@ -1,4 +1,16 @@
|
||||
const deleteConnection = async (_parent, params, context) => {
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteConnection = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('delete', 'Connection');
|
||||
|
||||
await context.currentUser
|
@@ -1,11 +1,17 @@
|
||||
import { Duration } from 'luxon';
|
||||
import Context from '../../types/express/context';
|
||||
import deleteUserQueue from '../../queues/delete-user.ee';
|
||||
import flowQueue from '../../queues/flow';
|
||||
import Flow from '../../models/flow';
|
||||
import Execution from '../../models/execution';
|
||||
import ExecutionStep from '../../models/execution-step';
|
||||
import appConfig from '../../config/app';
|
||||
|
||||
const deleteCurrentUser = async (_parent, params, context) => {
|
||||
const deleteCurrentUser = async (
|
||||
_parent: unknown,
|
||||
params: never,
|
||||
context: Context
|
||||
) => {
|
||||
const id = context.currentUser.id;
|
||||
|
||||
const flows = await context.currentUser.$relatedQuery('flows').where({
|
||||
@@ -26,7 +32,7 @@ const deleteCurrentUser = async (_parent, params, context) => {
|
||||
await context.currentUser
|
||||
.$relatedQuery('executions')
|
||||
.select('executions.id')
|
||||
).map((execution) => execution.id);
|
||||
).map((execution: Execution) => execution.id);
|
||||
const flowIds = flows.map((flow) => flow.id);
|
||||
|
||||
await ExecutionStep.query().delete().whereIn('execution_id', executionIds);
|
@@ -1,9 +1,21 @@
|
||||
import Context from '../../types/express/context';
|
||||
import Flow from '../../models/flow';
|
||||
import Execution from '../../models/execution';
|
||||
import ExecutionStep from '../../models/execution-step';
|
||||
import globalVariable from '../../helpers/global-variable';
|
||||
import logger from '../../helpers/logger';
|
||||
|
||||
const deleteFlow = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteFlow = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const conditions = context.currentUser.can('delete', 'Flow');
|
||||
const isCreator = conditions.isCreator;
|
||||
const allFlows = Flow.query();
|
||||
@@ -31,15 +43,13 @@ const deleteFlow = async (_parent, params, context) => {
|
||||
await trigger.unregisterHook($);
|
||||
} catch (error) {
|
||||
// suppress error as the remote resource might have been already deleted
|
||||
logger.debug(
|
||||
`Failed to unregister webhook for flow ${flow.id}: ${error.message}`
|
||||
);
|
||||
logger.debug(`Failed to unregister webhook for flow ${flow.id}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const executionIds = (
|
||||
await flow.$relatedQuery('executions').select('executions.id')
|
||||
).map((execution) => execution.id);
|
||||
).map((execution: Execution) => execution.id);
|
||||
|
||||
await ExecutionStep.query().delete().whereIn('execution_id', executionIds);
|
||||
|
@@ -1,7 +1,18 @@
|
||||
import Role from '../../models/role';
|
||||
import SamlAuthProvider from '../../models/saml-auth-provider.ee';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const deleteRole = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteRole = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('delete', 'Role');
|
||||
|
||||
const role = await Role.query().findById(params.input.id).throwIfNotFound();
|
@@ -1,4 +1,16 @@
|
||||
const deleteStep = async (_parent, params, context) => {
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteStep = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'Flow');
|
||||
|
||||
const step = await context.currentUser
|
@@ -1,8 +1,19 @@
|
||||
import { Duration } from 'luxon';
|
||||
import Context from '../../types/express/context';
|
||||
import User from '../../models/user';
|
||||
import deleteUserQueue from '../../queues/delete-user.ee';
|
||||
|
||||
const deleteUser = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const deleteUser = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('delete', 'User');
|
||||
|
||||
const id = params.input.id;
|
||||
@@ -13,7 +24,7 @@ const deleteUser = async (_parent, params, context) => {
|
||||
const jobPayload = { id };
|
||||
const millisecondsFor30Days = Duration.fromObject({ days: 30 }).toMillis();
|
||||
const jobOptions = {
|
||||
delay: millisecondsFor30Days,
|
||||
delay: millisecondsFor30Days
|
||||
};
|
||||
|
||||
await deleteUserQueue.add(jobName, jobPayload, jobOptions);
|
@@ -1,4 +1,15 @@
|
||||
function updateStepId(value, newStepIds) {
|
||||
import Context from '../../types/express/context';
|
||||
import Step from '../../models/step';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
type NewStepIds = Record<string, string>;
|
||||
|
||||
function updateStepId(value: string, newStepIds: NewStepIds) {
|
||||
let newValue = value;
|
||||
|
||||
const stepIdEntries = Object.entries(newStepIds);
|
||||
@@ -13,9 +24,9 @@ function updateStepId(value, newStepIds) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
function updateStepVariables(parameters, newStepIds) {
|
||||
function updateStepVariables(parameters: Step['parameters'], newStepIds: NewStepIds): Step['parameters'] {
|
||||
const entries = Object.entries(parameters);
|
||||
return entries.reduce((result, [key, value]) => {
|
||||
return entries.reduce((result, [key, value]: [string, unknown]) => {
|
||||
if (typeof value === 'string') {
|
||||
return {
|
||||
...result,
|
||||
@@ -26,7 +37,7 @@ function updateStepVariables(parameters, newStepIds) {
|
||||
if (Array.isArray(value)) {
|
||||
return {
|
||||
...result,
|
||||
[key]: value.map((item) => updateStepVariables(item, newStepIds)),
|
||||
[key]: value.map(item => updateStepVariables(item, newStepIds)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,7 +48,11 @@ function updateStepVariables(parameters, newStepIds) {
|
||||
}, {});
|
||||
}
|
||||
|
||||
const duplicateFlow = async (_parent, params, context) => {
|
||||
const duplicateFlow = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Flow');
|
||||
|
||||
const flow = await context.currentUser
|
||||
@@ -54,16 +69,17 @@ const duplicateFlow = async (_parent, params, context) => {
|
||||
active: false,
|
||||
});
|
||||
|
||||
const newStepIds = {};
|
||||
const newStepIds: NewStepIds = {};
|
||||
for (const step of flow.steps) {
|
||||
const duplicatedStep = await duplicatedFlow.$relatedQuery('steps').insert({
|
||||
key: step.key,
|
||||
appKey: step.appKey,
|
||||
type: step.type,
|
||||
connectionId: step.connectionId,
|
||||
position: step.position,
|
||||
parameters: updateStepVariables(step.parameters, newStepIds),
|
||||
});
|
||||
const duplicatedStep = await duplicatedFlow.$relatedQuery('steps')
|
||||
.insert({
|
||||
key: step.key,
|
||||
appKey: step.appKey,
|
||||
type: step.type,
|
||||
connectionId: step.connectionId,
|
||||
position: step.position,
|
||||
parameters: updateStepVariables(step.parameters, newStepIds),
|
||||
});
|
||||
|
||||
if (duplicatedStep.isTrigger) {
|
||||
await duplicatedStep.updateWebhookUrl();
|
@@ -1,7 +1,18 @@
|
||||
import Context from '../../types/express/context';
|
||||
import testRun from '../../services/test-run';
|
||||
import Step from '../../models/step';
|
||||
|
||||
const executeFlow = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
stepId: string;
|
||||
};
|
||||
};
|
||||
|
||||
const executeFlow = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const conditions = context.currentUser.can('update', 'Flow');
|
||||
const isCreator = conditions.isCreator;
|
||||
const allSteps = Step.query();
|
||||
@@ -10,7 +21,10 @@ const executeFlow = async (_parent, params, context) => {
|
||||
|
||||
const { stepId } = params.input;
|
||||
|
||||
const untilStep = await baseQuery.clone().findById(stepId).throwIfNotFound();
|
||||
const untilStep = await baseQuery
|
||||
.clone()
|
||||
.findById(stepId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const { executionStep } = await testRun({ stepId });
|
||||
|
@@ -6,7 +6,13 @@ import {
|
||||
REMOVE_AFTER_7_DAYS_OR_50_JOBS,
|
||||
} from '../../helpers/remove-job-configuration';
|
||||
|
||||
const forgotPassword = async (_parent, params) => {
|
||||
type Params = {
|
||||
input: {
|
||||
email: string;
|
||||
};
|
||||
};
|
||||
|
||||
const forgotPassword = async (_parent: unknown, params: Params) => {
|
||||
const { email } = params.input;
|
||||
|
||||
const user = await User.query().findOne({ email: email.toLowerCase() });
|
@@ -1,7 +1,18 @@
|
||||
import Context from '../../types/express/context';
|
||||
import globalVariable from '../../helpers/global-variable';
|
||||
import App from '../../models/app';
|
||||
|
||||
const generateAuthUrl = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const generateAuthUrl = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const connection = await context.currentUser
|
@@ -1,7 +1,14 @@
|
||||
import User from '../../models/user';
|
||||
import createAuthTokenByUserId from '../../helpers/create-auth-token-by-user-id';
|
||||
|
||||
const login = async (_parent, params) => {
|
||||
type Params = {
|
||||
input: {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
||||
|
||||
const login = async (_parent: unknown, params: Params) => {
|
||||
const user = await User.query().findOne({
|
||||
email: params.input.email.toLowerCase(),
|
||||
});
|
@@ -1,7 +1,15 @@
|
||||
import User from '../../models/user';
|
||||
import Role from '../../models/role';
|
||||
|
||||
const registerUser = async (_parent, params) => {
|
||||
type Params = {
|
||||
input: {
|
||||
fullName: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
||||
|
||||
const registerUser = async (_parent: unknown, params: Params) => {
|
||||
const { fullName, email, password } = params.input;
|
||||
|
||||
const existingUser = await User.query().findOne({
|
@@ -1,4 +1,16 @@
|
||||
const resetConnection = async (_parent, params, context) => {
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const resetConnection = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
@@ -1,6 +1,13 @@
|
||||
import User from '../../models/user';
|
||||
|
||||
const resetPassword = async (_parent, params) => {
|
||||
type Params = {
|
||||
input: {
|
||||
token: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
||||
|
||||
const resetPassword = async (_parent: unknown, params: Params) => {
|
||||
const { token, password } = params.input;
|
||||
|
||||
if (!token) {
|
@@ -1,17 +0,0 @@
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
|
||||
const updateAppAuthClient = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const { id, ...appAuthClientData } = params.input;
|
||||
|
||||
const appAuthClient = await AppAuthClient.query()
|
||||
.findById(id)
|
||||
.throwIfNotFound();
|
||||
|
||||
await appAuthClient.$query().patch(appAuthClientData);
|
||||
|
||||
return appAuthClient;
|
||||
};
|
||||
|
||||
export default updateAppAuthClient;
|
@@ -0,0 +1,38 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
name: string;
|
||||
formattedAuthDefaults?: IJSONObject;
|
||||
active?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const updateAppAuthClient = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const {
|
||||
id,
|
||||
...appAuthClientData
|
||||
} = params.input;
|
||||
|
||||
const appAuthClient = await AppAuthClient
|
||||
.query()
|
||||
.findById(id)
|
||||
.throwIfNotFound();
|
||||
|
||||
await appAuthClient
|
||||
.$query()
|
||||
.patch(appAuthClientData);
|
||||
|
||||
return appAuthClient;
|
||||
};
|
||||
|
||||
export default updateAppAuthClient;
|
@@ -1,15 +0,0 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
|
||||
const updateAppConfig = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const { id, ...appConfigToUpdate } = params.input;
|
||||
|
||||
const appConfig = await AppConfig.query().findById(id).throwIfNotFound();
|
||||
|
||||
await appConfig.$query().patch(appConfigToUpdate);
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default updateAppConfig;
|
@@ -0,0 +1,39 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
allowCustomConnection?: boolean;
|
||||
shared?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const updateAppConfig = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'App');
|
||||
|
||||
const {
|
||||
id,
|
||||
...appConfigToUpdate
|
||||
} = params.input;
|
||||
|
||||
const appConfig = await AppConfig
|
||||
.query()
|
||||
.findById(id)
|
||||
.throwIfNotFound();
|
||||
|
||||
await appConfig
|
||||
.$query()
|
||||
.patch(
|
||||
appConfigToUpdate
|
||||
);
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default updateAppConfig;
|
@@ -1,6 +1,18 @@
|
||||
import type { IJSONValue } from '@automatisch/types';
|
||||
import Config from '../../models/config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const updateConfig = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
[index: string]: IJSONValue;
|
||||
};
|
||||
};
|
||||
|
||||
const updateConfig = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'Config');
|
||||
|
||||
const config = params.input;
|
@@ -1,6 +1,20 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import Context from '../../types/express/context';
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
|
||||
const updateConnection = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
formattedData?: IJSONObject;
|
||||
appAuthClientId?: string;
|
||||
};
|
||||
};
|
||||
|
||||
const updateConnection = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
||||
@@ -13,7 +27,8 @@ const updateConnection = async (_parent, params, context) => {
|
||||
let formattedData = params.input.formattedData;
|
||||
|
||||
if (params.input.appAuthClientId) {
|
||||
const appAuthClient = await AppAuthClient.query()
|
||||
const appAuthClient = await AppAuthClient
|
||||
.query()
|
||||
.findById(params.input.appAuthClientId)
|
||||
.throwIfNotFound();
|
||||
|
@@ -1,11 +0,0 @@
|
||||
const updateCurrentUser = async (_parent, params, context) => {
|
||||
const user = await context.currentUser.$query().patchAndFetch({
|
||||
email: params.input.email,
|
||||
password: params.input.password,
|
||||
fullName: params.input.fullName,
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export default updateCurrentUser;
|
@@ -0,0 +1,25 @@
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
email: string;
|
||||
password: string;
|
||||
fullName: string;
|
||||
};
|
||||
};
|
||||
|
||||
const updateCurrentUser = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const user = await context.currentUser.$query().patchAndFetch({
|
||||
email: params.input.email,
|
||||
password: params.input.password,
|
||||
fullName: params.input.fullName,
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export default updateCurrentUser;
|
@@ -1,15 +1,24 @@
|
||||
import Flow from '../../models/flow';
|
||||
import Context from '../../types/express/context';
|
||||
import flowQueue from '../../queues/flow';
|
||||
import {
|
||||
REMOVE_AFTER_30_DAYS_OR_150_JOBS,
|
||||
REMOVE_AFTER_7_DAYS_OR_50_JOBS,
|
||||
} from '../../helpers/remove-job-configuration';
|
||||
import { REMOVE_AFTER_30_DAYS_OR_150_JOBS, REMOVE_AFTER_7_DAYS_OR_50_JOBS } from '../../helpers/remove-job-configuration';
|
||||
import globalVariable from '../../helpers/global-variable';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const JOB_NAME = 'flow';
|
||||
const EVERY_15_MINUTES_CRON = '*/15 * * * *';
|
||||
|
||||
const updateFlowStatus = async (_parent, params, context) => {
|
||||
const updateFlowStatus = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const conditions = context.currentUser.can('publish', 'Flow');
|
||||
const isCreator = conditions.isCreator;
|
||||
const allFlows = Flow.query();
|
||||
@@ -65,7 +74,7 @@ const updateFlowStatus = async (_parent, params, context) => {
|
||||
repeat: repeatOptions,
|
||||
jobId: flow.id,
|
||||
removeOnComplete: REMOVE_AFTER_7_DAYS_OR_50_JOBS,
|
||||
removeOnFail: REMOVE_AFTER_30_DAYS_OR_150_JOBS,
|
||||
removeOnFail: REMOVE_AFTER_30_DAYS_OR_150_JOBS
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@@ -76,9 +85,12 @@ const updateFlowStatus = async (_parent, params, context) => {
|
||||
}
|
||||
}
|
||||
|
||||
flow = await flow.$query().withGraphFetched('steps').patchAndFetch({
|
||||
active: newActiveValue,
|
||||
});
|
||||
flow = await flow
|
||||
.$query()
|
||||
.withGraphFetched('steps')
|
||||
.patchAndFetch({
|
||||
active: newActiveValue,
|
||||
});
|
||||
|
||||
return flow;
|
||||
};
|
@@ -1,4 +1,17 @@
|
||||
const updateFlow = async (_parent, params, context) => {
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
|
||||
const updateFlow = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'Flow');
|
||||
|
||||
let flow = await context.currentUser
|
@@ -1,13 +1,35 @@
|
||||
import Context from '../../types/express/context';
|
||||
import Role from '../../models/role';
|
||||
import Permission from '../../models/permission';
|
||||
import permissionCatalog from '../../helpers/permission-catalog.ee';
|
||||
|
||||
const updateRole = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
permissions: Permission[];
|
||||
};
|
||||
};
|
||||
|
||||
const updateRole = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'Role');
|
||||
|
||||
const { id, name, description, permissions } = params.input;
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
permissions,
|
||||
} = params.input;
|
||||
|
||||
const role = await Role.query().findById(id).throwIfNotFound();
|
||||
const role = await Role
|
||||
.query()
|
||||
.findById(id)
|
||||
.throwIfNotFound();
|
||||
|
||||
try {
|
||||
const updatedRole = await Role.transaction(async (trx) => {
|
||||
@@ -16,17 +38,19 @@ const updateRole = async (_parent, params, context) => {
|
||||
if (permissions?.length) {
|
||||
const sanitizedPermissions = permissions
|
||||
.filter((permission) => {
|
||||
const { action, subject, conditions } = permission;
|
||||
const {
|
||||
action,
|
||||
subject,
|
||||
conditions,
|
||||
} = permission;
|
||||
|
||||
const relevantAction = permissionCatalog.actions.find(
|
||||
(actionCatalogItem) => actionCatalogItem.key === action
|
||||
);
|
||||
const relevantAction = permissionCatalog.actions.find(actionCatalogItem => actionCatalogItem.key === action);
|
||||
const validSubject = relevantAction.subjects.includes(subject);
|
||||
const validConditions = conditions.every((condition) => {
|
||||
return !!permissionCatalog.conditions.find(
|
||||
(conditionCatalogItem) => conditionCatalogItem.key === condition
|
||||
);
|
||||
});
|
||||
const validConditions = conditions.every(condition => {
|
||||
return !!permissionCatalog
|
||||
.conditions
|
||||
.find((conditionCatalogItem) => conditionCatalogItem.key === condition);
|
||||
})
|
||||
|
||||
return validSubject && validConditions;
|
||||
})
|
||||
@@ -38,17 +62,22 @@ const updateRole = async (_parent, params, context) => {
|
||||
await Permission.query().insert(sanitizedPermissions);
|
||||
}
|
||||
|
||||
await role.$query(trx).patch({
|
||||
name,
|
||||
description,
|
||||
});
|
||||
await role
|
||||
.$query(trx)
|
||||
.patch(
|
||||
{
|
||||
name,
|
||||
description,
|
||||
}
|
||||
);
|
||||
|
||||
return await Role.query(trx)
|
||||
return await Role
|
||||
.query(trx)
|
||||
.leftJoinRelated({
|
||||
permissions: true,
|
||||
permissions: true
|
||||
})
|
||||
.withGraphFetched({
|
||||
permissions: true,
|
||||
permissions: true
|
||||
})
|
||||
.findById(id);
|
||||
});
|
@@ -1,8 +1,29 @@
|
||||
import { IJSONObject } from '@automatisch/types';
|
||||
import App from '../../models/app';
|
||||
import Step from '../../models/step';
|
||||
import Connection from '../../models/connection';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const updateStep = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
key: string;
|
||||
appKey: string;
|
||||
parameters: IJSONObject;
|
||||
flow: {
|
||||
id: string;
|
||||
};
|
||||
connection: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const updateStep = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
const { isCreator } = context.currentUser.can('update', 'Flow');
|
||||
const userSteps = context.currentUser.$relatedQuery('steps');
|
||||
const allSteps = Step.query();
|
||||
@@ -29,13 +50,11 @@ const updateStep = async (_parent, params, context) => {
|
||||
|
||||
const userConnections = context.currentUser.$relatedQuery('connections');
|
||||
const allConnections = Connection.query();
|
||||
const baseConnectionsQuery = canSeeAllConnections
|
||||
? allConnections
|
||||
: userConnections;
|
||||
const baseConnectionsQuery = canSeeAllConnections ? allConnections : userConnections;
|
||||
|
||||
const connection = await baseConnectionsQuery
|
||||
.clone()
|
||||
.findById(input.connection?.id);
|
||||
.findById(input.connection?.id)
|
||||
|
||||
if (!connection) {
|
||||
throw new Error('The connection does not exist!');
|
@@ -1,9 +1,25 @@
|
||||
import Context from '../../types/express/context';
|
||||
import User from '../../models/user';
|
||||
|
||||
const updateUser = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
email: string;
|
||||
fullName: string;
|
||||
role: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const updateUser = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'User');
|
||||
|
||||
const userPayload = {
|
||||
const userPayload: Partial<User> = {
|
||||
email: params.input.email,
|
||||
fullName: params.input.fullName,
|
||||
};
|
@@ -1,30 +0,0 @@
|
||||
import SamlAuthProvider from '../../models/saml-auth-provider.ee';
|
||||
|
||||
const upsertSamlAuthProvider = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'SamlAuthProvider');
|
||||
|
||||
const samlAuthProviderPayload = {
|
||||
...params.input,
|
||||
};
|
||||
|
||||
const existingSamlAuthProvider = await SamlAuthProvider.query()
|
||||
.limit(1)
|
||||
.first();
|
||||
|
||||
if (!existingSamlAuthProvider) {
|
||||
const samlAuthProvider = await SamlAuthProvider.query().insert(
|
||||
samlAuthProviderPayload
|
||||
);
|
||||
|
||||
return samlAuthProvider;
|
||||
}
|
||||
|
||||
const samlAuthProvider = await SamlAuthProvider.query().patchAndFetchById(
|
||||
existingSamlAuthProvider.id,
|
||||
samlAuthProviderPayload
|
||||
);
|
||||
|
||||
return samlAuthProvider;
|
||||
};
|
||||
|
||||
export default upsertSamlAuthProvider;
|
@@ -0,0 +1,52 @@
|
||||
import type { SamlConfig } from '@node-saml/passport-saml';
|
||||
import SamlAuthProvider from '../../models/saml-auth-provider.ee';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
name: string;
|
||||
certificate: string;
|
||||
signatureAlgorithm: SamlConfig['signatureAlgorithm'];
|
||||
issuer: string;
|
||||
entryPoint: string;
|
||||
firstnameAttributeName: string;
|
||||
surnameAttributeName: string;
|
||||
emailAttributeName: string;
|
||||
roleAttributeName: string;
|
||||
defaultRoleId: string;
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
const upsertSamlAuthProvider = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'SamlAuthProvider');
|
||||
|
||||
const samlAuthProviderPayload: Partial<SamlAuthProvider> = {
|
||||
...params.input,
|
||||
};
|
||||
|
||||
const existingSamlAuthProvider = await SamlAuthProvider.query()
|
||||
.limit(1)
|
||||
.first();
|
||||
|
||||
if (!existingSamlAuthProvider) {
|
||||
const samlAuthProvider = await SamlAuthProvider.query().insert(
|
||||
samlAuthProviderPayload
|
||||
);
|
||||
|
||||
return samlAuthProvider;
|
||||
}
|
||||
|
||||
const samlAuthProvider = await SamlAuthProvider.query().patchAndFetchById(
|
||||
existingSamlAuthProvider.id,
|
||||
samlAuthProviderPayload
|
||||
);
|
||||
|
||||
return samlAuthProvider;
|
||||
};
|
||||
|
||||
export default upsertSamlAuthProvider;
|
@@ -1,11 +1,24 @@
|
||||
import SamlAuthProvider from '../../models/saml-auth-provider.ee';
|
||||
import SamlAuthProvidersRoleMapping from '../../models/saml-auth-providers-role-mapping.ee';
|
||||
import Context from '../../types/express/context';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
samlAuthProviderId: string;
|
||||
samlAuthProvidersRoleMappings: [
|
||||
{
|
||||
roleId: string;
|
||||
remoteRoleName: string;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
const upsertSamlAuthProvidersRoleMappings = async (
|
||||
_parent,
|
||||
params,
|
||||
context
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('update', 'SamlAuthProvider');
|
||||
|
@@ -1,7 +1,18 @@
|
||||
import Context from '../../types/express/context';
|
||||
import App from '../../models/app';
|
||||
import globalVariable from '../../helpers/global-variable';
|
||||
|
||||
const verifyConnection = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
input: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
const verifyConnection = async (
|
||||
_parent: unknown,
|
||||
params: Params,
|
||||
context: Context
|
||||
) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
@@ -1,6 +1,11 @@
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const getAppAuthClient = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const getAppAuthClient = async (_parent: unknown, params: Params, context: Context) => {
|
||||
let canSeeAllClients = false;
|
||||
try {
|
||||
context.currentUser.can('read', 'App');
|
||||
@@ -10,7 +15,8 @@ const getAppAuthClient = async (_parent, params, context) => {
|
||||
// void
|
||||
}
|
||||
|
||||
const appAuthClient = AppAuthClient.query()
|
||||
const appAuthClient = AppAuthClient
|
||||
.query()
|
||||
.findById(params.id)
|
||||
.throwIfNotFound();
|
||||
|
@@ -1,6 +1,12 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const getAppAuthClients = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
appKey: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
const getAppAuthClients = async (_parent: unknown, params: Params, context: Context) => {
|
||||
let canSeeAllClients = false;
|
||||
try {
|
||||
context.currentUser.can('read', 'App');
|
||||
@@ -10,7 +16,8 @@ const getAppAuthClients = async (_parent, params, context) => {
|
||||
// void
|
||||
}
|
||||
|
||||
const appConfig = await AppConfig.query()
|
||||
const appConfig = await AppConfig
|
||||
.query()
|
||||
.findOne({
|
||||
key: params.appKey,
|
||||
})
|
||||
@@ -23,8 +30,8 @@ const getAppAuthClients = async (_parent, params, context) => {
|
||||
|
||||
if (!canSeeAllClients) {
|
||||
appAuthClients.where({
|
||||
active: true,
|
||||
});
|
||||
active: true
|
||||
})
|
||||
}
|
||||
|
||||
return await appAuthClients;
|
@@ -1,17 +0,0 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
|
||||
const getAppConfig = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const appConfig = await AppConfig.query()
|
||||
.withGraphFetched({
|
||||
appAuthClients: true,
|
||||
})
|
||||
.findOne({
|
||||
key: params.key,
|
||||
});
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default getAppConfig;
|
23
packages/backend/src/graphql/queries/get-app-config.ee.ts
Normal file
23
packages/backend/src/graphql/queries/get-app-config.ee.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import AppConfig from '../../models/app-config';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
type Params = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
const getAppConfig = async (_parent: unknown, params: Params, context: Context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const appConfig = await AppConfig
|
||||
.query()
|
||||
.withGraphFetched({
|
||||
appAuthClients: true
|
||||
})
|
||||
.findOne({
|
||||
key: params.key
|
||||
});
|
||||
|
||||
return appConfig;
|
||||
};
|
||||
|
||||
export default getAppConfig;
|
@@ -1,14 +1,17 @@
|
||||
import App from '../../models/app';
|
||||
import Connection from '../../models/connection';
|
||||
import Context from '../../types/express/context';
|
||||
|
||||
const getApp = async (_parent, params, context) => {
|
||||
type Params = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
const getApp = async (_parent: unknown, params: Params, context: Context) => {
|
||||
const conditions = context.currentUser.can('read', 'Connection');
|
||||
|
||||
const userConnections = context.currentUser.$relatedQuery('connections');
|
||||
const allConnections = Connection.query();
|
||||
const connectionBaseQuery = conditions.isCreator
|
||||
? userConnections
|
||||
: allConnections;
|
||||
const connectionBaseQuery = conditions.isCreator ? userConnections : allConnections;
|
||||
|
||||
const app = await App.findOneByKey(params.key);
|
||||
|
||||
@@ -18,7 +21,7 @@ const getApp = async (_parent, params, context) => {
|
||||
.select('connections.*')
|
||||
.withGraphFetched({
|
||||
appConfig: true,
|
||||
appAuthClient: true,
|
||||
appAuthClient: true
|
||||
})
|
||||
.fullOuterJoinRelated('steps')
|
||||
.where({
|
@@ -1,17 +0,0 @@
|
||||
import App from '../../models/app';
|
||||
|
||||
const getApps = async (_parent, params) => {
|
||||
const apps = await App.findAll(params.name);
|
||||
|
||||
if (params.onlyWithTriggers) {
|
||||
return apps.filter((app) => app.triggers?.length);
|
||||
}
|
||||
|
||||
if (params.onlyWithActions) {
|
||||
return apps.filter((app) => app.actions?.length);
|
||||
}
|
||||
|
||||
return apps;
|
||||
};
|
||||
|
||||
export default getApps;
|
24
packages/backend/src/graphql/queries/get-apps.ts
Normal file
24
packages/backend/src/graphql/queries/get-apps.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { IApp } from '@automatisch/types';
|
||||
import App from '../../models/app';
|
||||
|
||||
type Params = {
|
||||
name: string;
|
||||
onlyWithTriggers: boolean;
|
||||
onlyWithActions: boolean;
|
||||
};
|
||||
|
||||
const getApps = async (_parent: unknown, params: Params) => {
|
||||
const apps = await App.findAll(params.name);
|
||||
|
||||
if (params.onlyWithTriggers) {
|
||||
return apps.filter((app: IApp) => app.triggers?.length);
|
||||
}
|
||||
|
||||
if (params.onlyWithActions) {
|
||||
return apps.filter((app: IApp) => app.actions?.length);
|
||||
}
|
||||
|
||||
return apps;
|
||||
};
|
||||
|
||||
export default getApps;
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user