Compare commits
1 Commits
hubspot-up
...
hubspot-do
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1893d9ea56 |
@@ -28,7 +28,7 @@ cd packages/web
|
|||||||
rm -rf .env
|
rm -rf .env
|
||||||
echo "
|
echo "
|
||||||
PORT=$WEB_PORT
|
PORT=$WEB_PORT
|
||||||
REACT_APP_BACKEND_URL=http://localhost:$BACKEND_PORT
|
REACT_APP_GRAPHQL_URL=http://localhost:$BACKEND_PORT/graphql
|
||||||
" >> .env
|
" >> .env
|
||||||
cd $CURRENT_DIR
|
cd $CURRENT_DIR
|
||||||
|
|
||||||
|
18
.eslintrc.js
Normal file
18
.eslintrc.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: 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'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- run: cd packages/backend && yarn lint
|
- run: yarn lint
|
||||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
start-backend-server:
|
start-backend-server:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
32
.github/workflows/docs-change.yml
vendored
32
.github/workflows/docs-change.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Automatisch Docs Change
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'packages/docs/**'
|
|
||||||
jobs:
|
|
||||||
label:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Label PR
|
|
||||||
uses: actions/github-script@v6
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { pull_request } = context.payload;
|
|
||||||
|
|
||||||
const label = 'documentation-change';
|
|
||||||
const hasLabel = pull_request.labels.some(({ name }) => name === label);
|
|
||||||
|
|
||||||
if (!hasLabel) {
|
|
||||||
await github.rest.issues.addLabels({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: pull_request.number,
|
|
||||||
labels: [label],
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Label "${label}" added to PR #${pull_request.number}`);
|
|
||||||
} else {
|
|
||||||
console.log(`Label "${label}" already exists on PR #${pull_request.number}`);
|
|
||||||
}
|
|
5
.github/workflows/playwright.yml
vendored
5
.github/workflows/playwright.yml
vendored
@@ -62,9 +62,8 @@ jobs:
|
|||||||
run: yarn && yarn lerna bootstrap
|
run: yarn && yarn lerna bootstrap
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: yarn playwright install --with-deps
|
run: yarn playwright install --with-deps
|
||||||
- name: Build Automatisch web
|
- name: Build Automatisch
|
||||||
working-directory: ./packages/web
|
run: yarn lerna run --scope=@*/{web,cli} build
|
||||||
run: yarn build
|
|
||||||
env:
|
env:
|
||||||
# Keep this until we clean up warnings in build processes
|
# Keep this until we clean up warnings in build processes
|
||||||
CI: false
|
CI: false
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
|
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
|
||||||
"start:web": "lerna run --stream --scope=@*/web dev",
|
"start:web": "lerna run --stream --scope=@*/web dev",
|
||||||
"start:backend": "lerna run --stream --scope=@*/backend dev",
|
"start:backend": "lerna run --stream --scope=@*/backend dev",
|
||||||
|
"lint": "lerna run --no-bail --stream --parallel --scope=@*/{web,backend} lint",
|
||||||
"build:docs": "cd ./packages/docs && yarn install && yarn build"
|
"build:docs": "cd ./packages/docs && yarn install && yarn build"
|
||||||
},
|
},
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
@@ -20,6 +21,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||||
|
"@typescript-eslint/parser": "^5.9.1",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
"start:worker": "node src/worker.js",
|
"start:worker": "node src/worker.js",
|
||||||
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
|
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
|
||||||
"test": "APP_ENV=test vitest run",
|
"test": "APP_ENV=test vitest run",
|
||||||
"lint": "eslint .",
|
"lint": "eslint . --ignore-path ../../.eslintignore",
|
||||||
"db:create": "node ./bin/database/create.js",
|
"db:create": "node ./bin/database/create.js",
|
||||||
"db:seed:user": "node ./bin/database/seed-user.js",
|
"db:seed:user": "node ./bin/database/seed-user.js",
|
||||||
"db:drop": "node ./bin/database/drop.js",
|
"db:drop": "node ./bin/database/drop.js",
|
||||||
@@ -95,6 +95,7 @@
|
|||||||
"url": "https://github.com/automatisch/automatisch/issues"
|
"url": "https://github.com/automatisch/automatisch/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/utils": "^7.0.2",
|
||||||
"nodemon": "^2.0.13",
|
"nodemon": "^2.0.13",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^6.3.3",
|
||||||
"vitest": "^1.1.3"
|
"vitest": "^1.1.3"
|
||||||
|
@@ -1,27 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action.js';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Get value',
|
|
||||||
key: 'getValue',
|
|
||||||
description: 'Get value from the persistent datastore.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Key',
|
|
||||||
key: 'key',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'The key of your value to get.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const keyValuePair = await $.datastore.get({
|
|
||||||
key: $.step.parameters.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: keyValuePair,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,4 +0,0 @@
|
|||||||
import getValue from './get-value/index.js';
|
|
||||||
import setValue from './set-value/index.js';
|
|
||||||
|
|
||||||
export default [getValue, setValue];
|
|
@@ -1,36 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action.js';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Set value',
|
|
||||||
key: 'setValue',
|
|
||||||
description: 'Set value to the persistent datastore.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Key',
|
|
||||||
key: 'key',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'The key of your value to set.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Value',
|
|
||||||
key: 'value',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'The value to set.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const keyValuePair = await $.datastore.set({
|
|
||||||
key: $.step.parameters.key,
|
|
||||||
value: $.step.parameters.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: keyValuePair,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" id="icon">
|
|
||||||
<defs>
|
|
||||||
<style>.cls-1{fill:none;}</style>
|
|
||||||
</defs>
|
|
||||||
<title>datastore</title>
|
|
||||||
<circle cx="23" cy="23" r="1"/>
|
|
||||||
<rect x="8" y="22" width="12" height="2"/>
|
|
||||||
<circle cx="23" cy="9" r="1"/>
|
|
||||||
<rect x="8" y="8" width="12" height="2"/>
|
|
||||||
<path d="M26,14a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H6A2,2,0,0,0,4,6v6a2,2,0,0,0,2,2H8v4H6a2,2,0,0,0-2,2v6a2,2,0,0,0,2,2H26a2,2,0,0,0,2-2V20a2,2,0,0,0-2-2H24V14ZM6,6H26v6H6ZM26,26H6V20H26Zm-4-8H10V14H22Z"/>
|
|
||||||
<rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 704 B |
@@ -1,14 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app.js';
|
|
||||||
import actions from './actions/index.js';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'Datastore',
|
|
||||||
key: 'datastore',
|
|
||||||
iconUrl: '{BASE_URL}/apps/datastore/assets/favicon.svg',
|
|
||||||
authDocUrl: 'https://automatisch.io/docs/apps/datastore/connection',
|
|
||||||
supportsConnections: false,
|
|
||||||
baseUrl: '',
|
|
||||||
apiBaseUrl: '',
|
|
||||||
primaryColor: '001F52',
|
|
||||||
actions,
|
|
||||||
});
|
|
@@ -1,3 +1,4 @@
|
|||||||
|
import FormData from 'form-data';
|
||||||
import defineAction from '../../../../helpers/define-action.js';
|
import defineAction from '../../../../helpers/define-action.js';
|
||||||
|
|
||||||
export default defineAction({
|
export default defineAction({
|
||||||
@@ -5,51 +6,45 @@ export default defineAction({
|
|||||||
key: 'newChat',
|
key: 'newChat',
|
||||||
description: 'Create a new chat session for Helix AI.',
|
description: 'Create a new chat session for Helix AI.',
|
||||||
arguments: [
|
arguments: [
|
||||||
{
|
|
||||||
label: 'Session ID',
|
|
||||||
key: 'sessionId',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'ID of the chat session to continue. Leave empty to start a new chat.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'System Prompt',
|
|
||||||
key: 'systemPrompt',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Optional system prompt to start the chat with. It will be used only for new chat sessions.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Input',
|
label: 'Input',
|
||||||
key: 'input',
|
key: 'input',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'User input to start the chat with.',
|
description: 'Prompt to start the chat with.',
|
||||||
variables: true,
|
variables: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
async run($) {
|
async run($) {
|
||||||
const response = await $.http.post('/api/v1/sessions/chat', {
|
const formData = new FormData();
|
||||||
session_id: $.step.parameters.sessionId,
|
formData.append('input', $.step.parameters.input);
|
||||||
system: $.step.parameters.systemPrompt,
|
formData.append('mode', 'inference');
|
||||||
messages: [
|
formData.append('type', 'text');
|
||||||
{
|
|
||||||
role: 'user',
|
const sessionResponse = await $.http.post('/api/v1/sessions', formData, {
|
||||||
content: {
|
headers: {
|
||||||
content_type: 'text',
|
...formData.getHeaders(),
|
||||||
parts: [$.step.parameters.input],
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$.setActionItem({
|
const sessionId = sessionResponse.data.id;
|
||||||
raw: response.data,
|
|
||||||
});
|
let chatGenerated = false;
|
||||||
|
|
||||||
|
while (!chatGenerated) {
|
||||||
|
const response = await $.http.get(`/api/v1/sessions/${sessionId}`);
|
||||||
|
|
||||||
|
const message =
|
||||||
|
response.data.interactions[response.data.interactions.length - 1];
|
||||||
|
|
||||||
|
if (message.creator === 'system' && message.state === 'complete') {
|
||||||
|
$.setActionItem({
|
||||||
|
raw: message,
|
||||||
|
});
|
||||||
|
|
||||||
|
chatGenerated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -90,7 +90,7 @@ export default defineAction({
|
|||||||
|
|
||||||
async run($) {
|
async run($) {
|
||||||
const method = $.step.parameters.method;
|
const method = $.step.parameters.method;
|
||||||
const data = $.step.parameters.data || null;
|
const data = $.step.parameters.data;
|
||||||
const url = $.step.parameters.url;
|
const url = $.step.parameters.url;
|
||||||
const headers = $.step.parameters.headers;
|
const headers = $.step.parameters.headers;
|
||||||
|
|
||||||
@@ -108,17 +108,14 @@ export default defineAction({
|
|||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
let expectedResponseContentType = headersObject.accept;
|
let contentType = headersObject['content-type'];
|
||||||
|
|
||||||
// in case HEAD request is not supported by the URL
|
// in case HEAD request is not supported by the URL
|
||||||
try {
|
try {
|
||||||
const metadataResponse = await $.http.head(url, {
|
const metadataResponse = await $.http.head(url, {
|
||||||
headers: headersObject,
|
headers: headersObject,
|
||||||
});
|
});
|
||||||
|
contentType = metadataResponse.headers['content-type'];
|
||||||
if (!expectedResponseContentType) {
|
|
||||||
expectedResponseContentType = metadataResponse.headers['content-type'];
|
|
||||||
}
|
|
||||||
|
|
||||||
throwIfFileSizeExceedsLimit(metadataResponse.headers['content-length']);
|
throwIfFileSizeExceedsLimit(metadataResponse.headers['content-length']);
|
||||||
// eslint-disable-next-line no-empty
|
// eslint-disable-next-line no-empty
|
||||||
@@ -131,7 +128,7 @@ export default defineAction({
|
|||||||
headers: headersObject,
|
headers: headersObject,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isPossiblyTextBased(expectedResponseContentType)) {
|
if (!isPossiblyTextBased(contentType)) {
|
||||||
requestData.responseType = 'arraybuffer';
|
requestData.responseType = 'arraybuffer';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +138,7 @@ export default defineAction({
|
|||||||
|
|
||||||
let responseData = response.data;
|
let responseData = response.data;
|
||||||
|
|
||||||
if (!isPossiblyTextBased(expectedResponseContentType)) {
|
if (!isPossiblyTextBased(contentType)) {
|
||||||
responseData = Buffer.from(responseData).toString('base64');
|
responseData = Buffer.from(responseData).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import createContact from './create-contact/index.js';
|
import createContact from './create-contact/index.js';
|
||||||
import updateContact from './update-contact/index.js';
|
|
||||||
|
|
||||||
export default [createContact, updateContact];
|
export default [createContact];
|
||||||
|
@@ -1,96 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action.js';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Update contact',
|
|
||||||
key: 'updateContact',
|
|
||||||
description: `Updates an existing contact on user's account.`,
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Contact ID',
|
|
||||||
key: 'contactId',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Company name',
|
|
||||||
key: 'company',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Email',
|
|
||||||
key: 'email',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'First name',
|
|
||||||
key: 'firstName',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Last name',
|
|
||||||
key: 'lastName',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
description: 'Last name',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Phone',
|
|
||||||
key: 'phone',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Website URL',
|
|
||||||
key: 'website',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Owner ID',
|
|
||||||
key: 'hubspotOwnerId',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const {
|
|
||||||
contactId,
|
|
||||||
company,
|
|
||||||
email,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
phone,
|
|
||||||
website,
|
|
||||||
hubspotOwnerId,
|
|
||||||
} = $.step.parameters;
|
|
||||||
|
|
||||||
const response = await $.http.patch(
|
|
||||||
`crm/v3/objects/contacts/${contactId}`,
|
|
||||||
{
|
|
||||||
properties: {
|
|
||||||
company,
|
|
||||||
email,
|
|
||||||
firstname: firstName,
|
|
||||||
lastname: lastName,
|
|
||||||
phone,
|
|
||||||
website,
|
|
||||||
hubspot_owner_id: hubspotOwnerId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$.setActionItem({ raw: response.data });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -64,17 +64,32 @@ export default defineAction({
|
|||||||
value: '1',
|
value: '1',
|
||||||
description:
|
description:
|
||||||
'The ID of the stage this deal will be added to. If omitted, the deal will be placed in the first stage of the default pipeline.',
|
'The ID of the stage this deal will be added to. If omitted, the deal will be placed in the first stage of the default pipeline.',
|
||||||
variables: true,
|
options: [
|
||||||
source: {
|
{
|
||||||
type: 'query',
|
label: 'Qualified (Pipeline)',
|
||||||
name: 'getDynamicData',
|
value: 1,
|
||||||
arguments: [
|
},
|
||||||
{
|
{
|
||||||
name: 'key',
|
label: 'Contact Made (Pipeline)',
|
||||||
value: 'listStages',
|
value: 2,
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
},
|
label: 'Prospect Qualified (Pipeline)',
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Needs Defined (Pipeline)',
|
||||||
|
value: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Proposal Made (Pipeline)',
|
||||||
|
value: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Negotiations Started (Pipeline)',
|
||||||
|
value: 6,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Owner',
|
label: 'Owner',
|
||||||
|
@@ -1,25 +1,23 @@
|
|||||||
import listActivityTypes from './list-activity-types/index.js';
|
import listActivityTypes from './list-activity-types/index.js';
|
||||||
import listCurrencies from './list-currencies/index.js';
|
import listCurrencies from './list-currencies/index.js';
|
||||||
import listDeals from './list-deals/index.js';
|
import listDeals from './list-deals/index.js';
|
||||||
import listLeadLabels from './list-lead-labels/index.js';
|
|
||||||
import listLeads from './list-leads/index.js';
|
import listLeads from './list-leads/index.js';
|
||||||
import listOrganizationLabelField from './list-organization-label-field/index.js';
|
import listLeadLabels from './list-lead-labels/index.js';
|
||||||
import listOrganizations from './list-organizations/index.js';
|
import listOrganizations from './list-organizations/index.js';
|
||||||
|
import listOrganizationLabelField from './list-organization-label-field/index.js';
|
||||||
import listPersonLabelField from './list-person-label-field/index.js';
|
import listPersonLabelField from './list-person-label-field/index.js';
|
||||||
import listPersons from './list-persons/index.js';
|
import listPersons from './list-persons/index.js';
|
||||||
import listStages from './list-stages/index.js';
|
|
||||||
import listUsers from './list-users/index.js';
|
import listUsers from './list-users/index.js';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
listActivityTypes,
|
listActivityTypes,
|
||||||
listCurrencies,
|
listCurrencies,
|
||||||
listDeals,
|
listDeals,
|
||||||
listLeadLabels,
|
|
||||||
listLeads,
|
listLeads,
|
||||||
listOrganizationLabelField,
|
listLeadLabels,
|
||||||
listOrganizations,
|
listOrganizations,
|
||||||
|
listOrganizationLabelField,
|
||||||
listPersonLabelField,
|
listPersonLabelField,
|
||||||
listPersons,
|
listPersons,
|
||||||
listStages,
|
|
||||||
listUsers,
|
listUsers,
|
||||||
];
|
];
|
||||||
|
@@ -1,23 +0,0 @@
|
|||||||
export default {
|
|
||||||
name: 'List stages',
|
|
||||||
key: 'listStages',
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const stages = {
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data } = await $.http.get('/api/v1/stages');
|
|
||||||
|
|
||||||
if (data.data?.length) {
|
|
||||||
for (const stage of data.data) {
|
|
||||||
stages.data.push({
|
|
||||||
value: stage.id,
|
|
||||||
name: stage.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stages;
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,3 +0,0 @@
|
|||||||
import respondWith from './respond-with/index.js';
|
|
||||||
|
|
||||||
export default [respondWith];
|
|
@@ -1,69 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action.js';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Respond with',
|
|
||||||
key: 'respondWith',
|
|
||||||
description: 'Respond with defined JSON body.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Status code',
|
|
||||||
key: 'statusCode',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
value: '200',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Headers',
|
|
||||||
key: 'headers',
|
|
||||||
type: 'dynamic',
|
|
||||||
required: false,
|
|
||||||
description: 'Add or remove headers as needed',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: 'Key',
|
|
||||||
key: 'key',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'Header key',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Value',
|
|
||||||
key: 'value',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'Header value',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Body',
|
|
||||||
key: 'body',
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
description: 'The content of the response body.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const statusCode = parseInt($.step.parameters.statusCode, 10);
|
|
||||||
const body = $.step.parameters.body;
|
|
||||||
const headers = $.step.parameters.headers.reduce((result, entry) => {
|
|
||||||
return {
|
|
||||||
...result,
|
|
||||||
[entry.key]: entry.value,
|
|
||||||
};
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: {
|
|
||||||
headers,
|
|
||||||
body,
|
|
||||||
statusCode,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,5 +1,4 @@
|
|||||||
import defineApp from '../../helpers/define-app.js';
|
import defineApp from '../../helpers/define-app.js';
|
||||||
import actions from './actions/index.js';
|
|
||||||
import triggers from './triggers/index.js';
|
import triggers from './triggers/index.js';
|
||||||
|
|
||||||
export default defineApp({
|
export default defineApp({
|
||||||
@@ -11,6 +10,5 @@ export default defineApp({
|
|||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '0059F7',
|
primaryColor: '0059F7',
|
||||||
actions,
|
|
||||||
triggers,
|
triggers,
|
||||||
});
|
});
|
||||||
|
@@ -7,20 +7,7 @@ export default defineTrigger({
|
|||||||
key: 'catchRawWebhook',
|
key: 'catchRawWebhook',
|
||||||
type: 'webhook',
|
type: 'webhook',
|
||||||
showWebhookUrl: true,
|
showWebhookUrl: true,
|
||||||
description:
|
description: 'Triggers when the webhook receives a request.',
|
||||||
'Triggers (immediately if configured) when the webhook receives a request.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Wait until flow is done',
|
|
||||||
key: 'workSynchronously',
|
|
||||||
type: 'dropdown',
|
|
||||||
required: true,
|
|
||||||
options: [
|
|
||||||
{ label: 'Yes', value: true },
|
|
||||||
{ label: 'No', value: false },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
async run($) {
|
||||||
const dataItem = {
|
const dataItem = {
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
import User from '../../../../models/user.js';
|
|
||||||
import { renderObject, renderError } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const { email, password } = request.body;
|
|
||||||
const token = await User.authenticate(email, password);
|
|
||||||
|
|
||||||
if (token) {
|
|
||||||
return renderObject(response, { token });
|
|
||||||
}
|
|
||||||
|
|
||||||
renderError(response, [{ general: ['Incorrect email or password.'] }]);
|
|
||||||
};
|
|
@@ -1,39 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
|
|
||||||
describe('POST /api/v1/access-tokens', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await createUser({
|
|
||||||
email: 'user@automatisch.io',
|
|
||||||
password: 'password',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the token data with correct credentials', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/api/v1/access-tokens')
|
|
||||||
.send({
|
|
||||||
email: 'user@automatisch.io',
|
|
||||||
password: 'password',
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data.token.length).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return error with incorrect credentials', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.post('/api/v1/access-tokens')
|
|
||||||
.send({
|
|
||||||
email: 'incorrect@email.com',
|
|
||||||
password: 'incorrectpassword',
|
|
||||||
})
|
|
||||||
.expect(422);
|
|
||||||
|
|
||||||
expect(response.body.errors.general).toEqual([
|
|
||||||
'Incorrect email or password.',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -4,7 +4,6 @@ import AppAuthClient from '../../../../../models/app-auth-client.js';
|
|||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
const appAuthClient = await AppAuthClient.query()
|
const appAuthClient = await AppAuthClient.query()
|
||||||
.findById(request.params.appAuthClientId)
|
.findById(request.params.appAuthClientId)
|
||||||
.where({ app_key: request.params.appKey })
|
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
renderObject(response, appAuthClient);
|
renderObject(response, appAuthClient);
|
@@ -0,0 +1,52 @@
|
|||||||
|
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||||
|
import request from 'supertest';
|
||||||
|
import Crypto from 'crypto';
|
||||||
|
import app from '../../../../../app.js';
|
||||||
|
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
||||||
|
import { createUser } from '../../../../../../test/factories/user.js';
|
||||||
|
import getAdminAppAuthClientMock from '../../../../../../test/mocks/rest/api/v1/admin/get-app-auth-client.js';
|
||||||
|
import { createAppAuthClient } from '../../../../../../test/factories/app-auth-client.js';
|
||||||
|
import { createRole } from '../../../../../../test/factories/role.js';
|
||||||
|
import * as license from '../../../../../helpers/license.ee.js';
|
||||||
|
|
||||||
|
describe('GET /api/v1/admin/app-auth-clients/:appAuthClientId', () => {
|
||||||
|
let currentUser, currentUserRole, currentAppAuthClient, token;
|
||||||
|
|
||||||
|
describe('with valid license key', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
||||||
|
|
||||||
|
currentUserRole = await createRole({ key: 'admin' });
|
||||||
|
currentUser = await createUser({ roleId: currentUserRole.id });
|
||||||
|
currentAppAuthClient = await createAppAuthClient();
|
||||||
|
|
||||||
|
token = createAuthTokenByUserId(currentUser.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return specified app auth client info', async () => {
|
||||||
|
const response = await request(app)
|
||||||
|
.get(`/api/v1/admin/app-auth-clients/${currentAppAuthClient.id}`)
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const expectedPayload = getAdminAppAuthClientMock(currentAppAuthClient);
|
||||||
|
expect(response.body).toEqual(expectedPayload);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return not found response for not existing app auth client UUID', async () => {
|
||||||
|
const notExistingAppAuthClientUUID = Crypto.randomUUID();
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.get(`/api/v1/admin/app-auth-clients/${notExistingAppAuthClientUUID}`)
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return bad request response for invalid UUID', async () => {
|
||||||
|
await request(app)
|
||||||
|
.get('/api/v1/admin/app-auth-clients/invalidAppAuthClientUUID')
|
||||||
|
.set('Authorization', token)
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -1,55 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../../test/factories/user.js';
|
|
||||||
import { createRole } from '../../../../../../test/factories/role.js';
|
|
||||||
import getAppAuthClientMock from '../../../../../../test/mocks/rest/api/v1/admin/apps/get-auth-client.js';
|
|
||||||
import { createAppAuthClient } from '../../../../../../test/factories/app-auth-client.js';
|
|
||||||
import * as license from '../../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/admin/apps/:appKey/auth-clients/:appAuthClientId', () => {
|
|
||||||
let currentUser, adminRole, currentAppAuthClient, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
adminRole = await createRole({ key: 'admin' });
|
|
||||||
currentUser = await createUser({ roleId: adminRole.id });
|
|
||||||
|
|
||||||
currentAppAuthClient = await createAppAuthClient({
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return specified app auth client', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/admin/apps/deepl/auth-clients/${currentAppAuthClient.id}`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppAuthClientMock(currentAppAuthClient);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing app auth client ID', async () => {
|
|
||||||
const notExistingAppAuthClientUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(
|
|
||||||
`/api/v1/admin/apps/deepl/auth-clients/${notExistingAppAuthClientUUID}`
|
|
||||||
)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/admin/apps/deepl/auth-clients/invalidAppAuthClientUUID')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,10 +0,0 @@
|
|||||||
import { renderObject } from '../../../../../helpers/renderer.js';
|
|
||||||
import AppAuthClient from '../../../../../models/app-auth-client.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const appAuthClients = await AppAuthClient.query()
|
|
||||||
.where({ app_key: request.params.appKey })
|
|
||||||
.orderBy('created_at', 'desc');
|
|
||||||
|
|
||||||
renderObject(response, appAuthClients);
|
|
||||||
};
|
|
@@ -1,44 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../../test/factories/user.js';
|
|
||||||
import { createRole } from '../../../../../../test/factories/role.js';
|
|
||||||
import getAuthClientsMock from '../../../../../../test/mocks/rest/api/v1/admin/apps/get-auth-clients.js';
|
|
||||||
import { createAppAuthClient } from '../../../../../../test/factories/app-auth-client.js';
|
|
||||||
import * as license from '../../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/admin/apps/:appKey/auth-clients', () => {
|
|
||||||
let currentUser, adminRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
adminRole = await createRole({ key: 'admin' });
|
|
||||||
currentUser = await createUser({ roleId: adminRole.id });
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return specified app auth client info', async () => {
|
|
||||||
const appAuthClientOne = await createAppAuthClient({
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const appAuthClientTwo = await createAppAuthClient({
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/admin/apps/deepl/auth-clients')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAuthClientsMock([
|
|
||||||
appAuthClientTwo,
|
|
||||||
appAuthClientOne,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,14 +0,0 @@
|
|||||||
import { renderObject } from '../../../../../helpers/renderer.js';
|
|
||||||
import SamlAuthProvider from '../../../../../models/saml-auth-provider.ee.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const samlAuthProvider = await SamlAuthProvider.query()
|
|
||||||
.findById(request.params.samlAuthProviderId)
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const roleMappings = await samlAuthProvider
|
|
||||||
.$relatedQuery('samlAuthProvidersRoleMappings')
|
|
||||||
.orderBy('remote_role_name', 'asc');
|
|
||||||
|
|
||||||
renderObject(response, roleMappings);
|
|
||||||
};
|
|
@@ -1,51 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createRole } from '../../../../../../test/factories/role.js';
|
|
||||||
import { createUser } from '../../../../../../test/factories/user.js';
|
|
||||||
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
|
|
||||||
import { createRoleMapping } from '../../../../../../test/factories/role-mapping.js';
|
|
||||||
import getRoleMappingsMock from '../../../../../../test/mocks/rest/api/v1/admin/saml-auth-providers/get-role-mappings.ee.js';
|
|
||||||
import * as license from '../../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mappings', () => {
|
|
||||||
let roleMappingOne, roleMappingTwo, samlAuthProvider, currentUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const role = await createRole({ key: 'admin' });
|
|
||||||
currentUser = await createUser({ roleId: role.id });
|
|
||||||
|
|
||||||
samlAuthProvider = await createSamlAuthProvider();
|
|
||||||
|
|
||||||
roleMappingOne = await createRoleMapping({
|
|
||||||
samlAuthProviderId: samlAuthProvider.id,
|
|
||||||
remoteRoleName: 'Admin',
|
|
||||||
});
|
|
||||||
|
|
||||||
roleMappingTwo = await createRoleMapping({
|
|
||||||
samlAuthProviderId: samlAuthProvider.id,
|
|
||||||
remoteRoleName: 'User',
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return role mappings', async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(
|
|
||||||
`/api/v1/admin/saml-auth-providers/${samlAuthProvider.id}/role-mappings`
|
|
||||||
)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getRoleMappingsMock([
|
|
||||||
roleMappingOne,
|
|
||||||
roleMappingTwo,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -6,7 +6,5 @@ export default async (request, response) => {
|
|||||||
.findById(request.params.samlAuthProviderId)
|
.findById(request.params.samlAuthProviderId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
renderObject(response, samlAuthProvider, {
|
renderObject(response, samlAuthProvider);
|
||||||
serializer: 'AdminSamlAuthProvider',
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@@ -7,7 +7,5 @@ export default async (request, response) => {
|
|||||||
'desc'
|
'desc'
|
||||||
);
|
);
|
||||||
|
|
||||||
renderObject(response, samlAuthProviders, {
|
renderObject(response, samlAuthProviders);
|
||||||
serializer: 'AdminSamlAuthProvider',
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,7 @@ import AppAuthClient from '../../../../models/app-auth-client.js';
|
|||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
const appAuthClient = await AppAuthClient.query()
|
const appAuthClient = await AppAuthClient.query()
|
||||||
.findById(request.params.appAuthClientId)
|
.findById(request.params.appAuthClientId)
|
||||||
.where({ app_key: request.params.appKey, active: true })
|
.where({ active: true })
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
renderObject(response, appAuthClient);
|
renderObject(response, appAuthClient);
|
@@ -4,27 +4,25 @@ import Crypto from 'crypto';
|
|||||||
import app from '../../../../app.js';
|
import app from '../../../../app.js';
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
import { createUser } from '../../../../../test/factories/user.js';
|
||||||
import getAppAuthClientMock from '../../../../../test/mocks/rest/api/v1/apps/get-auth-client.js';
|
import getAppAuthClientMock from '../../../../../test/mocks/rest/api/v1/admin/get-app-auth-client.js';
|
||||||
import { createAppAuthClient } from '../../../../../test/factories/app-auth-client.js';
|
import { createAppAuthClient } from '../../../../../test/factories/app-auth-client.js';
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
import * as license from '../../../../helpers/license.ee.js';
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/auth-clients/:appAuthClientId', () => {
|
describe('GET /api/v1/app-auth-clients/:id', () => {
|
||||||
let currentUser, currentAppAuthClient, token;
|
let currentUser, currentAppAuthClient, token;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
||||||
|
|
||||||
currentUser = await createUser();
|
currentUser = await createUser();
|
||||||
currentAppAuthClient = await createAppAuthClient({
|
currentAppAuthClient = await createAppAuthClient();
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
token = createAuthTokenByUserId(currentUser.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return specified app auth client', async () => {
|
it('should return specified app auth client info', async () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.get(`/api/v1/apps/deepl/auth-clients/${currentAppAuthClient.id}`)
|
.get(`/api/v1/app-auth-clients/${currentAppAuthClient.id}`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
@@ -36,14 +34,14 @@ describe('GET /api/v1/apps/:appKey/auth-clients/:appAuthClientId', () => {
|
|||||||
const notExistingAppAuthClientUUID = Crypto.randomUUID();
|
const notExistingAppAuthClientUUID = Crypto.randomUUID();
|
||||||
|
|
||||||
await request(app)
|
await request(app)
|
||||||
.get(`/api/v1/apps/deepl/auth-clients/${notExistingAppAuthClientUUID}`)
|
.get(`/api/v1/app-auth-clients/${notExistingAppAuthClientUUID}`)
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
it('should return bad request response for invalid UUID', async () => {
|
||||||
await request(app)
|
await request(app)
|
||||||
.get('/api/v1/apps/deepl/auth-clients/invalidAppAuthClientUUID')
|
.get('/api/v1/app-auth-clients/invalidAppAuthClientUUID')
|
||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
});
|
});
|
@@ -1,11 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const substeps = await App.findActionSubsteps(
|
|
||||||
request.params.appKey,
|
|
||||||
request.params.actionKey
|
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, substeps);
|
|
||||||
};
|
|
@@ -1,52 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getActionSubstepsMock from '../../../../../test/mocks/rest/api/v1/apps/get-action-substeps.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/actions/:actionKey/substeps', () => {
|
|
||||||
let currentUser, exampleApp, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
exampleApp = await App.findOneByKey('github');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the app auth info', async () => {
|
|
||||||
const actions = await App.findActionsByKey('github');
|
|
||||||
const exampleAction = actions.find(
|
|
||||||
(action) => action.key === 'createIssue'
|
|
||||||
);
|
|
||||||
|
|
||||||
const endpointUrl = `/api/v1/apps/${exampleApp.key}/actions/${exampleAction.key}/substeps`;
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(endpointUrl)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getActionSubstepsMock(exampleAction.substeps);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/actions/invalid-actions-key/substeps')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return empty array for invalid action key', async () => {
|
|
||||||
const endpointUrl = `/api/v1/apps/${exampleApp.key}/actions/invalid-action-key/substeps`;
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(endpointUrl)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,8 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const actions = await App.findActionsByKey(request.params.appKey);
|
|
||||||
|
|
||||||
renderObject(response, actions, { serializer: 'Action' });
|
|
||||||
};
|
|
@@ -1,35 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getActionsMock from '../../../../../test/mocks/rest/api/v1/apps/get-actions.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/actions', () => {
|
|
||||||
let currentUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the app actions', async () => {
|
|
||||||
const exampleApp = await App.findOneByKey('github');
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/apps/${exampleApp.key}/actions`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getActionsMock(exampleApp.actions);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/actions')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,16 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
let apps = await App.findAll(request.query.name);
|
|
||||||
|
|
||||||
if (request.query.onlyWithTriggers) {
|
|
||||||
apps = apps.filter((app) => app.triggers?.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.query.onlyWithActions) {
|
|
||||||
apps = apps.filter((app) => app.actions?.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderObject(response, apps, { serializer: 'App' });
|
|
||||||
};
|
|
@@ -1,63 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getAppsMock from '../../../../../test/mocks/rest/api/v1/apps/get-apps.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps', () => {
|
|
||||||
let currentUser, apps, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
apps = await App.findAll();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return all apps', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(apps);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return all apps filtered by name', async () => {
|
|
||||||
const appsWithNameGit = apps.filter((app) => app.name.includes('Git'));
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps?name=Git')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithNameGit);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return only the apps with triggers', async () => {
|
|
||||||
const appsWithTriggers = apps.filter((app) => app.triggers?.length > 0);
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps?onlyWithTriggers=true')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithTriggers);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return only the apps with actions', async () => {
|
|
||||||
const appsWithActions = apps.filter((app) => app.actions?.length > 0);
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps?onlyWithActions=true')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock(appsWithActions);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,10 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import AppAuthClient from '../../../../models/app-auth-client.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const appAuthClients = await AppAuthClient.query()
|
|
||||||
.where({ app_key: request.params.appKey, active: true })
|
|
||||||
.orderBy('created_at', 'desc');
|
|
||||||
|
|
||||||
renderObject(response, appAuthClients);
|
|
||||||
};
|
|
@@ -1,42 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import getAuthClientsMock from '../../../../../test/mocks/rest/api/v1/apps/get-auth-clients.js';
|
|
||||||
import { createAppAuthClient } from '../../../../../test/factories/app-auth-client.js';
|
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/auth-clients', () => {
|
|
||||||
let currentUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
currentUser = await createUser();
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return specified app auth client info', async () => {
|
|
||||||
const appAuthClientOne = await createAppAuthClient({
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const appAuthClientTwo = await createAppAuthClient({
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps/deepl/auth-clients')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAuthClientsMock([
|
|
||||||
appAuthClientTwo,
|
|
||||||
appAuthClientOne,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,8 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const auth = await App.findAuthByKey(request.params.appKey);
|
|
||||||
|
|
||||||
renderObject(response, auth, { serializer: 'Auth' });
|
|
||||||
};
|
|
@@ -1,35 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getAuthMock from '../../../../../test/mocks/rest/api/v1/apps/get-auth.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/auth', () => {
|
|
||||||
let currentUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the app auth info', async () => {
|
|
||||||
const exampleApp = await App.findOneByKey('github');
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/apps/${exampleApp.key}/auth`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAuthMock(exampleApp.auth);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/auth')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,15 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import AppConfig from '../../../../models/app-config.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const appConfig = await AppConfig.query()
|
|
||||||
.withGraphFetched({
|
|
||||||
appAuthClients: true,
|
|
||||||
})
|
|
||||||
.findOne({
|
|
||||||
key: request.params.appKey,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
renderObject(response, appConfig);
|
|
||||||
};
|
|
@@ -1,44 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import getAppConfigMock from '../../../../../test/mocks/rest/api/v1/apps/get-config.js';
|
|
||||||
import { createAppConfig } from '../../../../../test/factories/app-config.js';
|
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/config', () => {
|
|
||||||
let currentUser, appConfig, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
currentUser = await createUser();
|
|
||||||
|
|
||||||
appConfig = await createAppConfig({
|
|
||||||
key: 'deepl',
|
|
||||||
allowCustomConnection: true,
|
|
||||||
shared: true,
|
|
||||||
disabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return specified app config info', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/apps/${appConfig.key}/config`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppConfigMock(appConfig);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/not-existing-app-key/config')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,24 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import App from '../../../../models/app.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const app = await App.findOneByKey(request.params.appKey);
|
|
||||||
|
|
||||||
const connections = await request.currentUser.authorizedConnections
|
|
||||||
.clone()
|
|
||||||
.select('connections.*')
|
|
||||||
.withGraphFetched({
|
|
||||||
appConfig: true,
|
|
||||||
appAuthClient: true,
|
|
||||||
})
|
|
||||||
.fullOuterJoinRelated('steps')
|
|
||||||
.where({
|
|
||||||
'connections.key': app.key,
|
|
||||||
'connections.draft': false,
|
|
||||||
})
|
|
||||||
.countDistinct('steps.flow_id as flowCount')
|
|
||||||
.groupBy('connections.id')
|
|
||||||
.orderBy('created_at', 'desc');
|
|
||||||
|
|
||||||
renderObject(response, connections);
|
|
||||||
};
|
|
@@ -1,101 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
|
||||||
import getConnectionsMock from '../../../../../test/mocks/rest/api/v1/apps/get-connections.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/connections', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the connections data of specified app for current user', async () => {
|
|
||||||
const currentUserConnectionOne = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserConnectionTwo = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps/deepl/connections')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getConnectionsMock([
|
|
||||||
currentUserConnectionTwo,
|
|
||||||
currentUserConnectionOne,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the connections data of specified app for another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
|
|
||||||
const anotherUserConnectionOne = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserConnectionTwo = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps/deepl/connections')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getConnectionsMock([
|
|
||||||
anotherUserConnectionTwo,
|
|
||||||
anotherUserConnectionOne,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid connection UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/connections/invalid-connection-id/connections')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,23 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import App from '../../../../models/app.js';
|
|
||||||
import paginateRest from '../../../../helpers/pagination-rest.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const app = await App.findOneByKey(request.params.appKey);
|
|
||||||
|
|
||||||
const flowsQuery = request.currentUser.authorizedFlows
|
|
||||||
.clone()
|
|
||||||
.joinRelated({
|
|
||||||
steps: true,
|
|
||||||
})
|
|
||||||
.withGraphFetched({
|
|
||||||
steps: true,
|
|
||||||
})
|
|
||||||
.where('steps.app_key', app.key)
|
|
||||||
.orderBy('active', 'desc')
|
|
||||||
.orderBy('updated_at', 'desc');
|
|
||||||
|
|
||||||
const flows = await paginateRest(flowsQuery, request.query.page);
|
|
||||||
|
|
||||||
renderObject(response, flows);
|
|
||||||
};
|
|
@@ -1,129 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
|
||||||
import getFlowsMock from '../../../../../test/mocks/rest/api/v1/flows/get-flows.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/flows', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of specified app for current user', async () => {
|
|
||||||
const currentUserFlowOne = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserFlowTwo = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps/webhook/flows')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[currentUserFlowOne],
|
|
||||||
[triggerStepFlowOne, actionStepFlowOne]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of specified app for another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserFlowOne = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserFlowTwo = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/apps/webhook/flows')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[anotherUserFlowOne],
|
|
||||||
[triggerStepFlowOne, actionStepFlowOne]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/flows')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,11 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const substeps = await App.findTriggerSubsteps(
|
|
||||||
request.params.appKey,
|
|
||||||
request.params.triggerKey
|
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, substeps);
|
|
||||||
};
|
|
@@ -1,52 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getTriggerSubstepsMock from '../../../../../test/mocks/rest/api/v1/apps/get-trigger-substeps.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/triggers/:triggerKey/substeps', () => {
|
|
||||||
let currentUser, exampleApp, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
exampleApp = await App.findOneByKey('github');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the app auth info', async () => {
|
|
||||||
const triggers = await App.findTriggersByKey('github');
|
|
||||||
const exampleTrigger = triggers.find(
|
|
||||||
(trigger) => trigger.key === 'newIssues'
|
|
||||||
);
|
|
||||||
|
|
||||||
const endpointUrl = `/api/v1/apps/${exampleApp.key}/triggers/${exampleTrigger.key}/substeps`;
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(endpointUrl)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getTriggerSubstepsMock(exampleTrigger.substeps);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/triggers/invalid-trigger-key/substeps')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return empty array for invalid trigger key', async () => {
|
|
||||||
const endpointUrl = `/api/v1/apps/${exampleApp.key}/triggers/invalid-trigger-key/substeps`;
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(endpointUrl)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,8 +0,0 @@
|
|||||||
import App from '../../../../models/app.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const triggers = await App.findTriggersByKey(request.params.appKey);
|
|
||||||
|
|
||||||
renderObject(response, triggers, { serializer: 'Trigger' });
|
|
||||||
};
|
|
@@ -1,35 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import App from '../../../../models/app';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import getTriggersMock from '../../../../../test/mocks/rest/api/v1/apps/get-triggers.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/apps/:appKey/triggers', () => {
|
|
||||||
let currentUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the app triggers', async () => {
|
|
||||||
const exampleApp = await App.findOneByKey('github');
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/apps/${exampleApp.key}/triggers`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getTriggersMock(exampleApp.triggers);
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for invalid app key', async () => {
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/apps/invalid-app-key/triggers')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,24 +0,0 @@
|
|||||||
import appConfig from '../../../../config/app.js';
|
|
||||||
import Config from '../../../../models/config.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const defaultConfig = {
|
|
||||||
disableNotificationsPage: appConfig.disableNotificationsPage,
|
|
||||||
disableFavicon: appConfig.disableFavicon,
|
|
||||||
additionalDrawerLink: appConfig.additionalDrawerLink,
|
|
||||||
additionalDrawerLinkText: appConfig.additionalDrawerLinkText,
|
|
||||||
};
|
|
||||||
|
|
||||||
let config = await Config.query().orderBy('key', 'asc');
|
|
||||||
|
|
||||||
config = config.reduce((computedConfig, configEntry) => {
|
|
||||||
const { key, value } = configEntry;
|
|
||||||
|
|
||||||
computedConfig[key] = value?.data;
|
|
||||||
|
|
||||||
return computedConfig;
|
|
||||||
}, defaultConfig);
|
|
||||||
|
|
||||||
renderObject(response, config);
|
|
||||||
};
|
|
@@ -1,51 +0,0 @@
|
|||||||
import { vi, expect, describe, it } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import { createConfig } from '../../../../../test/factories/config.js';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import configMock from '../../../../../test/mocks/rest/api/v1/automatisch/config.js';
|
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/automatisch/config', () => {
|
|
||||||
it('should return Automatisch config', async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
const logoConfig = await createConfig({
|
|
||||||
key: 'logo.svgData',
|
|
||||||
value: { data: '<svg>Sample</svg>' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const primaryDarkConfig = await createConfig({
|
|
||||||
key: 'palette.primary.dark',
|
|
||||||
value: { data: '#001F52' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const primaryLightConfig = await createConfig({
|
|
||||||
key: 'palette.primary.light',
|
|
||||||
value: { data: '#4286FF' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const primaryMainConfig = await createConfig({
|
|
||||||
key: 'palette.primary.main',
|
|
||||||
value: { data: '#0059F7' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const titleConfig = await createConfig({
|
|
||||||
key: 'title',
|
|
||||||
value: { data: 'Sample Title' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/automatisch/config')
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = configMock(
|
|
||||||
logoConfig,
|
|
||||||
primaryDarkConfig,
|
|
||||||
primaryLightConfig,
|
|
||||||
primaryMainConfig,
|
|
||||||
titleConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,14 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
let connection = await request.currentUser.authorizedConnections
|
|
||||||
.clone()
|
|
||||||
.findOne({
|
|
||||||
id: request.params.connectionId,
|
|
||||||
})
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
connection = await connection.testAndUpdateConnection();
|
|
||||||
|
|
||||||
renderObject(response, connection);
|
|
||||||
};
|
|
@@ -1,123 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
|
||||||
|
|
||||||
describe('POST /api/v1/connections/:connectionId/test', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the connection as not verified for current user', async () => {
|
|
||||||
const currentUserConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
verified: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/connections/${currentUserConnection.id}/test`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data.verified).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the connection as not verified for another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
|
|
||||||
const anotherUserConnection = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
verified: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/connections/${anotherUserConnection.id}/test`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data.verified).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing connection UUID', async () => {
|
|
||||||
const notExistingConnectionUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post(`/api/v1/connections/${notExistingConnectionUUID}/test`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/api/v1/connections/invalidConnectionUUID/test')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,20 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import paginateRest from '../../../../helpers/pagination-rest.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const flowsQuery = request.currentUser.authorizedFlows
|
|
||||||
.clone()
|
|
||||||
.joinRelated({
|
|
||||||
steps: true,
|
|
||||||
})
|
|
||||||
.withGraphFetched({
|
|
||||||
steps: true,
|
|
||||||
})
|
|
||||||
.where('steps.connection_id', request.params.connectionId)
|
|
||||||
.orderBy('active', 'desc')
|
|
||||||
.orderBy('updated_at', 'desc');
|
|
||||||
|
|
||||||
const flows = await paginateRest(flowsQuery, request.query.page);
|
|
||||||
|
|
||||||
renderObject(response, flows);
|
|
||||||
};
|
|
@@ -1,128 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection.js';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
|
||||||
import getFlowsMock from '../../../../../test/mocks/rest/api/v1/flows/get-flows.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/connections/:connectionId/flows', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of specified connection for current user', async () => {
|
|
||||||
const currentUserFlowOne = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const currentUserConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'webhook',
|
|
||||||
connectionId: currentUserConnection.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserFlowTwo = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/connections/${currentUserConnection.id}/flows`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[currentUserFlowOne],
|
|
||||||
[triggerStepFlowOne, actionStepFlowOne]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of specified connection for another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserFlowOne = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const anotherUserConnection = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'webhook',
|
|
||||||
connectionId: anotherUserConnection.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserFlowTwo = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/connections/${anotherUserConnection.id}/flows`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[anotherUserFlowOne],
|
|
||||||
[triggerStepFlowOne, actionStepFlowOne]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,23 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import paginateRest from '../../../../helpers/pagination-rest.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const execution = await request.currentUser.authorizedExecutions
|
|
||||||
.clone()
|
|
||||||
.withSoftDeleted()
|
|
||||||
.findById(request.params.executionId)
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const executionStepsQuery = execution
|
|
||||||
.$relatedQuery('executionSteps')
|
|
||||||
.withSoftDeleted()
|
|
||||||
.withGraphFetched('step')
|
|
||||||
.orderBy('created_at', 'asc');
|
|
||||||
|
|
||||||
const executionSteps = await paginateRest(
|
|
||||||
executionStepsQuery,
|
|
||||||
request.query.page
|
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, executionSteps);
|
|
||||||
};
|
|
@@ -1,153 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createExecution } from '../../../../../test/factories/execution.js';
|
|
||||||
import { createExecutionStep } from '../../../../../test/factories/execution-step.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getExecutionStepsMock from '../../../../../test/mocks/rest/api/v1/executions/get-execution-steps';
|
|
||||||
|
|
||||||
describe('GET /api/v1/executions/:executionId/execution-steps', () => {
|
|
||||||
let currentUser, currentUserRole, anotherUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
anotherUser = await createUser();
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the execution steps of current user execution', async () => {
|
|
||||||
const currentUserFlow = await createFlow({
|
|
||||||
userId: currentUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecution = await createExecution({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecutionStepOne = await createExecutionStep({
|
|
||||||
executionId: currentUserExecution.id,
|
|
||||||
stepId: stepOne.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecutionStepTwo = await createExecutionStep({
|
|
||||||
executionId: currentUserExecution.id,
|
|
||||||
stepId: stepTwo.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/executions/${currentUserExecution.id}/execution-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionStepsMock(
|
|
||||||
[currentUserExecutionStepOne, currentUserExecutionStepTwo],
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the execution steps of another user execution', async () => {
|
|
||||||
const anotherUserFlow = await createFlow({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecution = await createExecution({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecutionStepOne = await createExecutionStep({
|
|
||||||
executionId: anotherUserExecution.id,
|
|
||||||
stepId: stepOne.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecutionStepTwo = await createExecutionStep({
|
|
||||||
executionId: anotherUserExecution.id,
|
|
||||||
stepId: stepTwo.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/executions/${anotherUserExecution.id}/execution-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionStepsMock(
|
|
||||||
[anotherUserExecutionStepOne, anotherUserExecutionStepTwo],
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing execution step UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingExcecutionUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/executions/${notExistingExcecutionUUID}/execution-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/executions/invalidExecutionUUID/execution-steps')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,16 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const execution = await request.currentUser.authorizedExecutions
|
|
||||||
.clone()
|
|
||||||
.withGraphFetched({
|
|
||||||
flow: {
|
|
||||||
steps: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.withSoftDeleted()
|
|
||||||
.findById(request.params.executionId)
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
renderObject(response, execution);
|
|
||||||
};
|
|
@@ -1,134 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createExecution } from '../../../../../test/factories/execution.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getExecutionMock from '../../../../../test/mocks/rest/api/v1/executions/get-execution';
|
|
||||||
|
|
||||||
describe('GET /api/v1/executions/:executionId', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the execution data of current user', async () => {
|
|
||||||
const currentUserFlow = await createFlow({
|
|
||||||
userId: currentUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecution = await createExecution({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/executions/${currentUserExecution.id}`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionMock(
|
|
||||||
currentUserExecution,
|
|
||||||
currentUserFlow,
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the execution data of another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
|
|
||||||
const anotherUserFlow = await createFlow({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecution = await createExecution({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/executions/${anotherUserExecution.id}`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionMock(
|
|
||||||
anotherUserExecution,
|
|
||||||
anotherUserFlow,
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing execution UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingExcecutionUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/executions/${notExistingExcecutionUUID}`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/executions/invalidExecutionUUID')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,27 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import paginateRest from '../../../../helpers/pagination-rest.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const executionsQuery = request.currentUser.authorizedExecutions
|
|
||||||
.clone()
|
|
||||||
.withSoftDeleted()
|
|
||||||
.orderBy('created_at', 'desc')
|
|
||||||
.withGraphFetched({
|
|
||||||
flow: {
|
|
||||||
steps: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const executions = await paginateRest(executionsQuery, request.query.page);
|
|
||||||
|
|
||||||
for (const execution of executions.records) {
|
|
||||||
const executionSteps = await execution.$relatedQuery('executionSteps');
|
|
||||||
const status = executionSteps.some((step) => step.status === 'failure')
|
|
||||||
? 'failure'
|
|
||||||
: 'success';
|
|
||||||
|
|
||||||
execution.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderObject(response, executions);
|
|
||||||
};
|
|
@@ -1,119 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createExecution } from '../../../../../test/factories/execution.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getExecutionsMock from '../../../../../test/mocks/rest/api/v1/executions/get-executions';
|
|
||||||
|
|
||||||
describe('GET /api/v1/executions', () => {
|
|
||||||
let currentUser, currentUserRole, anotherUser, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
anotherUser = await createUser();
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the executions of current user', async () => {
|
|
||||||
const currentUserFlow = await createFlow({
|
|
||||||
userId: currentUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecutionOne = await createExecution({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserExecutionTwo = await createExecution({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await currentUserExecutionTwo
|
|
||||||
.$query()
|
|
||||||
.patchAndFetch({ deletedAt: new Date().toISOString() });
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/executions')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionsMock(
|
|
||||||
[currentUserExecutionTwo, currentUserExecutionOne],
|
|
||||||
currentUserFlow,
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the executions of another user', async () => {
|
|
||||||
const anotherUserFlow = await createFlow({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepOne = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const stepTwo = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecutionOne = await createExecution({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserExecutionTwo = await createExecution({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await anotherUserExecutionTwo
|
|
||||||
.$query()
|
|
||||||
.patchAndFetch({ deletedAt: new Date().toISOString() });
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Execution',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/executions')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getExecutionsMock(
|
|
||||||
[anotherUserExecutionTwo, anotherUserExecutionOne],
|
|
||||||
anotherUserFlow,
|
|
||||||
[stepOne, stepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -2,7 +2,6 @@ import { renderObject } from '../../../../helpers/renderer.js';
|
|||||||
|
|
||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
const flow = await request.currentUser.authorizedFlows
|
const flow = await request.currentUser.authorizedFlows
|
||||||
.clone()
|
|
||||||
.withGraphJoined({ steps: true })
|
.withGraphJoined({ steps: true })
|
||||||
.orderBy('steps.position', 'asc')
|
.orderBy('steps.position', 'asc')
|
||||||
.findOne({ 'flows.id': request.params.flowId })
|
.findOne({ 'flows.id': request.params.flowId })
|
||||||
|
@@ -1,21 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import paginateRest from '../../../../helpers/pagination-rest.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const flowsQuery = request.currentUser.authorizedFlows
|
|
||||||
.clone()
|
|
||||||
.withGraphFetched({
|
|
||||||
steps: true,
|
|
||||||
})
|
|
||||||
.where((builder) => {
|
|
||||||
if (request.query.name) {
|
|
||||||
builder.where('flows.name', 'ilike', `%${request.query.name}%`);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.orderBy('active', 'desc')
|
|
||||||
.orderBy('updated_at', 'desc');
|
|
||||||
|
|
||||||
const flows = await paginateRest(flowsQuery, request.query.page);
|
|
||||||
|
|
||||||
renderObject(response, flows);
|
|
||||||
};
|
|
@@ -1,118 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow';
|
|
||||||
import { createStep } from '../../../../../test/factories/step';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getFlowsMock from '../../../../../test/mocks/rest/api/v1/flows/get-flows.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/flows', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of current user', async () => {
|
|
||||||
const currentUserFlowOne = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: currentUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUserFlowTwo = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowTwo = await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
const actionStepFlowTwo = await createStep({
|
|
||||||
flowId: currentUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/flows')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[currentUserFlowTwo, currentUserFlowOne],
|
|
||||||
[
|
|
||||||
triggerStepFlowOne,
|
|
||||||
actionStepFlowOne,
|
|
||||||
triggerStepFlowTwo,
|
|
||||||
actionStepFlowTwo,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the flows data of another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
|
|
||||||
const anotherUserFlowOne = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
const actionStepFlowOne = await createStep({
|
|
||||||
flowId: anotherUserFlowOne.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const anotherUserFlowTwo = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const triggerStepFlowTwo = await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
const actionStepFlowTwo = await createStep({
|
|
||||||
flowId: anotherUserFlowTwo.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/flows')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getFlowsMock(
|
|
||||||
[anotherUserFlowTwo, anotherUserFlowOne],
|
|
||||||
[
|
|
||||||
triggerStepFlowOne,
|
|
||||||
actionStepFlowOne,
|
|
||||||
triggerStepFlowTwo,
|
|
||||||
actionStepFlowTwo,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,12 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
import SamlAuthProvider from '../../../../models/saml-auth-provider.ee.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const samlAuthProviders = await SamlAuthProvider.query()
|
|
||||||
.where({
|
|
||||||
active: true,
|
|
||||||
})
|
|
||||||
.orderBy('created_at', 'desc');
|
|
||||||
|
|
||||||
renderObject(response, samlAuthProviders);
|
|
||||||
};
|
|
@@ -1,30 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import { createSamlAuthProvider } from '../../../../../test/factories/saml-auth-provider.ee.js';
|
|
||||||
import getSamlAuthProvidersMock from '../../../../../test/mocks/rest/api/v1/saml-auth-providers/get-saml-auth-providers.js';
|
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/saml-auth-providers', () => {
|
|
||||||
let samlAuthProviderOne, samlAuthProviderTwo;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
samlAuthProviderOne = await createSamlAuthProvider();
|
|
||||||
samlAuthProviderTwo = await createSamlAuthProvider();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return saml auth providers', async () => {
|
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get('/api/v1/saml-auth-providers')
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getSamlAuthProvidersMock([
|
|
||||||
samlAuthProviderTwo,
|
|
||||||
samlAuthProviderOne,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,18 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const step = await request.currentUser.authorizedSteps
|
|
||||||
.clone()
|
|
||||||
.where('steps.id', request.params.stepId)
|
|
||||||
.whereNotNull('steps.app_key')
|
|
||||||
.whereNotNull('steps.connection_id')
|
|
||||||
.first()
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const dynamicData = await step.createDynamicData(
|
|
||||||
request.body.dynamicDataKey,
|
|
||||||
request.body.parameters
|
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, dynamicData);
|
|
||||||
};
|
|
@@ -1,244 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow';
|
|
||||||
import { createStep } from '../../../../../test/factories/step';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import listRepos from '../../../../apps/github/dynamic-data/list-repos/index.js';
|
|
||||||
import HttpError from '../../../../errors/http.js';
|
|
||||||
|
|
||||||
describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('should return dynamically created data', () => {
|
|
||||||
let repositories;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
repositories = [
|
|
||||||
{
|
|
||||||
value: 'automatisch/automatisch',
|
|
||||||
name: 'automatisch/automatisch',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'automatisch/sample',
|
|
||||||
name: 'automatisch/sample',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
vi.spyOn(listRepos, 'run').mockImplementation(async () => {
|
|
||||||
return {
|
|
||||||
data: repositories,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('of the current users step', async () => {
|
|
||||||
const currentUserFlow = await createFlow({ userId: currentUser.id });
|
|
||||||
const connection = await createConnection({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const actionStep = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
connectionId: connection.id,
|
|
||||||
type: 'action',
|
|
||||||
appKey: 'github',
|
|
||||||
key: 'createIssue',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/steps/${actionStep.id}/dynamic-data`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send({
|
|
||||||
dynamicDataKey: 'listRepos',
|
|
||||||
parameters: {},
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual(repositories);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('of the another users step', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
|
|
||||||
const connection = await createConnection({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const actionStep = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
connectionId: connection.id,
|
|
||||||
type: 'action',
|
|
||||||
appKey: 'github',
|
|
||||||
key: 'createIssue',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/steps/${actionStep.id}/dynamic-data`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send({
|
|
||||||
dynamicDataKey: 'listRepos',
|
|
||||||
parameters: {},
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual(repositories);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('should return error for dynamically created data', () => {
|
|
||||||
let errors;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
errors = {
|
|
||||||
message: 'Not Found',
|
|
||||||
documentation_url:
|
|
||||||
'https://docs.github.com/rest/users/users#get-a-user',
|
|
||||||
};
|
|
||||||
|
|
||||||
vi.spyOn(listRepos, 'run').mockImplementation(async () => {
|
|
||||||
throw new HttpError({ message: errors });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('of the current users step', async () => {
|
|
||||||
const currentUserFlow = await createFlow({ userId: currentUser.id });
|
|
||||||
const connection = await createConnection({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const actionStep = await createStep({
|
|
||||||
flowId: currentUserFlow.id,
|
|
||||||
connectionId: connection.id,
|
|
||||||
type: 'action',
|
|
||||||
appKey: 'github',
|
|
||||||
key: 'createIssue',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/steps/${actionStep.id}/dynamic-data`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send({
|
|
||||||
dynamicDataKey: 'listRepos',
|
|
||||||
parameters: {},
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.errors).toEqual(errors);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingStepUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${notExistingStepUUID}/dynamic-data`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for existing step UUID without app key', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const step = await createStep({ appKey: null });
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${step.id}/dynamic-data`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/api/v1/steps/invalidStepUUID/dynamic-fields')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,17 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const step = await request.currentUser.authorizedSteps
|
|
||||||
.clone()
|
|
||||||
.where('steps.id', request.params.stepId)
|
|
||||||
.whereNotNull('steps.app_key')
|
|
||||||
.first()
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const dynamicFields = await step.createDynamicFields(
|
|
||||||
request.body.dynamicFieldsKey,
|
|
||||||
request.body.parameters
|
|
||||||
);
|
|
||||||
|
|
||||||
renderObject(response, dynamicFields);
|
|
||||||
};
|
|
@@ -1,169 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow';
|
|
||||||
import { createStep } from '../../../../../test/factories/step';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import createDynamicFieldsMock from '../../../../../test/mocks/rest/api/v1/steps/create-dynamic-fields';
|
|
||||||
|
|
||||||
describe('POST /api/v1/steps/:stepId/dynamic-fields', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return dynamically created fields of the current users step', async () => {
|
|
||||||
const currentUserflow = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const actionStep = await createStep({
|
|
||||||
flowId: currentUserflow.id,
|
|
||||||
type: 'action',
|
|
||||||
appKey: 'slack',
|
|
||||||
key: 'sendMessageToChannel',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/steps/${actionStep.id}/dynamic-fields`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send({
|
|
||||||
dynamicFieldsKey: 'listFieldsAfterSendAsBot',
|
|
||||||
parameters: {
|
|
||||||
sendAsBot: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await createDynamicFieldsMock();
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return dynamically created fields of the another users step', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserflow = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const actionStep = await createStep({
|
|
||||||
flowId: anotherUserflow.id,
|
|
||||||
type: 'action',
|
|
||||||
appKey: 'slack',
|
|
||||||
key: 'sendMessageToChannel',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.post(`/api/v1/steps/${actionStep.id}/dynamic-fields`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.send({
|
|
||||||
dynamicFieldsKey: 'listFieldsAfterSendAsBot',
|
|
||||||
parameters: {
|
|
||||||
sendAsBot: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await createDynamicFieldsMock();
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingStepUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${notExistingStepUUID}/dynamic-fields`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for existing step UUID without app key', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const step = await createStep({ appKey: null });
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${step.id}/dynamic-fields`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.post('/api/v1/steps/invalidStepUUID/dynamic-fields')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const step = await request.currentUser.authorizedSteps
|
|
||||||
.findById(request.params.stepId)
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const connection = await step.$relatedQuery('connection').throwIfNotFound();
|
|
||||||
|
|
||||||
renderObject(response, connection);
|
|
||||||
};
|
|
@@ -1,121 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow';
|
|
||||||
import { createStep } from '../../../../../test/factories/step';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getConnectionMock from '../../../../../test/mocks/rest/api/v1/steps/get-connection';
|
|
||||||
|
|
||||||
describe('GET /api/v1/steps/:stepId/connection', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the current user connection data of specified step', async () => {
|
|
||||||
const currentUserflow = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const currentUserConnection = await createConnection();
|
|
||||||
const triggerStep = await createStep({
|
|
||||||
flowId: currentUserflow.id,
|
|
||||||
connectionId: currentUserConnection.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/steps/${triggerStep.id}/connection`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getConnectionMock(currentUserConnection);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the current user connection data of specified step', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const anotherUserConnection = await createConnection();
|
|
||||||
const triggerStep = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
connectionId: anotherUserConnection.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/steps/${triggerStep.id}/connection`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getConnectionMock(anotherUserConnection);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing step without connection', async () => {
|
|
||||||
const stepWithoutConnection = await createStep();
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${stepWithoutConnection.id}/connection`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingFlowUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${notExistingFlowUUID}/connection`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/steps/invalidFlowUUID/connection')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,27 +0,0 @@
|
|||||||
import { ref } from 'objection';
|
|
||||||
import ExecutionStep from '../../../../models/execution-step.js';
|
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const step = await request.currentUser.authorizedSteps
|
|
||||||
.clone()
|
|
||||||
.findOne({ 'steps.id': request.params.stepId })
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const previousSteps = await request.currentUser.authorizedSteps
|
|
||||||
.clone()
|
|
||||||
.withGraphJoined('executionSteps')
|
|
||||||
.where('flow_id', '=', step.flowId)
|
|
||||||
.andWhere('position', '<', step.position)
|
|
||||||
.andWhere(
|
|
||||||
'executionSteps.created_at',
|
|
||||||
'=',
|
|
||||||
ExecutionStep.query()
|
|
||||||
.max('created_at')
|
|
||||||
.where('step_id', '=', ref('steps.id'))
|
|
||||||
.andWhere('status', 'success')
|
|
||||||
)
|
|
||||||
.orderBy('steps.position', 'asc');
|
|
||||||
|
|
||||||
renderObject(response, previousSteps);
|
|
||||||
};
|
|
@@ -1,173 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import Crypto from 'crypto';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow';
|
|
||||||
import { createStep } from '../../../../../test/factories/step';
|
|
||||||
import { createExecutionStep } from '../../../../../test/factories/execution-step.js';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import getPreviousStepsMock from '../../../../../test/mocks/rest/api/v1/steps/get-previous-steps';
|
|
||||||
|
|
||||||
describe('GET /api/v1/steps/:stepId/previous-steps', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUser = await createUser();
|
|
||||||
currentUserRole = await currentUser.$relatedQuery('role');
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the previous steps of the specified step of the current user', async () => {
|
|
||||||
const currentUserflow = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const triggerStep = await createStep({
|
|
||||||
flowId: currentUserflow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepOne = await createStep({
|
|
||||||
flowId: currentUserflow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepTwo = await createStep({
|
|
||||||
flowId: currentUserflow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const executionStepOne = await createExecutionStep({
|
|
||||||
stepId: triggerStep.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const executionStepTwo = await createExecutionStep({
|
|
||||||
stepId: actionStepOne.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/steps/${actionStepTwo.id}/previous-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getPreviousStepsMock(
|
|
||||||
[triggerStep, actionStepOne],
|
|
||||||
[executionStepOne, executionStepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the previous steps of the specified step of another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const triggerStep = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'trigger',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepOne = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionStepTwo = await createStep({
|
|
||||||
flowId: anotherUserFlow.id,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const executionStepOne = await createExecutionStep({
|
|
||||||
stepId: triggerStep.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const executionStepTwo = await createExecutionStep({
|
|
||||||
stepId: actionStepOne.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/steps/${actionStepTwo.id}/previous-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = await getPreviousStepsMock(
|
|
||||||
[triggerStep, actionStepOne],
|
|
||||||
[executionStepOne, executionStepTwo]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response for not existing step UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const notExistingFlowUUID = Crypto.randomUUID();
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/steps/${notExistingFlowUUID}/previous-steps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return bad request response for invalid UUID', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'update',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get('/api/v1/steps/invalidFlowUUID/previous-steps')
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(400);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,7 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const apps = await request.currentUser.getApps(request.query.name);
|
|
||||||
|
|
||||||
renderObject(response, apps, { serializer: 'App' });
|
|
||||||
};
|
|
@@ -1,210 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createRole } from '../../../../../test/factories/role';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
|
||||||
import { createFlow } from '../../../../../test/factories/flow.js';
|
|
||||||
import { createStep } from '../../../../../test/factories/step.js';
|
|
||||||
import { createConnection } from '../../../../../test/factories/connection.js';
|
|
||||||
import getAppsMock from '../../../../../test/mocks/rest/api/v1/users/get-apps.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/users/:userId/apps', () => {
|
|
||||||
let currentUser, currentUserRole, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
currentUserRole = await createRole();
|
|
||||||
currentUser = await createUser({ roleId: currentUserRole.id });
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return all apps of the current user', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOne = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOneActionStepConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowOneActionStepConnection.id,
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowTwo = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const flowTwoTriggerStepConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'github',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowTwoTriggerStepConnection.id,
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'slack',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${currentUser.id}/apps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock();
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return all apps of the another user', async () => {
|
|
||||||
const anotherUser = await createUser();
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOne = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOneActionStepConnection = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowOneActionStepConnection.id,
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowTwo = await createFlow({ userId: anotherUser.id });
|
|
||||||
|
|
||||||
const flowTwoTriggerStepConnection = await createConnection({
|
|
||||||
userId: anotherUser.id,
|
|
||||||
key: 'github',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowTwoTriggerStepConnection.id,
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'slack',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${currentUser.id}/apps`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getAppsMock();
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return specified app of the current user', async () => {
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Flow',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await createPermission({
|
|
||||||
action: 'read',
|
|
||||||
subject: 'Connection',
|
|
||||||
roleId: currentUserRole.id,
|
|
||||||
conditions: ['isCreator'],
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOne = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'webhook',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowOneActionStepConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'deepl',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowOneActionStepConnection.id,
|
|
||||||
flowId: flowOne.id,
|
|
||||||
appKey: 'deepl',
|
|
||||||
});
|
|
||||||
|
|
||||||
const flowTwo = await createFlow({ userId: currentUser.id });
|
|
||||||
|
|
||||||
const flowTwoTriggerStepConnection = await createConnection({
|
|
||||||
userId: currentUser.id,
|
|
||||||
key: 'github',
|
|
||||||
draft: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
connectionId: flowTwoTriggerStepConnection.id,
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'github',
|
|
||||||
});
|
|
||||||
|
|
||||||
await createStep({
|
|
||||||
flowId: flowTwo.id,
|
|
||||||
appKey: 'slack',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${currentUser.id}/apps?name=deepl`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
expect(response.body.data.length).toEqual(1);
|
|
||||||
expect(response.body.data[0].key).toEqual('deepl');
|
|
||||||
});
|
|
||||||
});
|
|
@@ -2,29 +2,15 @@ import { describe, it, expect, beforeEach } from 'vitest';
|
|||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import app from '../../../../app.js';
|
import app from '../../../../app.js';
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
||||||
import { createPermission } from '../../../../../test/factories/permission';
|
|
||||||
import { createRole } from '../../../../../test/factories/role';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
import { createUser } from '../../../../../test/factories/user';
|
||||||
import getCurrentUserMock from '../../../../../test/mocks/rest/api/v1/users/get-current-user';
|
import getCurrentUserMock from '../../../../../test/mocks/rest/api/v1/users/get-current-user';
|
||||||
|
|
||||||
describe('GET /api/v1/users/me', () => {
|
describe('GET /api/v1/users/me', () => {
|
||||||
let role, permissionOne, permissionTwo, currentUser, token;
|
let role, currentUser, token;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
role = await createRole();
|
currentUser = await createUser();
|
||||||
|
role = await currentUser.$relatedQuery('role');
|
||||||
permissionOne = await createPermission({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
permissionTwo = await createPermission({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
currentUser = await createUser({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
token = createAuthTokenByUserId(currentUser.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,11 +20,7 @@ describe('GET /api/v1/users/me', () => {
|
|||||||
.set('Authorization', token)
|
.set('Authorization', token)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = getCurrentUserMock(currentUser, role, [
|
const expectedPayload = getCurrentUserMock(currentUser, role);
|
||||||
permissionOne,
|
|
||||||
permissionTwo,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
expect(response.body).toEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const planAndUsage = await request.currentUser.getPlanAndUsage();
|
|
||||||
|
|
||||||
renderObject(response, planAndUsage);
|
|
||||||
};
|
|
@@ -1,68 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
|
||||||
import { createUser } from '../../../../../test/factories/user.js';
|
|
||||||
import { createSubscription } from '../../../../../test/factories/subscription.js';
|
|
||||||
import { createUsageData } from '../../../../../test/factories/usage-data.js';
|
|
||||||
import appConfig from '../../../../config/app.js';
|
|
||||||
import { DateTime } from 'luxon';
|
|
||||||
|
|
||||||
describe('GET /api/v1/users/:userId/plan-and-usage', () => {
|
|
||||||
let user, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const trialExpiryDate = DateTime.now().plus({ days: 30 }).toISODate();
|
|
||||||
user = await createUser({ trialExpiryDate });
|
|
||||||
token = createAuthTokenByUserId(user.id);
|
|
||||||
|
|
||||||
vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return free trial plan and usage data', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${user.id}/plan-and-usage`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedResponseData = {
|
|
||||||
plan: {
|
|
||||||
id: null,
|
|
||||||
limit: null,
|
|
||||||
name: 'Free Trial',
|
|
||||||
},
|
|
||||||
usage: {
|
|
||||||
task: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual(expectedResponseData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return current plan and usage data', async () => {
|
|
||||||
await createSubscription({ userId: user.id });
|
|
||||||
|
|
||||||
await createUsageData({
|
|
||||||
userId: user.id,
|
|
||||||
consumedTaskCount: 1234,
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${user.id}/plan-and-usage`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedResponseData = {
|
|
||||||
plan: {
|
|
||||||
id: '47384',
|
|
||||||
limit: '10,000',
|
|
||||||
name: '10k - monthly',
|
|
||||||
},
|
|
||||||
usage: {
|
|
||||||
task: 1234,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(response.body.data).toEqual(expectedResponseData);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,9 +0,0 @@
|
|||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const subscription = await request.currentUser
|
|
||||||
.$relatedQuery('currentSubscription')
|
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
renderObject(response, subscription);
|
|
||||||
};
|
|
@@ -1,51 +0,0 @@
|
|||||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import appConfig from '../../../../config/app.js';
|
|
||||||
import app from '../../../../app.js';
|
|
||||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createRole } from '../../../../../test/factories/role';
|
|
||||||
import { createUser } from '../../../../../test/factories/user';
|
|
||||||
import { createSubscription } from '../../../../../test/factories/subscription.js';
|
|
||||||
import getSubscriptionMock from '../../../../../test/mocks/rest/api/v1/users/get-subscription.js';
|
|
||||||
|
|
||||||
describe('GET /api/v1/users/:userId/subscription', () => {
|
|
||||||
let currentUser, role, subscription, token;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true);
|
|
||||||
|
|
||||||
role = await createRole();
|
|
||||||
|
|
||||||
currentUser = await createUser({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
subscription = await createSubscription({ userId: currentUser.id });
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return subscription info of the current user', async () => {
|
|
||||||
const response = await request(app)
|
|
||||||
.get(`/api/v1/users/${currentUser.id}/subscription`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(200);
|
|
||||||
|
|
||||||
const expectedPayload = getSubscriptionMock(subscription);
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedPayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return not found response if there is no current subscription', async () => {
|
|
||||||
const userWithoutSubscription = await createUser({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const token = createAuthTokenByUserId(userWithoutSubscription.id);
|
|
||||||
|
|
||||||
await request(app)
|
|
||||||
.get(`/api/v1/users/${userWithoutSubscription.id}/subscription`)
|
|
||||||
.set('Authorization', token)
|
|
||||||
.expect(404);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,29 +0,0 @@
|
|||||||
import Flow from '../../models/flow.js';
|
|
||||||
import logger from '../../helpers/logger.js';
|
|
||||||
import handlerSync from '../../helpers/webhook-handler-sync.js';
|
|
||||||
|
|
||||||
export default async (request, response) => {
|
|
||||||
const computedRequestPayload = {
|
|
||||||
headers: request.headers,
|
|
||||||
body: request.body,
|
|
||||||
query: request.query,
|
|
||||||
params: request.params,
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.debug(`Handling incoming webhook request at ${request.originalUrl}.`);
|
|
||||||
logger.debug(JSON.stringify(computedRequestPayload, null, 2));
|
|
||||||
|
|
||||||
const flowId = request.params.flowId;
|
|
||||||
const flow = await Flow.query().findById(flowId).throwIfNotFound();
|
|
||||||
const triggerStep = await flow.getTriggerStep();
|
|
||||||
|
|
||||||
if (triggerStep.appKey !== 'webhook') {
|
|
||||||
const connection = await triggerStep.$relatedQuery('connection');
|
|
||||||
|
|
||||||
if (!(await connection.verifyWebhook(request))) {
|
|
||||||
return response.sendStatus(401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await handlerSync(flowId, request, response);
|
|
||||||
};
|
|
@@ -1,16 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
return knex.schema.createTable('datastore', (table) => {
|
|
||||||
table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()'));
|
|
||||||
table.string('key').notNullable();
|
|
||||||
table.string('value');
|
|
||||||
table.string('scope').notNullable();
|
|
||||||
table.uuid('scope_id').notNullable();
|
|
||||||
table.index(['key', 'scope', 'scope_id']);
|
|
||||||
|
|
||||||
table.timestamps(true, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex) {
|
|
||||||
return knex.schema.dropTable('datastore');
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.string('app_key');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.dropColumn('app_key');
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
const appAuthClients = await knex('app_auth_clients').select('*');
|
|
||||||
|
|
||||||
for (const appAuthClient of appAuthClients) {
|
|
||||||
const appConfig = await knex('app_configs')
|
|
||||||
.where('id', appAuthClient.app_config_id)
|
|
||||||
.first();
|
|
||||||
|
|
||||||
await knex('app_auth_clients')
|
|
||||||
.where('id', appAuthClient.id)
|
|
||||||
.update({ app_key: appConfig.key });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down() {
|
|
||||||
// void
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.dropColumn('app_config_id');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.uuid('app_config_id').references('id').inTable('app_configs');
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.string('app_key').notNullable().alter();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex) {
|
|
||||||
await knex.schema.table('app_auth_clients', (table) => {
|
|
||||||
table.string('app_key').nullable().alter();
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
import Step from '../../models/step.js';
|
import Step from '../../models/flow.js';
|
||||||
|
|
||||||
const deleteStep = async (_parent, params, context) => {
|
const deleteStep = async (_parent, params, context) => {
|
||||||
const conditions = context.currentUser.can('update', 'Flow');
|
const conditions = context.currentUser.can('update', 'Flow');
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
import AppAuthClient from '../../models/app-auth-client.js';
|
||||||
|
|
||||||
|
const getAppAuthClient = async (_parent, params, context) => {
|
||||||
|
let canSeeAllClients = false;
|
||||||
|
try {
|
||||||
|
context.currentUser.can('read', 'App');
|
||||||
|
|
||||||
|
canSeeAllClients = true;
|
||||||
|
} catch {
|
||||||
|
// void
|
||||||
|
}
|
||||||
|
|
||||||
|
const appAuthClient = AppAuthClient.query()
|
||||||
|
.findById(params.id)
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
if (!canSeeAllClients) {
|
||||||
|
appAuthClient.where({ active: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return await appAuthClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getAppAuthClient;
|
@@ -0,0 +1,33 @@
|
|||||||
|
import AppConfig from '../../models/app-config.js';
|
||||||
|
|
||||||
|
const getAppAuthClients = async (_parent, params, context) => {
|
||||||
|
let canSeeAllClients = false;
|
||||||
|
try {
|
||||||
|
context.currentUser.can('read', 'App');
|
||||||
|
|
||||||
|
canSeeAllClients = true;
|
||||||
|
} catch {
|
||||||
|
// void
|
||||||
|
}
|
||||||
|
|
||||||
|
const appConfig = await AppConfig.query()
|
||||||
|
.findOne({
|
||||||
|
key: params.appKey,
|
||||||
|
})
|
||||||
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
const appAuthClients = appConfig
|
||||||
|
.$relatedQuery('appAuthClients')
|
||||||
|
.where({ active: params.active })
|
||||||
|
.skipUndefined();
|
||||||
|
|
||||||
|
if (!canSeeAllClients) {
|
||||||
|
appAuthClients.where({
|
||||||
|
active: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return await appAuthClients;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getAppAuthClients;
|
17
packages/backend/src/graphql/queries/get-app-config.ee.js
Normal file
17
packages/backend/src/graphql/queries/get-app-config.ee.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import AppConfig from '../../models/app-config.js';
|
||||||
|
|
||||||
|
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;
|
41
packages/backend/src/graphql/queries/get-app.js
Normal file
41
packages/backend/src/graphql/queries/get-app.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import App from '../../models/app.js';
|
||||||
|
import Connection from '../../models/connection.js';
|
||||||
|
|
||||||
|
const getApp = async (_parent, params, 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 app = await App.findOneByKey(params.key);
|
||||||
|
|
||||||
|
if (context.currentUser) {
|
||||||
|
const connections = await connectionBaseQuery
|
||||||
|
.clone()
|
||||||
|
.select('connections.*')
|
||||||
|
.withGraphFetched({
|
||||||
|
appConfig: true,
|
||||||
|
appAuthClient: true,
|
||||||
|
})
|
||||||
|
.fullOuterJoinRelated('steps')
|
||||||
|
.where({
|
||||||
|
'connections.key': params.key,
|
||||||
|
'connections.draft': false,
|
||||||
|
})
|
||||||
|
.countDistinct('steps.flow_id as flowCount')
|
||||||
|
.groupBy('connections.id')
|
||||||
|
.orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
return {
|
||||||
|
...app,
|
||||||
|
connections,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return app;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getApp;
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user