Compare commits

..

2 Commits

Author SHA1 Message Date
Rıdvan Akca
8a8be21d56 test: make better stack first when creating a connection 2024-01-16 12:37:06 +03:00
Rıdvan Akca
e5c4e18fd5 feat(better-stack): add better stack integration 2024-01-16 12:37:06 +03:00
170 changed files with 537 additions and 3373 deletions

View File

@@ -8,7 +8,7 @@
"version": "latest" "version": "latest"
}, },
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": 18 "version": 16
}, },
"ghcr.io/devcontainers/features/common-utils:1": { "ghcr.io/devcontainers/features/common-utils:1": {
"username": "vscode", "username": "vscode",

View File

@@ -6,7 +6,7 @@ ENV PORT 3000
RUN \ RUN \
apk --no-cache add --virtual build-dependencies python3 build-base git apk --no-cache add --virtual build-dependencies python3 build-base git
RUN git clone -b helix-new-endpoint https://github.com/automatisch/automatisch.git RUN git clone https://github.com/automatisch/automatisch.git
WORKDIR /automatisch WORKDIR /automatisch

View File

@@ -33,18 +33,19 @@
"axios": "1.6.0", "axios": "1.6.0",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bullmq": "^3.0.0", "bullmq": "^3.0.0",
"copyfiles": "^2.4.1",
"cors": "^2.8.5", "cors": "^2.8.5",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"debug": "~2.6.9", "debug": "~2.6.9",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "~4.18.2", "express": "~4.18.2",
"express-async-handler": "^1.2.0",
"express-basic-auth": "^1.2.1", "express-basic-auth": "^1.2.1",
"express-graphql": "^0.12.0", "express-graphql": "^0.12.0",
"fast-xml-parser": "^4.0.11", "fast-xml-parser": "^4.0.11",
"graphql-middleware": "^6.1.15", "graphql-middleware": "^6.1.15",
"graphql-shield": "^7.5.0", "graphql-shield": "^7.5.0",
"graphql-tools": "^8.2.0", "graphql-tools": "^8.2.0",
"graphql-type-json": "^0.3.2",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"http-errors": "~1.6.3", "http-errors": "~1.6.3",
"http-proxy-agent": "^7.0.0", "http-proxy-agent": "^7.0.0",
@@ -67,6 +68,7 @@
"pluralize": "^8.0.0", "pluralize": "^8.0.0",
"raw-body": "^2.5.2", "raw-body": "^2.5.2",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"stripe": "^11.13.0",
"winston": "^3.7.1", "winston": "^3.7.1",
"xmlrpc": "^1.3.2" "xmlrpc": "^1.3.2"
}, },
@@ -95,7 +97,6 @@
"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"

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
fill="#000" stroke="none">
<path d="M0 1000 l0 -1000 1000 0 1000 0 0 1000 0 1000 -1000 0 -1000 0 0
-1000z m1162 460 c14 -11 113 -184 232 -408 228 -429 231 -439 175 -486 -35
-30 -30 -29 -140 -15 -89 12 -123 25 -152 56 -9 11 -72 147 -140 304 -113 263
-124 284 -149 287 -14 2 -29 10 -32 17 -8 21 67 214 94 242 28 29 78 30 112 3z
m-340 -148 c10 -10 72 -175 139 -367 114 -325 121 -351 108 -374 -8 -14 -27
-32 -41 -41 -25 -13 -34 -12 -126 18 -55 18 -111 43 -125 56 -19 17 -40 67
-76 182 -36 112 -58 164 -73 176 l-22 16 27 99 c63 224 66 232 95 248 31 17
69 12 94 -13z m-314 -219 c16 -15 26 -59 56 -243 42 -262 43 -285 17 -300 -11
-5 -24 -10 -30 -10 -19 0 -140 114 -150 141 -7 20 -4 76 10 191 10 90 19 171
19 181 0 18 33 57 49 57 5 0 18 -8 29 -17z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,33 @@
import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js';
export default {
fields: [
{
key: 'screenName',
label: 'Screen Name',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description:
'Screen name of your connection to be used on Automatisch UI.',
clickToCopy: false,
},
{
key: 'apiKey',
label: 'API Key',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'Better Stack API key of your account.',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -0,0 +1,8 @@
import verifyCredentials from './verify-credentials.js';
const isStillVerified = async ($) => {
await verifyCredentials($);
return true;
};
export default isStillVerified;

View File

@@ -0,0 +1,10 @@
const verifyCredentials = async ($) => {
await $.http.get('/v2/metadata');
await $.auth.set({
screenName: $.auth.data.screenName,
apiKey: $.auth.data.apiKey,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,9 @@
const addAuthHeader = ($, requestConfig) => {
if ($.auth.data?.apiKey) {
requestConfig.headers.Authorization = `Bearer ${$.auth.data.apiKey}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,16 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
export default defineApp({
name: 'Better Stack',
key: 'better-stack',
iconUrl: '{BASE_URL}/apps/better-stack/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/better-stack/connection',
supportsConnections: true,
baseUrl: 'https://betterstack.com',
apiBaseUrl: 'https://uptime.betterstack.com/api',
primaryColor: '000000',
beforeRequest: [addAuthHeader],
auth,
});

View File

@@ -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,
});
},
});

View File

@@ -1,4 +0,0 @@
import getValue from './get-value/index.js';
import setValue from './set-value/index.js';
export default [getValue, setValue];

View File

@@ -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,
});
},
});

View File

@@ -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="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/>
</svg>

Before

Width:  |  Height:  |  Size: 704 B

View File

@@ -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,
});

View File

@@ -1,6 +1,5 @@
import defineAction from '../../../../helpers/define-action.js'; import defineAction from '../../../../helpers/define-action.js';
import base64ToString from './transformers/base64-to-string.js';
import capitalize from './transformers/capitalize.js'; import capitalize from './transformers/capitalize.js';
import extractEmailAddress from './transformers/extract-email-address.js'; import extractEmailAddress from './transformers/extract-email-address.js';
import extractNumber from './transformers/extract-number.js'; import extractNumber from './transformers/extract-number.js';
@@ -9,12 +8,10 @@ import lowercase from './transformers/lowercase.js';
import markdownToHtml from './transformers/markdown-to-html.js'; import markdownToHtml from './transformers/markdown-to-html.js';
import pluralize from './transformers/pluralize.js'; import pluralize from './transformers/pluralize.js';
import replace from './transformers/replace.js'; import replace from './transformers/replace.js';
import stringToBase64 from './transformers/string-to-base64.js';
import trimWhitespace from './transformers/trim-whitespace.js'; import trimWhitespace from './transformers/trim-whitespace.js';
import useDefaultValue from './transformers/use-default-value.js'; import useDefaultValue from './transformers/use-default-value.js';
const transformers = { const transformers = {
base64ToString,
capitalize, capitalize,
extractEmailAddress, extractEmailAddress,
extractNumber, extractNumber,
@@ -23,7 +20,6 @@ const transformers = {
markdownToHtml, markdownToHtml,
pluralize, pluralize,
replace, replace,
stringToBase64,
trimWhitespace, trimWhitespace,
useDefaultValue, useDefaultValue,
}; };
@@ -41,7 +37,6 @@ export default defineAction({
required: true, required: true,
variables: true, variables: true,
options: [ options: [
{ label: 'Base64 to String', value: 'base64ToString' },
{ label: 'Capitalize', value: 'capitalize' }, { label: 'Capitalize', value: 'capitalize' },
{ label: 'Convert HTML to Markdown', value: 'htmlToMarkdown' }, { label: 'Convert HTML to Markdown', value: 'htmlToMarkdown' },
{ label: 'Convert Markdown to HTML', value: 'markdownToHtml' }, { label: 'Convert Markdown to HTML', value: 'markdownToHtml' },
@@ -50,7 +45,6 @@ export default defineAction({
{ label: 'Lowercase', value: 'lowercase' }, { label: 'Lowercase', value: 'lowercase' },
{ label: 'Pluralize', value: 'pluralize' }, { label: 'Pluralize', value: 'pluralize' },
{ label: 'Replace', value: 'replace' }, { label: 'Replace', value: 'replace' },
{ label: 'String to Base64', value: 'stringToBase64' },
{ label: 'Trim Whitespace', value: 'trimWhitespace' }, { label: 'Trim Whitespace', value: 'trimWhitespace' },
{ label: 'Use Default Value', value: 'useDefaultValue' }, { label: 'Use Default Value', value: 'useDefaultValue' },
], ],

View File

@@ -1,8 +0,0 @@
const base64ToString = ($) => {
const input = $.step.parameters.input;
const decodedString = Buffer.from(input, 'base64').toString('utf8');
return decodedString;
};
export default base64ToString;

View File

@@ -1,8 +0,0 @@
const stringtoBase64 = ($) => {
const input = $.step.parameters.input;
const base64String = Buffer.from(input).toString('base64');
return base64String;
};
export default stringtoBase64;

View File

@@ -1,4 +1,3 @@
import base64ToString from './text/base64-to-string.js';
import capitalize from './text/capitalize.js'; import capitalize from './text/capitalize.js';
import extractEmailAddress from './text/extract-email-address.js'; import extractEmailAddress from './text/extract-email-address.js';
import extractNumber from './text/extract-number.js'; import extractNumber from './text/extract-number.js';
@@ -7,7 +6,6 @@ import lowercase from './text/lowercase.js';
import markdownToHtml from './text/markdown-to-html.js'; import markdownToHtml from './text/markdown-to-html.js';
import pluralize from './text/pluralize.js'; import pluralize from './text/pluralize.js';
import replace from './text/replace.js'; import replace from './text/replace.js';
import stringToBase64 from './text/string-to-base64.js';
import trimWhitespace from './text/trim-whitespace.js'; import trimWhitespace from './text/trim-whitespace.js';
import useDefaultValue from './text/use-default-value.js'; import useDefaultValue from './text/use-default-value.js';
import performMathOperation from './numbers/perform-math-operation.js'; import performMathOperation from './numbers/perform-math-operation.js';
@@ -17,7 +15,6 @@ import formatPhoneNumber from './numbers/format-phone-number.js';
import formatDateTime from './date-time/format-date-time.js'; import formatDateTime from './date-time/format-date-time.js';
const options = { const options = {
base64ToString,
capitalize, capitalize,
extractEmailAddress, extractEmailAddress,
extractNumber, extractNumber,
@@ -26,7 +23,6 @@ const options = {
markdownToHtml, markdownToHtml,
pluralize, pluralize,
replace, replace,
stringToBase64,
trimWhitespace, trimWhitespace,
useDefaultValue, useDefaultValue,
performMathOperation, performMathOperation,

View File

@@ -1,12 +0,0 @@
const base64ToString = [
{
label: 'Input',
key: 'input',
type: 'string',
required: true,
description: 'Text that will be converted from Base64 to string.',
variables: true,
},
];
export default base64ToString;

View File

@@ -1,12 +0,0 @@
const stringToBase64 = [
{
label: 'Input',
key: 'input',
type: 'string',
required: true,
description: 'Text that will be converted to Base64.',
variables: true,
},
];
export default stringToBase64;

View File

@@ -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({
@@ -16,21 +17,34 @@ export default defineAction({
], ],
async run($) { async run($) {
const response = await $.http.post('/api/v1/sessions/chat', { const formData = new FormData();
session_id: '', formData.append('input', $.step.parameters.input);
messages: [ formData.append('mode', 'inference');
{ formData.append('type', 'text');
role: 'user',
content: { const sessionResponse = await $.http.post('/api/v1/sessions', formData, {
content_type: 'text', headers: {
parts: [$.step.parameters.input], ...formData.getHeaders(),
}, },
},
],
}); });
const sessionId = sessionResponse.data.id;
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({ $.setActionItem({
raw: response.data, raw: message,
}); });
chatGenerated = true;
}
}
}, },
}); });

View File

@@ -18,9 +18,7 @@ const port = process.env.PORT || '3000';
const serveWebAppSeparately = const serveWebAppSeparately =
process.env.SERVE_WEB_APP_SEPARATELY === 'true' ? true : false; process.env.SERVE_WEB_APP_SEPARATELY === 'true' ? true : false;
let apiUrl = new URL( let apiUrl = new URL(`${protocol}://${host}:${port}`).toString();
process.env.API_URL || `${protocol}://${host}:${port}`
).toString();
apiUrl = apiUrl.substring(0, apiUrl.length - 1); apiUrl = apiUrl.substring(0, apiUrl.length - 1);
// use apiUrl by default, which has less priority over the following cases // use apiUrl by default, which has less priority over the following cases
@@ -90,10 +88,6 @@ const appConfig = {
licenseKey: process.env.LICENSE_KEY, licenseKey: process.env.LICENSE_KEY,
sentryDsn: process.env.SENTRY_DSN, sentryDsn: process.env.SENTRY_DSN,
CI: process.env.CI === 'true', CI: process.env.CI === 'true',
disableNotificationsPage: process.env.DISABLE_NOTIFICATIONS_PAGE === 'true',
disableFavicon: process.env.DISABLE_FAVICON === 'true',
additionalDrawerLink: process.env.ADDITIONAL_DRAWER_LINK,
additionalDrawerLinkText: process.env.ADDITIONAL_DRAWER_LINK_TEXT,
}; };
if (!appConfig.encryptionKey) { if (!appConfig.encryptionKey) {

View File

@@ -1,10 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import AppAuthClient from '../../../../../models/app-auth-client.js';
export default async (request, response) => {
const appAuthClient = await AppAuthClient.query()
.findById(request.params.appAuthClientId)
.throwIfNotFound();
renderObject(response, appAuthClient);
};

View File

@@ -1,52 +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 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);
});
});
});

View File

@@ -1,6 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import permissionCatalog from '../../../../../helpers/permission-catalog.ee.js';
export default async (request, response) => {
renderObject(response, permissionCatalog);
};

View File

@@ -1,32 +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 getPermissionsCatalogMock from '../../../../../../test/mocks/rest/api/v1/admin/permissions/get-permissions-catalog.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/permissions/catalog', () => {
let role, currentUser, token;
beforeEach(async () => {
role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
token = createAuthTokenByUserId(currentUser.id);
});
it('should return roles', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/permissions/catalog')
.set('Authorization', token)
.expect(200);
const expectedPayload = await getPermissionsCatalogMock();
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,16 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import Role from '../../../../../models/role.js';
export default async (request, response) => {
const role = await Role.query()
.leftJoinRelated({
permissions: true,
})
.withGraphFetched({
permissions: true,
})
.findById(request.params.roleId)
.throwIfNotFound();
renderObject(response, role);
};

View File

@@ -1,59 +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 { createRole } from '../../../../../../test/factories/role.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createPermission } from '../../../../../../test/factories/permission.js';
import getRoleMock from '../../../../../../test/mocks/rest/api/v1/admin/roles/get-role.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/roles/:roleId', () => {
let role, currentUser, token, permissionOne, permissionTwo;
beforeEach(async () => {
role = await createRole({ key: 'admin' });
permissionOne = await createPermission({ roleId: role.id });
permissionTwo = await createPermission({ roleId: role.id });
currentUser = await createUser({ roleId: role.id });
token = createAuthTokenByUserId(currentUser.id);
});
it('should return role', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get(`/api/v1/admin/roles/${role.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = await getRoleMock(role, [
permissionOne,
permissionTwo,
]);
expect(response.body).toEqual(expectedPayload);
});
it('should return not found response for not existing role UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const notExistingRoleUUID = Crypto.randomUUID();
await request(app)
.get(`/api/v1/admin/roles/${notExistingRoleUUID}`)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
await request(app)
.get('/api/v1/admin/roles/invalidRoleUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,8 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import Role from '../../../../../models/role.js';
export default async (request, response) => {
const roles = await Role.query().orderBy('name');
renderObject(response, roles);
};

View File

@@ -1,33 +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 getRolesMock from '../../../../../../test/mocks/rest/api/v1/admin/roles/get-roles.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/roles', () => {
let roleOne, roleTwo, currentUser, token;
beforeEach(async () => {
roleOne = await createRole({ key: 'admin' });
roleTwo = await createRole({ key: 'user' });
currentUser = await createUser({ roleId: roleOne.id });
token = createAuthTokenByUserId(currentUser.id);
});
it('should return roles', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/roles')
.set('Authorization', token)
.expect(200);
const expectedPayload = await getRolesMock([roleOne, roleTwo]);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,10 +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();
renderObject(response, samlAuthProvider);
};

View File

@@ -1,57 +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 { createRole } from '../../../../../../test/factories/role.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
import getSamlAuthProviderMock from '../../../../../../test/mocks/rest/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/saml-auth-provider/:samlAuthProviderId', () => {
let samlAuthProvider, currentUser, token;
beforeEach(async () => {
const role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
samlAuthProvider = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth provider with specified id', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get(`/api/v1/admin/saml-auth-providers/${samlAuthProvider.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = await getSamlAuthProviderMock(samlAuthProvider);
expect(response.body).toEqual(expectedPayload);
});
it('should return not found response for not existing saml auth provider UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const notExistingSamlAuthProviderUUID = Crypto.randomUUID();
await request(app)
.get(
`/api/v1/admin/saml-auth-providers/${notExistingSamlAuthProviderUUID}`
)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
await request(app)
.get('/api/v1/admin/saml-auth-providers/invalidSamlAuthProviderUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,11 +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().orderBy(
'created_at',
'desc'
);
renderObject(response, samlAuthProviders);
};

View File

@@ -1,39 +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 getSamlAuthProvidersMock from '../../../../../../test/mocks/rest/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/saml-auth-providers', () => {
let samlAuthProviderOne, samlAuthProviderTwo, currentUser, token;
beforeEach(async () => {
const role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
samlAuthProviderOne = await createSamlAuthProvider();
samlAuthProviderTwo = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth providers', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/saml-auth-providers')
.set('Authorization', token)
.expect(200);
const expectedPayload = await getSamlAuthProvidersMock([
samlAuthProviderTwo,
samlAuthProviderOne,
]);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,13 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import User from '../../../../../models/user.js';
export default async (request, response) => {
const user = await User.query()
.withGraphFetched({
role: true,
})
.findById(request.params.userId)
.throwIfNotFound();
renderObject(response, user);
};

View File

@@ -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';
import { createUser } from '../../../../../../test/factories/user';
import { createRole } from '../../../../../../test/factories/role';
import getUserMock from '../../../../../../test/mocks/rest/api/v1/admin/users/get-user.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/users/:userId', () => {
let currentUser, currentUserRole, anotherUser, anotherUserRole, token;
beforeEach(async () => {
currentUserRole = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: currentUserRole.id });
anotherUser = await createUser();
anotherUserRole = await anotherUser.$relatedQuery('role');
token = createAuthTokenByUserId(currentUser.id);
});
it('should return specified user info', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get(`/api/v1/admin/users/${anotherUser.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = getUserMock(anotherUser, anotherUserRole);
expect(response.body).toEqual(expectedPayload);
});
it('should return not found response for not existing user UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const notExistingUserUUID = Crypto.randomUUID();
await request(app)
.get(`/api/v1/admin/users/${notExistingUserUUID}`)
.set('Authorization', token)
.expect(404);
});
it('should return bad request response for invalid UUID', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
await request(app)
.get('/api/v1/admin/users/invalidUserUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,15 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import User from '../../../../../models/user.js';
import paginateRest from '../../../../../helpers/pagination-rest.js';
export default async (request, response) => {
const usersQuery = User.query()
.withGraphFetched({
role: true,
})
.orderBy('full_name', 'asc');
const users = await paginateRest(usersQuery, request.query.page);
renderObject(response, users);
};

View File

@@ -1,49 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id';
import { createRole } from '../../../../../../test/factories/role';
import { createUser } from '../../../../../../test/factories/user';
import getUsersMock from '../../../../../../test/mocks/rest/api/v1/admin/users/get-users.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/users', () => {
let currentUser, currentUserRole, anotherUser, anotherUserRole, token;
beforeEach(async () => {
currentUserRole = await createRole({ key: 'admin' });
currentUser = await createUser({
roleId: currentUserRole.id,
fullName: 'Current User',
});
anotherUserRole = await createRole({
key: 'anotherUser',
name: 'Another user role',
});
anotherUser = await createUser({
roleId: anotherUserRole.id,
fullName: 'Another User',
});
token = createAuthTokenByUserId(currentUser.id);
});
it('should return users data', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/users')
.set('Authorization', token)
.expect(200);
const expectedResponsePayload = await getUsersMock(
[anotherUser, currentUser],
[anotherUserRole, currentUserRole]
);
expect(response.body).toEqual(expectedResponsePayload);
});
});

View File

@@ -1,11 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
import AppAuthClient from '../../../../models/app-auth-client.js';
export default async (request, response) => {
const appAuthClient = await AppAuthClient.query()
.findById(request.params.appAuthClientId)
.where({ active: true })
.throwIfNotFound();
renderObject(response, appAuthClient);
};

View File

@@ -1,48 +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 getAppAuthClientMock from '../../../../../test/mocks/rest/api/v1/admin/get-app-auth-client.js';
import { createAppAuthClient } from '../../../../../test/factories/app-auth-client.js';
import * as license from '../../../../helpers/license.ee.js';
describe('GET /api/v1/app-auth-clients/:id', () => {
let currentUser, currentAppAuthClient, token;
beforeEach(async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
currentUser = await createUser();
currentAppAuthClient = await createAppAuthClient();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return specified app auth client info', async () => {
const response = await request(app)
.get(`/api/v1/app-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/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/app-auth-clients/invalidAppAuthClientUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,8 +0,0 @@
import App from '../../../../models/app.js';
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const app = await App.findOneByKey(request.params.appKey);
renderObject(response, app, { serializer: 'App' });
};

View File

@@ -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 getAppMock from '../../../../../test/mocks/rest/api/v1/apps/get-app.js';
describe('GET /api/v1/apps/:appKey', () => {
let currentUser, token;
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return the app info', async () => {
const exampleApp = await App.findOneByKey('github');
const response = await request(app)
.get(`/api/v1/apps/${exampleApp.key}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = getAppMock(exampleApp);
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')
.set('Authorization', token)
.expect(404);
});
});

View File

@@ -1,13 +0,0 @@
import appConfig from '../../../../config/app.js';
import { hasValidLicense } from '../../../../helpers/license.ee.js';
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const info = {
isCloud: appConfig.isCloud,
isMation: appConfig.isMation,
isEnterprise: await hasValidLicense(),
};
renderObject(response, info);
};

View File

@@ -1,22 +0,0 @@
import { vi, expect, describe, it } from 'vitest';
import request from 'supertest';
import appConfig from '../../../../config/app.js';
import app from '../../../../app.js';
import infoMock from '../../../../../test/mocks/rest/api/v1/automatisch/info.js';
import * as license from '../../../../helpers/license.ee.js';
describe('GET /api/v1/automatisch/info', () => {
it('should return Automatisch info', async () => {
vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(false);
vi.spyOn(appConfig, 'isMation', 'get').mockReturnValue(false);
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/automatisch/info')
.expect(200);
const expectedPayload = infoMock();
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,15 +0,0 @@
import { getLicense } from '../../../../helpers/license.ee.js';
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const license = await getLicense();
const computedLicense = {
id: license ? license.id : null,
name: license ? license.name : null,
expireAt: license ? license.expireAt : null,
verified: license ? true : false,
};
renderObject(response, computedLicense);
};

View File

@@ -1,23 +0,0 @@
import { vi, expect, describe, it } from 'vitest';
import request from 'supertest';
import app from '../../../../app.js';
import licenseMock from '../../../../../test/mocks/rest/api/v1/automatisch/license.js';
import * as license from '../../../../helpers/license.ee.js';
describe('GET /api/v1/automatisch/license', () => {
it('should return Automatisch license info', async () => {
vi.spyOn(license, 'getLicense').mockResolvedValue({
id: '123',
name: 'license-name',
expireAt: '2025-12-31T23:59:59Z',
});
const response = await request(app)
.get('/api/v1/automatisch/license')
.expect(200);
const expectedPayload = licenseMock();
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,19 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
import axios from '../../../../helpers/axios-with-proxy.js';
import logger from '../../../../helpers/logger.js';
const NOTIFICATIONS_URL =
'https://notifications.automatisch.io/notifications.json';
export default async (request, response) => {
let notifications = [];
try {
const response = await axios.get(NOTIFICATIONS_URL);
notifications = response.data;
} catch (error) {
logger.error('Error fetching notifications API endpoint!', error);
}
renderObject(response, notifications);
};

View File

@@ -1,9 +0,0 @@
import { describe, it } from 'vitest';
import request from 'supertest';
import app from '../../../../app.js';
describe('GET /api/v1/automatisch/notifications', () => {
it('should return Automatisch notifications', async () => {
await request(app).get('/api/v1/automatisch/notifications').expect(200);
});
});

View File

@@ -1,6 +0,0 @@
import appConfig from '../../../../config/app.js';
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
renderObject(response, { version: appConfig.version });
};

View File

@@ -1,26 +0,0 @@
import { describe, it, expect } from 'vitest';
import request from 'supertest';
import app from '../../../../app.js';
describe('GET /api/v1/automatisch/version', () => {
it('should return Automatisch version', async () => {
const response = await request(app)
.get('/api/v1/automatisch/version')
.expect(200);
const expectedPayload = {
data: {
version: '0.10.0',
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'Object',
},
};
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,11 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const flow = await request.currentUser.authorizedFlows
.withGraphJoined({ steps: true })
.orderBy('steps.position', 'asc')
.findOne({ 'flows.id': request.params.flowId })
.throwIfNotFound();
renderObject(response, flow);
};

View File

@@ -1,102 +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 getFlowMock from '../../../../../test/mocks/rest/api/v1/flows/get-flow';
describe('GET /api/v1/flows/:flowId', () => {
let currentUser, currentUserRole, token;
beforeEach(async () => {
currentUser = await createUser();
currentUserRole = await currentUser.$relatedQuery('role');
token = createAuthTokenByUserId(currentUser.id);
});
it('should return the flow data of current user', async () => {
const currentUserflow = await createFlow({ userId: currentUser.id });
const triggerStep = await createStep({ flowId: currentUserflow.id });
const actionStep = await createStep({ flowId: currentUserflow.id });
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: ['isCreator'],
});
const response = await request(app)
.get(`/api/v1/flows/${currentUserflow.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = await getFlowMock(currentUserflow, [
triggerStep,
actionStep,
]);
expect(response.body).toEqual(expectedPayload);
});
it('should return the flow data of another user', async () => {
const anotherUser = await createUser();
const anotherUserFlow = await createFlow({ userId: anotherUser.id });
const triggerStep = await createStep({ flowId: anotherUserFlow.id });
const actionStep = await createStep({ flowId: anotherUserFlow.id });
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
const response = await request(app)
.get(`/api/v1/flows/${anotherUserFlow.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = await getFlowMock(anotherUserFlow, [
triggerStep,
actionStep,
]);
expect(response.body).toEqual(expectedPayload);
});
it('should return not found response for not existing flow UUID', async () => {
await createPermission({
action: 'read',
subject: 'Flow',
roleId: currentUserRole.id,
conditions: [],
});
const notExistingFlowUUID = Crypto.randomUUID();
await request(app)
.get(`/api/v1/flows/${notExistingFlowUUID}`)
.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/flows/invalidFlowUUID')
.set('Authorization', token)
.expect(400);
});
});

View File

@@ -1,8 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
import Billing from '../../../../helpers/billing/index.ee.js';
export default async (request, response) => {
const paddleInfo = Billing.paddleInfo;
renderObject(response, paddleInfo);
};

View File

@@ -1,33 +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 getPaddleInfoMock from '../../../../../test/mocks/rest/api/v1/payment/get-paddle-info.js';
import appConfig from '../../../../config/app.js';
import billing from '../../../../helpers/billing/index.ee.js';
describe('GET /api/v1/payment/paddle-info', () => {
let user, token;
beforeEach(async () => {
user = await createUser();
token = createAuthTokenByUserId(user.id);
vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true);
vi.spyOn(billing.paddleInfo, 'vendorId', 'get').mockReturnValue(
'sampleVendorId'
);
});
it('should return payment plans', async () => {
const response = await request(app)
.get('/api/v1/payment/paddle-info')
.set('Authorization', token)
.expect(200);
const expectedResponsePayload = await getPaddleInfoMock();
expect(response.body).toEqual(expectedResponsePayload);
});
});

View File

@@ -1,8 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
import Billing from '../../../../helpers/billing/index.ee.js';
export default async (request, response) => {
const paymentPlans = Billing.paddlePlans;
renderObject(response, paymentPlans);
};

View File

@@ -1,29 +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 getPaymentPlansMock from '../../../../../test/mocks/rest/api/v1/payment/get-plans.js';
import appConfig from '../../../../config/app.js';
describe('GET /api/v1/payment/plans', () => {
let user, token;
beforeEach(async () => {
user = await createUser();
token = createAuthTokenByUserId(user.id);
vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true);
});
it('should return payment plans', async () => {
const response = await request(app)
.get('/api/v1/payment/plans')
.set('Authorization', token)
.expect(200);
const expectedResponsePayload = await getPaymentPlansMock();
expect(response.body).toEqual(expectedResponsePayload);
});
});

View File

@@ -1,5 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
renderObject(response, request.currentUser);
};

View File

@@ -1,26 +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 getCurrentUserMock from '../../../../../test/mocks/rest/api/v1/users/get-current-user';
describe('GET /api/v1/users/me', () => {
let role, currentUser, token;
beforeEach(async () => {
currentUser = await createUser();
role = await currentUser.$relatedQuery('role');
token = createAuthTokenByUserId(currentUser.id);
});
it('should return current user info', async () => {
const response = await request(app)
.get('/api/v1/users/me')
.set('Authorization', token)
.expect(200);
const expectedPayload = getCurrentUserMock(currentUser, role);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,7 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const invoices = await request.currentUser.getInvoices();
renderObject(response, invoices);
};

View File

@@ -1,34 +0,0 @@
import { describe, it, expect, beforeEach, vi } 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 User from '../../../../models/user';
import getInvoicesMock from '../../../../../test/mocks/rest/api/v1/users/get-invoices.ee';
describe('GET /api/v1/user/invoices', () => {
let currentUser, token;
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return current user invoices', async () => {
const invoices = [
{ id: 1, amount: 100, description: 'Invoice 1' },
{ id: 2, amount: 200, description: 'Invoice 2' },
];
vi.spyOn(User.prototype, 'getInvoices').mockResolvedValue(invoices);
const response = await request(app)
.get('/api/v1/users/invoices')
.set('Authorization', token)
.expect(200);
const expectedPayload = await getInvoicesMock(invoices);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,12 +0,0 @@
import { renderObject } from '../../../../helpers/renderer.js';
export default async (request, response) => {
const inTrial = await request.currentUser.inTrial();
const trialInfo = {
inTrial,
expireAt: request.currentUser.trialExpiryDate,
};
renderObject(response, trialInfo);
};

View File

@@ -1,38 +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 getUserTrialMock from '../../../../../test/mocks/rest/api/v1/users/get-user-trial.js';
import appConfig from '../../../../config/app.js';
import { DateTime } from 'luxon';
import User from '../../../../models/user.js';
describe('GET /api/v1/users/:userId/trial', () => {
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);
});
describe('should return in trial, active subscription and expire at info', () => {
beforeEach(async () => {
vi.spyOn(User.prototype, 'inTrial').mockResolvedValue(false);
vi.spyOn(User.prototype, 'hasActiveSubscription').mockResolvedValue(true);
});
it('should return null', async () => {
const response = await request(app)
.get(`/api/v1/users/${user.id}/trial`)
.set('Authorization', token)
.expect(200);
const expectedResponsePayload = await getUserTrialMock(user);
expect(response.body).toEqual(expectedResponsePayload);
});
});
});

View File

@@ -1,3 +0,0 @@
export default async (request, response) => {
response.status(200).end();
};

View File

@@ -1,9 +0,0 @@
import { describe, it } from 'vitest';
import request from 'supertest';
import app from '../../app.js';
describe('GET /healthcheck', () => {
it('should return 200 response with version data', async () => {
await request(app).get('/healthcheck').expect(200);
});
});

View File

@@ -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');
}

View File

@@ -1,13 +1,8 @@
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'); context.currentUser.can('update', 'Flow');
const isCreator = conditions.isCreator;
const allSteps = Step.query();
const userSteps = context.currentUser.$relatedQuery('steps');
const baseQuery = isCreator ? userSteps : allSteps;
const step = await baseQuery const step = await context.currentUser
.$relatedQuery('steps')
.withGraphFetched('flow') .withGraphFetched('flow')
.findOne({ .findOne({
'steps.id': params.input.id, 'steps.id': params.input.id,

View File

@@ -1,10 +1,7 @@
import appConfig from '../../config/app.js';
import User from '../../models/user.js'; import User from '../../models/user.js';
import Role from '../../models/role.js'; import Role from '../../models/role.js';
const registerUser = async (_parent, params) => { const registerUser = async (_parent, params) => {
if (!appConfig.isCloud) return;
const { fullName, email, password } = params.input; const { fullName, email, password } = params.input;
const existingUser = await User.query().findOne({ const existingUser = await User.query().findOne({

View File

@@ -1,17 +1,9 @@
import appConfig from '../../config/app.js';
import { hasValidLicense } from '../../helpers/license.ee.js'; import { hasValidLicense } from '../../helpers/license.ee.js';
import Config from '../../models/config.js'; import Config from '../../models/config.js';
const getConfig = async (_parent, params) => { const getConfig = async (_parent, params) => {
if (!(await hasValidLicense())) return {}; if (!(await hasValidLicense())) return {};
const defaultConfig = {
disableNotificationsPage: appConfig.disableNotificationsPage,
disableFavicon: appConfig.disableFavicon,
additionalDrawerLink: appConfig.additionalDrawerLink,
additionalDrawerLinkText: appConfig.additionalDrawerLinkText,
};
const configQuery = Config.query(); const configQuery = Config.query();
if (Array.isArray(params.keys)) { if (Array.isArray(params.keys)) {
@@ -26,7 +18,7 @@ const getConfig = async (_parent, params) => {
computedConfig[key] = value?.data; computedConfig[key] = value?.data;
return computedConfig; return computedConfig;
}, defaultConfig); }, {});
}; };
export default getConfig; export default getConfig;

View File

@@ -2,7 +2,6 @@ import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest'; import request from 'supertest';
import app from '../../app'; import app from '../../app';
import { createConfig } from '../../../test/factories/config'; import { createConfig } from '../../../test/factories/config';
import appConfig from '../../config/app';
import * as license from '../../helpers/license.ee'; import * as license from '../../helpers/license.ee';
describe('graphQL getConfig query', () => { describe('graphQL getConfig query', () => {
@@ -57,10 +56,6 @@ describe('graphQL getConfig query', () => {
[configOne.key]: configOne.value.data, [configOne.key]: configOne.value.data,
[configTwo.key]: configTwo.value.data, [configTwo.key]: configTwo.value.data,
[configThree.key]: configThree.value.data, [configThree.key]: configThree.value.data,
disableNotificationsPage: false,
disableFavicon: false,
additionalDrawerLink: undefined,
additionalDrawerLinkText: undefined,
}, },
}, },
}; };
@@ -87,48 +82,6 @@ describe('graphQL getConfig query', () => {
getConfig: { getConfig: {
[configOne.key]: configOne.value.data, [configOne.key]: configOne.value.data,
[configTwo.key]: configTwo.value.data, [configTwo.key]: configTwo.value.data,
disableNotificationsPage: false,
disableFavicon: false,
additionalDrawerLink: undefined,
additionalDrawerLinkText: undefined,
},
},
};
expect(response.body).toEqual(expectedResponsePayload);
});
});
describe('and with different defaults', () => {
beforeEach(async () => {
vi.spyOn(appConfig, 'disableNotificationsPage', 'get').mockReturnValue(
true
);
vi.spyOn(appConfig, 'disableFavicon', 'get').mockReturnValue(true);
vi.spyOn(appConfig, 'additionalDrawerLink', 'get').mockReturnValue(
'https://automatisch.io'
);
vi.spyOn(appConfig, 'additionalDrawerLinkText', 'get').mockReturnValue(
'Automatisch'
);
});
it('should return custom config', async () => {
const response = await request(app)
.post('/graphql')
.send({ query })
.expect(200);
const expectedResponsePayload = {
data: {
getConfig: {
[configOne.key]: configOne.value.data,
[configTwo.key]: configTwo.value.data,
[configThree.key]: configThree.value.data,
disableNotificationsPage: true,
disableFavicon: true,
additionalDrawerLink: 'https://automatisch.io',
additionalDrawerLinkText: 'Automatisch',
}, },
}, },
}; };

View File

@@ -20,8 +20,7 @@ export const isAuthenticated = async (_parent, _args, req) => {
.withGraphFetched({ .withGraphFetched({
role: true, role: true,
permissions: true, permissions: true,
}) });
.throwIfNotFound();
return true; return true;
} catch (error) { } catch (error) {
@@ -29,14 +28,6 @@ export const isAuthenticated = async (_parent, _args, req) => {
} }
}; };
export const authenticateUser = async (request, response, next) => {
if (await isAuthenticated(null, null, request)) {
next();
} else {
return response.status(401).end();
}
};
const isAuthenticatedRule = rule()(isAuthenticated); const isAuthenticatedRule = rule()(isAuthenticated);
export const authenticationRules = { export const authenticationRules = {

View File

@@ -1,8 +1,11 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect, vi } from 'vitest';
import { allow } from 'graphql-shield'; import { allow } from 'graphql-shield';
import jwt from 'jsonwebtoken';
import User from '../models/user.js';
import { isAuthenticated, authenticationRules } from './authentication.js'; import { isAuthenticated, authenticationRules } from './authentication.js';
import { createUser } from '../../test/factories/user.js';
import createAuthTokenByUserId from '../helpers/create-auth-token-by-user-id.js'; vi.mock('jsonwebtoken');
vi.mock('../models/user.js');
describe('isAuthenticated', () => { describe('isAuthenticated', () => {
it('should return false if no token is provided', async () => { it('should return false if no token is provided', async () => {
@@ -11,25 +14,28 @@ describe('isAuthenticated', () => {
}); });
it('should return false if token is invalid', async () => { it('should return false if token is invalid', async () => {
jwt.verify.mockImplementation(() => {
throw new Error('invalid token');
});
const req = { headers: { authorization: 'invalidToken' } }; const req = { headers: { authorization: 'invalidToken' } };
expect(await isAuthenticated(null, null, req)).toBe(false); expect(await isAuthenticated(null, null, req)).toBe(false);
}); });
it('should return true if token is valid and there is a user', async () => { it('should return true if token is valid', async () => {
const user = await createUser(); jwt.verify.mockReturnValue({ userId: '123' });
const token = createAuthTokenByUserId(user.id);
const req = { headers: { authorization: token } }; User.query.mockReturnValue({
expect(await isAuthenticated(null, null, req)).toBe(true); findById: vi.fn().mockReturnValue({
leftJoinRelated: vi.fn().mockReturnThis(),
withGraphFetched: vi
.fn()
.mockResolvedValue({ id: '123', role: {}, permissions: {} }),
}),
}); });
it('should return false if token is valid and but there is no user', async () => { const req = { headers: { authorization: 'validToken' } };
const user = await createUser(); expect(await isAuthenticated(null, null, req)).toBe(true);
const token = createAuthTokenByUserId(user.id);
await user.$query().delete();
const req = { headers: { authorization: token } };
expect(await isAuthenticated(null, null, req)).toBe(false);
}); });
}); });

View File

@@ -1,37 +0,0 @@
const authorizationList = {
'GET /api/v1/users/:userId': {
action: 'read',
subject: 'User',
},
'GET /api/v1/users/': {
action: 'read',
subject: 'User',
},
'GET /api/v1/flows/:flowId': {
action: 'read',
subject: 'Flow',
},
};
export const authorizeUser = async (request, response, next) => {
const currentRoute =
request.method + ' ' + request.baseUrl + request.route.path;
const currentRouteRule = authorizationList[currentRoute];
try {
request.currentUser.can(currentRouteRule.action, currentRouteRule.subject);
next();
} catch (error) {
return response.status(403).end();
}
};
export const authorizeAdmin = async (request, response, next) => {
const role = await request.currentUser.$relatedQuery('role');
if (role?.isAdmin) {
next();
} else {
return response.status(403).end();
}
};

View File

@@ -1,11 +0,0 @@
import appConfig from '../config/app.js';
export const checkIsCloud = async (request, response, next) => {
if (appConfig.isCloud) {
next();
} else {
return response.status(404).end();
}
};
export default checkIsCloud;

View File

@@ -1,9 +0,0 @@
import { hasValidLicense } from './license.ee.js';
export const checkIsEnterprise = async (request, response, next) => {
if (await hasValidLicense()) {
next();
} else {
return response.status(404).end();
}
};

View File

@@ -1,9 +1,6 @@
import path from 'path'; import * as path from 'path';
import fs from 'fs'; import * as fs from 'fs';
import handlebars from 'handlebars'; import * as handlebars from 'handlebars';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const compileEmail = (emailPath, replacements = {}) => { const compileEmail = (emailPath, replacements = {}) => {
const filePath = path.join(__dirname, `../views/emails/${emailPath}.ee.hbs`); const filePath = path.join(__dirname, `../views/emails/${emailPath}.ee.hbs`);

View File

@@ -1,31 +1,14 @@
import logger from './logger.js'; import logger from './logger.js';
import objection from 'objection';
const { NotFoundError, DataError } = objection;
// Do not remove `next` argument as the function signature will not fit for an error handler middleware // Do not remove `next` argument as the function signature will not fit for an error handler middleware
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const errorHandler = (error, request, response, next) => { const errorHandler = (err, req, res, next) => {
if (error.message === 'Not Found' || error instanceof NotFoundError) { if (err.message === 'Not Found') {
response.status(404).end(); res.status(404).end();
} else {
logger.error(err.message + '\n' + err.stack);
res.status(err.statusCode || 500).send(err.message);
} }
if (notFoundAppError(error)) {
response.status(404).end();
}
if (error instanceof DataError) {
response.status(400).end();
}
logger.error(error.message + '\n' + error.stack);
response.status(error.statusCode || 500).end();
};
const notFoundAppError = (error) => {
return (
error.message.includes('An application with the') ||
error.message.includes("key couldn't be found.")
);
}; };
export default errorHandler; export default errorHandler;

View File

@@ -1,7 +1,6 @@
import createHttpClient from './http-client/index.js'; import createHttpClient from './http-client/index.js';
import EarlyExitError from '../errors/early-exit.js'; import EarlyExitError from '../errors/early-exit.js';
import AlreadyProcessedError from '../errors/already-processed.js'; import AlreadyProcessedError from '../errors/already-processed.js';
import Datastore from '../models/datastore.js';
const globalVariable = async (options) => { const globalVariable = async (options) => {
const { const {
@@ -89,43 +88,6 @@ const globalVariable = async (options) => {
setActionItem: (actionItem) => { setActionItem: (actionItem) => {
$.actionOutput.data = actionItem; $.actionOutput.data = actionItem;
}, },
datastore: {
get: async ({ key }) => {
const datastore = await Datastore.query().findOne({
key,
scope: 'flow',
scope_id: $.flow.id,
});
return {
key: datastore.key,
value: datastore.value,
[datastore.key]: datastore.value,
};
},
set: async ({ key, value }) => {
let datastore = await Datastore.query()
.where({ key, scope: 'flow', scope_id: $.flow.id })
.first();
if (datastore) {
await datastore.$query().patchAndFetch({ value: value });
} else {
datastore = await Datastore.query().insert({
key,
value,
scope: 'flow',
scopeId: $.flow.id,
});
}
return {
key: datastore.key,
value: datastore.value,
[datastore.key]: datastore.value,
};
},
},
}; };
if (request) { if (request) {

View File

@@ -4,8 +4,8 @@ import appConfig from '../config/app.js';
const levels = { const levels = {
error: 0, error: 0,
warn: 1, warn: 1,
http: 2, info: 2,
info: 3, http: 3,
debug: 4, debug: 4,
}; };

View File

@@ -1,25 +0,0 @@
const paginateRest = async (query, page) => {
const pageSize = 10;
page = parseInt(page, 10);
if (isNaN(page) || page < 1) {
page = 1;
}
const [records, count] = await Promise.all([
query.limit(pageSize).offset((page - 1) * pageSize),
query.resultSize(),
]);
return {
pageInfo: {
currentPage: page,
totalPages: Math.ceil(count / pageSize),
},
totalCount: count,
records,
};
};
export default paginateRest;

View File

@@ -1,47 +0,0 @@
import serializers from '../serializers/index.js';
const isPaginated = (object) =>
object?.pageInfo &&
object?.totalCount !== undefined &&
Array.isArray(object?.records);
const isArray = (object) =>
Array.isArray(object) || Array.isArray(object?.records);
const totalCount = (object) =>
isPaginated(object) ? object.totalCount : isArray(object) ? object.length : 1;
const renderObject = (response, object, options) => {
let data = isPaginated(object) ? object.records : object;
const type = isPaginated(object)
? object.records[0].constructor.name
: Array.isArray(object)
? object?.[0]?.constructor?.name || 'Object'
: object.constructor.name;
const serializer = options?.serializer
? serializers[options.serializer]
: serializers[type];
if (serializer) {
data = Array.isArray(data)
? data.map((item) => serializer(item))
: serializer(data);
}
const computedPayload = {
data,
meta: {
type,
count: totalCount(object),
isArray: isArray(object),
currentPage: isPaginated(object) ? object.pageInfo.currentPage : null,
totalPages: isPaginated(object) ? object.pageInfo.totalPages : null,
},
};
return response.json(computedPayload);
};
export { renderObject };

View File

@@ -15,7 +15,7 @@ const webUIHandler = async (app) => {
app.use(express.static(webBuildPath)); app.use(express.static(webBuildPath));
app.get('*', (_req, res) => { app.get('*', (_req, res) => {
res.set('Content-Security-Policy', 'frame-ancestors \'none\';'); res.set('Content-Security-Policy', 'frame-ancestors: none;');
res.set('X-Frame-Options', 'DENY'); res.set('X-Frame-Options', 'DENY');
res.sendFile(indexHtml); res.sendFile(indexHtml);

View File

@@ -1,24 +0,0 @@
import Base from './base.js';
class Datastore extends Base {
static tableName = 'datastore';
static jsonSchema = {
type: 'object',
required: ['key', 'value', 'scope', 'scopeId'],
properties: {
id: { type: 'string', format: 'uuid' },
key: { type: 'string', minLength: 1 },
value: { type: 'string' },
scope: {
type: 'string',
enum: ['flow'],
default: 'flow',
},
scopeId: { type: 'string', format: 'uuid' },
},
};
}
export default Datastore;

View File

@@ -15,7 +15,6 @@ import Role from './role.js';
import Step from './step.js'; import Step from './step.js';
import Subscription from './subscription.ee.js'; import Subscription from './subscription.ee.js';
import UsageData from './usage-data.ee.js'; import UsageData from './usage-data.ee.js';
import Billing from '../helpers/billing/index.ee.js';
class User extends Base { class User extends Base {
static tableName = 'users'; static tableName = 'users';
@@ -144,11 +143,6 @@ class User extends Base {
}, },
}); });
get authorizedFlows() {
const conditions = this.can('read', 'Flow');
return conditions.isCreator ? this.$relatedQuery('flows') : Flow.query();
}
login(password) { login(password) {
return bcrypt.compare(password, this.password); return bcrypt.compare(password, this.password);
} }
@@ -243,20 +237,6 @@ class User extends Base {
return currentUsageData.consumedTaskCount < plan.quota; return currentUsageData.consumedTaskCount < plan.quota;
} }
async getInvoices() {
const subscription = await this.$relatedQuery('currentSubscription');
if (!subscription) {
return [];
}
const invoices = await Billing.paddleClient.getInvoices(
Number(subscription.paddleSubscriptionId)
);
return invoices;
}
async $beforeInsert(queryContext) { async $beforeInsert(queryContext) {
await super.$beforeInsert(queryContext); await super.$beforeInsert(queryContext);

View File

@@ -15,17 +15,11 @@ process.on('SIGTERM', async () => {
await actionQueue.close(); await actionQueue.close();
}); });
actionQueue.on('error', (error) => { actionQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error('Error happened in action queue!', error);
}); });
export default actionQueue; export default actionQueue;

View File

@@ -15,17 +15,11 @@ process.on('SIGTERM', async () => {
await deleteUserQueue.close(); await deleteUserQueue.close();
}); });
deleteUserQueue.on('error', (error) => { deleteUserQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error('Error happened in delete user queue!', error);
}); });
export default deleteUserQueue; export default deleteUserQueue;

View File

@@ -15,17 +15,11 @@ process.on('SIGTERM', async () => {
await emailQueue.close(); await emailQueue.close();
}); });
emailQueue.on('error', (error) => { emailQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error('Error happened in email queue!', error);
}); });
export default emailQueue; export default emailQueue;

View File

@@ -15,17 +15,11 @@ process.on('SIGTERM', async () => {
await flowQueue.close(); await flowQueue.close();
}); });
flowQueue.on('error', (error) => { flowQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error('Error happened in flow queue!', error);
}); });
export default flowQueue; export default flowQueue;

View File

@@ -18,20 +18,11 @@ process.on('SIGTERM', async () => {
await removeCancelledSubscriptionsQueue.close(); await removeCancelledSubscriptionsQueue.close();
}); });
removeCancelledSubscriptionsQueue.on('error', (error) => { removeCancelledSubscriptionsQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error(
'Error happened in remove cancelled subscriptions queue!',
error
);
}); });
removeCancelledSubscriptionsQueue.add('remove-cancelled-subscriptions', null, { removeCancelledSubscriptionsQueue.add('remove-cancelled-subscriptions', null, {

View File

@@ -15,17 +15,11 @@ process.on('SIGTERM', async () => {
await triggerQueue.close(); await triggerQueue.close();
}); });
triggerQueue.on('error', (error) => { triggerQueue.on('error', (err) => {
if (error.code === CONNECTION_REFUSED) { if (err.code === CONNECTION_REFUSED) {
logger.error( logger.error('Make sure you have installed Redis and it is running.', err);
'Make sure you have installed Redis and it is running.',
error
);
process.exit(); process.exit();
} }
logger.error('Error happened in trigger queue!', error);
}); });
export default triggerQueue; export default triggerQueue;

View File

@@ -1,18 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getAdminAppAuthClientsAction from '../../../../controllers/api/v1/admin/app-auth-clients/get-app-auth-client.js';
const router = Router();
router.get(
'/:appAuthClientId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getAdminAppAuthClientsAction)
);
export default router;

View File

@@ -1,18 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getPermissionsCatalogAction from '../../../../controllers/api/v1/admin/permissions/get-permissions-catalog.ee.js';
const router = Router();
router.get(
'/catalog',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getPermissionsCatalogAction)
);
export default router;

View File

@@ -1,27 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getRolesAction from '../../../../controllers/api/v1/admin/roles/get-roles.ee.js';
import getRoleAction from '../../../../controllers/api/v1/admin/roles/get-role.ee.js';
const router = Router();
router.get(
'/',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getRolesAction)
);
router.get(
'/:roleId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getRoleAction)
);
export default router;

View File

@@ -1,27 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getSamlAuthProvidersAction from '../../../../controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.js';
import getSamlAuthProviderAction from '../../../../controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.js';
const router = Router();
router.get(
'/',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getSamlAuthProvidersAction)
);
router.get(
'/:samlAuthProviderId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getSamlAuthProviderAction)
);
export default router;

View File

@@ -1,27 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
import getUsersAction from '../../../../controllers/api/v1/admin/users/get-users.ee.js';
import getUserAction from '../../../../controllers/api/v1/admin/users/get-user.ee.js';
const router = Router();
router.get(
'/',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getUsersAction)
);
router.get(
'/:userId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
asyncHandler(getUserAction)
);
export default router;

View File

@@ -1,16 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import { checkIsEnterprise } from '../../../helpers/check-is-enterprise.js';
import getAppAuthClientAction from '../../../controllers/api/v1/app-auth-clients/get-app-auth-client.js';
const router = Router();
router.get(
'/:appAuthClientId',
authenticateUser,
checkIsEnterprise,
asyncHandler(getAppAuthClientAction)
);
export default router;

View File

@@ -1,10 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import getAppAction from '../../../controllers/api/v1/apps/get-app.js';
const router = Router();
router.get('/:appKey', authenticateUser, asyncHandler(getAppAction));
export default router;

View File

@@ -1,15 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import versionAction from '../../../controllers/api/v1/automatisch/version.js';
import notificationsAction from '../../../controllers/api/v1/automatisch/notifications.js';
import infoAction from '../../../controllers/api/v1/automatisch/info.js';
import licenseAction from '../../../controllers/api/v1/automatisch/license.js';
const router = Router();
router.get('/version', asyncHandler(versionAction));
router.get('/notifications', asyncHandler(notificationsAction));
router.get('/info', asyncHandler(infoAction));
router.get('/license', asyncHandler(licenseAction));
export default router;

View File

@@ -1,16 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import { authorizeUser } from '../../../helpers/authorization.js';
import getFlowAction from '../../../controllers/api/v1/flows/get-flow.js';
const router = Router();
router.get(
'/:flowId',
authenticateUser,
authorizeUser,
asyncHandler(getFlowAction)
);
export default router;

View File

@@ -1,24 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import checkIsCloud from '../../../helpers/check-is-cloud.js';
import getPlansAction from '../../../controllers/api/v1/payment/get-plans.ee.js';
import getPaddleInfoAction from '../../../controllers/api/v1/payment/get-paddle-info.ee.js';
const router = Router();
router.get(
'/plans',
authenticateUser,
checkIsCloud,
asyncHandler(getPlansAction)
);
router.get(
'/paddle-info',
authenticateUser,
checkIsCloud,
asyncHandler(getPaddleInfoAction)
);
export default router;

View File

@@ -1,26 +0,0 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js';
import checkIsCloud from '../../../helpers/check-is-cloud.js';
import getCurrentUserAction from '../../../controllers/api/v1/users/get-current-user.js';
import getUserTrialAction from '../../../controllers/api/v1/users/get-user-trial.ee.js';
import getInvoicesAction from '../../../controllers/api/v1/users/get-invoices.ee.js';
const router = Router();
router.get('/me', authenticateUser, asyncHandler(getCurrentUserAction));
router.get(
'/invoices',
authenticateUser,
checkIsCloud,
asyncHandler(getInvoicesAction)
);
router.get(
'/:userId/trial',
authenticateUser,
checkIsCloud,
asyncHandler(getUserTrialAction)
);
export default router;

Some files were not shown because too many files have changed in this diff Show More