Compare commits

..

1 Commits

Author SHA1 Message Date
Rıdvan Akca
8e45a42a6b feat(discord): add change scheduled event action 2024-02-23 18:09:54 +03:00
73 changed files with 365 additions and 1047 deletions

View File

@@ -38,7 +38,6 @@
"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",
@@ -95,7 +94,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,120 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Change a scheduled event',
key: 'changeScheduledEvent',
description: 'Changes a scheduled event',
arguments: [
{
label: 'Scheduled Event',
key: 'scheduledEventId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listScheduledEvents',
},
],
},
},
{
label: 'Status',
key: 'status',
type: 'dropdown',
required: false,
description:
'After the status has been changed to COMPLETED or CANCELED, it becomes immutable and cannot be modified further.',
variables: true,
options: [
{ label: 'SCHEDULED', value: 1 },
{ label: 'ACTIVE', value: 2 },
{ label: 'COMPLETED', value: 3 },
{ label: 'CANCELED', value: 4 },
],
},
{
label: 'Type',
key: 'entityType',
type: 'dropdown',
required: true,
variables: true,
options: [
{ label: 'Stage channel', value: 1 },
{ label: 'Voice channel', value: 2 },
{ label: 'External', value: 3 },
],
additionalFields: {
type: 'query',
name: 'getDynamicFields',
arguments: [
{
name: 'key',
value: 'listScheduledEventFieldsForChange',
},
{
name: 'parameters.entityType',
value: '{parameters.entityType}',
},
],
},
},
{
label: 'Name',
key: 'name',
type: 'string',
required: false,
variables: true,
},
{
label: 'Description',
key: 'description',
type: 'string',
required: false,
variables: true,
},
{
label: 'Image',
key: 'image',
type: 'string',
required: false,
description:
'Image as DataURI scheme [data:image/<jpeg/png/gif>;base64,BASE64_ENCODED_<JPEG/PNG/GIF>_IMAGE_DATA]',
variables: true,
},
],
async run($) {
const data = {
channel_id: $.step.parameters.channel_id,
name: $.step.parameters.name,
scheduled_start_time: $.step.parameters.scheduledStartTime,
scheduled_end_time: $.step.parameters.scheduledEndTime,
description: $.step.parameters.description,
entity_type: $.step.parameters.entityType,
image: $.step.parameters.image,
};
const isExternal = $.step.parameters.entityType === 3;
if (isExternal) {
data.entity_metadata = {
location: $.step.parameters.location,
};
data.channel_id = null;
}
const response = await $.http?.patch(
`/guilds/${$.auth.data.guildId}/scheduled-events/${$.step.parameters.scheduledEventId}`,
data
);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -1,4 +1,9 @@
import changeScheduledEvent from './change-scheduled-event/index.js';
import sendMessageToChannel from './send-message-to-channel/index.js'; import sendMessageToChannel from './send-message-to-channel/index.js';
import createScheduledEvent from './create-scheduled-event/index.js'; import createScheduledEvent from './create-scheduled-event/index.js';
export default [sendMessageToChannel, createScheduledEvent]; export default [
changeScheduledEvent,
sendMessageToChannel,
createScheduledEvent,
];

View File

@@ -1,4 +1,5 @@
import listChannels from './list-channels/index.js'; import listChannels from './list-channels/index.js';
import listScheduledEvents from './list-scheduled-events/index.js';
import listVoiceChannels from './list-voice-channels/index.js'; import listVoiceChannels from './list-voice-channels/index.js';
export default [listChannels, listVoiceChannels]; export default [listChannels, listScheduledEvents, listVoiceChannels];

View File

@@ -0,0 +1,24 @@
export default {
name: 'List scheduled events',
key: 'listScheduledEvents',
async run($) {
const scheduledEvents = {
data: [],
error: null,
};
const response = await $.http.get(
`/guilds/${$.auth.data.guildId}/scheduled-events`
);
scheduledEvents.data = response.data.map((scheduledEvent) => {
return {
value: scheduledEvent.id,
name: scheduledEvent.name,
};
});
return scheduledEvents;
},
};

View File

@@ -1,3 +1,7 @@
import listExternalScheduledEventFields from './list-external-scheduled-event-fields/index.js'; import listExternalScheduledEventFields from './list-external-scheduled-event-fields/index.js';
import listScheduledEventFieldsForChange from './list-scheduled-event-fields-for-change/index.js';
export default [listExternalScheduledEventFields]; export default [
listExternalScheduledEventFields,
listScheduledEventFieldsForChange,
];

View File

@@ -0,0 +1,87 @@
export default {
name: 'List scheduled event fields for change',
key: 'listScheduledEventFieldsForChange',
async run($) {
const isExternal = $.step.parameters.entityType === 3;
if (isExternal) {
return [
{
label: 'Location',
key: 'location',
type: 'string',
required: true,
description:
'The location of the event (1-100 characters). This will be omitted if type is NOT EXTERNAL',
variables: true,
},
{
label: 'Start-Time',
key: 'scheduledStartTime',
type: 'string',
required: false,
description: 'The time the event will start [ISO8601]',
variables: true,
},
{
label: 'End-Time',
key: 'scheduledEndTime',
type: 'string',
required: true,
description:
'The time the event will end [ISO8601]. This will be omitted if type is NOT EXTERNAL',
variables: true,
},
];
}
return [
{
label: 'Channel',
key: 'channel_id',
type: 'dropdown',
required: true,
description:
'Pick a voice or stage channel to link the event to. This will be omitted if type is EXTERNAL',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listVoiceChannels',
},
],
},
},
{
label: 'Location',
key: 'location',
type: 'string',
required: false,
description:
'The location of the event (1-100 characters). This will be omitted if type is NOT EXTERNAL',
variables: true,
},
{
label: 'Start-Time',
key: 'scheduledStartTime',
type: 'string',
required: false,
description: 'The time the event will start [ISO8601]',
variables: true,
},
{
label: 'End-Time',
key: 'scheduledEndTime',
type: 'string',
required: false,
description:
'The time the event will end [ISO8601]. This will be omitted if type is NOT EXTERNAL',
variables: true,
},
];
},
};

View File

@@ -2,7 +2,6 @@ import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js'; import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js'; import auth from './auth/index.js';
import actions from './actions/index.js'; import actions from './actions/index.js';
import triggers from './triggers/index.js';
export default defineApp({ export default defineApp({
name: 'Dropbox', name: 'Dropbox',
@@ -16,5 +15,4 @@ export default defineApp({
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
actions, actions,
triggers,
}); });

View File

@@ -1,3 +0,0 @@
import newFolders from './new-folders/index.js';
export default [newFolders];

View File

@@ -1,61 +0,0 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New folders',
key: 'newFolders',
pollInterval: 15,
description:
'Triggers when any new folder is added. Ensure that the number of files/folders within the monitored directory remains below 4000.',
arguments: [
{
label: 'Folder',
key: 'folderPath',
type: 'string',
required: true,
description:
'Enter the folder path that you want to follow, like /TextFiles or /Documents/Taxes.',
variables: true,
},
],
async run($) {
const folderPath = $.step.parameters.folderPath;
let endpoint = '/2/files/list_folder';
let next = false;
const params = {
path: folderPath,
recursive: false,
include_deleted: false,
include_has_explicit_shared_members: false,
include_mounted_folders: true,
limit: 2000,
include_non_downloadable_files: true,
};
do {
const { data } = await $.http.post(endpoint, params);
if (data.has_more) {
endpoint += '/continue';
params.cursor = data.cursor;
next = data.has_more;
} else {
next = false;
}
if (data.entries?.length) {
for (const entry of data.entries.reverse()) {
if (entry['.tag'] === 'folder') {
$.pushTriggerItem({
raw: entry,
meta: {
internalId: entry.id,
},
});
}
}
}
} while (next);
},
});

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

View File

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

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

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

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,8 +1,11 @@
import { renderObject } from '../../../../../helpers/renderer.js'; import { renderObject } from '../../../../helpers/renderer.js';
import User from '../../../../../models/user.js'; import User from '../../../../models/user.js';
export default async (request, response) => { export default async (request, response) => {
const user = await User.query() const user = await User.query()
.leftJoinRelated({
role: true,
})
.withGraphFetched({ .withGraphFetched({
role: true, role: true,
}) })

View File

@@ -0,0 +1,36 @@
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 { createPermission } from '../../../../../test/factories/permission';
import getUserMock from '../../../../../test/mocks/rest/api/v1/users/get-user';
describe('GET /api/v1/users/:userId', () => {
let currentUser, currentUserRole, anotherUser, anotherUserRole, token;
beforeEach(async () => {
currentUser = await createUser();
anotherUser = await createUser();
currentUserRole = await currentUser.$relatedQuery('role');
anotherUserRole = await anotherUser.$relatedQuery('role');
await createPermission({
roleId: currentUserRole.id,
action: 'read',
subject: 'User',
});
token = createAuthTokenByUserId(currentUser.id);
});
it('should return specified user info', async () => {
const response = await request(app)
.get(`/api/v1/users/${anotherUser.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = getUserMock(anotherUser, anotherUserRole);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,9 +1,12 @@
import { renderObject } from '../../../../../helpers/renderer.js'; import { renderObject } from '../../../../helpers/renderer.js';
import User from '../../../../../models/user.js'; import User from '../../../../models/user.js';
import paginateRest from '../../../../../helpers/pagination-rest.js'; import paginateRest from '../../../../helpers/pagination-rest.js';
export default async (request, response) => { export default async (request, response) => {
const usersQuery = User.query() const usersQuery = User.query()
.leftJoinRelated({
role: true,
})
.withGraphFetched({ .withGraphFetched({
role: true, role: true,
}) })

View File

@@ -1,17 +1,26 @@
import { vi, describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest'; import request from 'supertest';
import app from '../../../../../app'; import app from '../../../../app';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id'; import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
import { createRole } from '../../../../../../test/factories/role'; import { createRole } from '../../../../../test/factories/role';
import { createUser } from '../../../../../../test/factories/user'; import { createPermission } from '../../../../../test/factories/permission';
import getUsersMock from '../../../../../../test/mocks/rest/api/v1/admin/users/get-users.js'; import { createUser } from '../../../../../test/factories/user';
import * as license from '../../../../../helpers/license.ee.js'; import getUsersMock from '../../../../../test/mocks/rest/api/v1/users/get-users';
describe('GET /api/v1/admin/users', () => { describe('GET /api/v1/users', () => {
let currentUser, currentUserRole, anotherUser, anotherUserRole, token; let currentUser, currentUserRole, anotherUser, anotherUserRole, token;
beforeEach(async () => { beforeEach(async () => {
currentUserRole = await createRole({ key: 'admin' }); currentUserRole = await createRole({
key: 'currentUser',
name: 'Current user role',
});
await createPermission({
action: 'read',
subject: 'User',
roleId: currentUserRole.id,
});
currentUser = await createUser({ currentUser = await createUser({
roleId: currentUserRole.id, roleId: currentUserRole.id,
@@ -32,10 +41,8 @@ describe('GET /api/v1/admin/users', () => {
}); });
it('should return users data', async () => { it('should return users data', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app) const response = await request(app)
.get('/api/v1/admin/users') .get('/api/v1/users')
.set('Authorization', token) .set('Authorization', token)
.expect(200); .expect(200);

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

@@ -7,10 +7,6 @@ const authorizationList = {
action: 'read', action: 'read',
subject: 'User', subject: 'User',
}, },
'GET /api/v1/flows/:flowId': {
action: 'read',
subject: 'Flow',
},
}; };
export const authorizeUser = async (request, response, next) => { export const authorizeUser = async (request, response, next) => {

View File

@@ -13,11 +13,10 @@ const totalCount = (object) =>
const renderObject = (response, object) => { const renderObject = (response, object) => {
let data = isPaginated(object) ? object.records : object; let data = isPaginated(object) ? object.records : object;
const type = isPaginated(object) const type = isPaginated(object)
? object.records[0].constructor.name ? object.records[0].constructor.name
: Array.isArray(object) : Array.isArray(object)
? object?.[0]?.constructor?.name || 'Object' ? object[0].constructor.name
: object.constructor.name; : object.constructor.name;
const serializer = serializers[type]; const serializer = serializers[type];

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,5 +1,4 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js'; import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js'; import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js'; import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
@@ -12,7 +11,7 @@ router.get(
authenticateUser, authenticateUser,
authorizeAdmin, authorizeAdmin,
checkIsEnterprise, checkIsEnterprise,
asyncHandler(getPermissionsCatalogAction) getPermissionsCatalogAction
); );
export default router; export default router;

View File

@@ -1,5 +1,4 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js'; import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js'; import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js'; import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
@@ -13,7 +12,7 @@ router.get(
authenticateUser, authenticateUser,
authorizeAdmin, authorizeAdmin,
checkIsEnterprise, checkIsEnterprise,
asyncHandler(getRolesAction) getRolesAction
); );
router.get( router.get(
@@ -21,7 +20,7 @@ router.get(
authenticateUser, authenticateUser,
authorizeAdmin, authorizeAdmin,
checkIsEnterprise, checkIsEnterprise,
asyncHandler(getRoleAction) getRoleAction
); );
export default router; export default router;

View File

@@ -1,5 +1,4 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../../helpers/authentication.js'; import { authenticateUser } from '../../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../../helpers/authorization.js'; import { authorizeAdmin } from '../../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js'; import { checkIsEnterprise } from '../../../../helpers/check-is-enterprise.js';
@@ -13,7 +12,7 @@ router.get(
authenticateUser, authenticateUser,
authorizeAdmin, authorizeAdmin,
checkIsEnterprise, checkIsEnterprise,
asyncHandler(getSamlAuthProvidersAction) getSamlAuthProvidersAction
); );
router.get( router.get(
@@ -21,7 +20,7 @@ router.get(
authenticateUser, authenticateUser,
authorizeAdmin, authorizeAdmin,
checkIsEnterprise, checkIsEnterprise,
asyncHandler(getSamlAuthProviderAction) getSamlAuthProviderAction
); );
export default router; 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,15 +1,10 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import versionAction from '../../../controllers/api/v1/automatisch/version.js'; import versionAction from '../../../controllers/api/v1/automatisch/version.js';
import notificationsAction from '../../../controllers/api/v1/automatisch/notifications.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(); const router = Router();
router.get('/version', asyncHandler(versionAction)); router.get('/version', versionAction);
router.get('/notifications', asyncHandler(notificationsAction)); router.get('/notifications', notificationsAction);
router.get('/info', asyncHandler(infoAction));
router.get('/license', asyncHandler(licenseAction));
export default router; 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,5 +1,4 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js'; import { authenticateUser } from '../../../helpers/authentication.js';
import checkIsCloud from '../../../helpers/check-is-cloud.js'; import checkIsCloud from '../../../helpers/check-is-cloud.js';
import getPlansAction from '../../../controllers/api/v1/payment/get-plans.ee.js'; import getPlansAction from '../../../controllers/api/v1/payment/get-plans.ee.js';
@@ -7,18 +6,7 @@ import getPaddleInfoAction from '../../../controllers/api/v1/payment/get-paddle-
const router = Router(); const router = Router();
router.get( router.get('/plans', authenticateUser, checkIsCloud, getPlansAction);
'/plans', router.get('/paddle-info', authenticateUser, checkIsCloud, getPaddleInfoAction);
authenticateUser,
checkIsCloud,
asyncHandler(getPlansAction)
);
router.get(
'/paddle-info',
authenticateUser,
checkIsCloud,
asyncHandler(getPaddleInfoAction)
);
export default router; export default router;

View File

@@ -1,26 +1,22 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { authenticateUser } from '../../../helpers/authentication.js'; import { authenticateUser } from '../../../helpers/authentication.js';
import { authorizeUser } from '../../../helpers/authorization.js';
import checkIsCloud from '../../../helpers/check-is-cloud.js'; import checkIsCloud from '../../../helpers/check-is-cloud.js';
import getCurrentUserAction from '../../../controllers/api/v1/users/get-current-user.js'; import getCurrentUserAction from '../../../controllers/api/v1/users/get-current-user.js';
import getUserAction from '../../../controllers/api/v1/users/get-user.js';
import getUsersAction from '../../../controllers/api/v1/users/get-users.js';
import getUserTrialAction from '../../../controllers/api/v1/users/get-user-trial.ee.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(); const router = Router();
router.get('/me', authenticateUser, asyncHandler(getCurrentUserAction)); router.get('/', authenticateUser, authorizeUser, getUsersAction);
router.get( router.get('/me', authenticateUser, getCurrentUserAction);
'/invoices', router.get('/:userId', authenticateUser, authorizeUser, getUserAction);
authenticateUser,
checkIsCloud,
asyncHandler(getInvoicesAction)
);
router.get( router.get(
'/:userId/trial', '/:userId/trial',
authenticateUser, authenticateUser,
checkIsCloud, checkIsCloud,
asyncHandler(getUserTrialAction) getUserTrialAction
); );
export default router; export default router;

View File

@@ -1,9 +1,8 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import indexAction from '../controllers/healthcheck/index.js'; import indexAction from '../controllers/healthcheck/index.js';
const router = Router(); const router = Router();
router.get('/', asyncHandler(indexAction)); router.get('/', indexAction);
export default router; export default router;

View File

@@ -6,13 +6,9 @@ import healthcheckRouter from './healthcheck.js';
import automatischRouter from './api/v1/automatisch.js'; import automatischRouter from './api/v1/automatisch.js';
import usersRouter from './api/v1/users.js'; import usersRouter from './api/v1/users.js';
import paymentRouter from './api/v1/payment.ee.js'; import paymentRouter from './api/v1/payment.ee.js';
import appAuthClientsRouter from './api/v1/app-auth-clients.js';
import flowsRouter from './api/v1/flows.js';
import samlAuthProvidersRouter from './api/v1/admin/saml-auth-providers.ee.js'; import samlAuthProvidersRouter from './api/v1/admin/saml-auth-providers.ee.js';
import rolesRouter from './api/v1/admin/roles.ee.js'; import rolesRouter from './api/v1/admin/roles.ee.js';
import permissionsRouter from './api/v1/admin/permissions.ee.js'; import permissionsRouter from './api/v1/admin/permissions.ee.js';
import adminUsersRouter from './api/v1/admin/users.ee.js';
import adminAppAuthClientsRouter from './api/v1/admin/app-auth-clients.js';
const router = Router(); const router = Router();
@@ -23,12 +19,8 @@ router.use('/healthcheck', healthcheckRouter);
router.use('/api/v1/automatisch', automatischRouter); router.use('/api/v1/automatisch', automatischRouter);
router.use('/api/v1/users', usersRouter); router.use('/api/v1/users', usersRouter);
router.use('/api/v1/payment', paymentRouter); router.use('/api/v1/payment', paymentRouter);
router.use('/api/v1/app-auth-clients', appAuthClientsRouter);
router.use('/api/v1/flows', flowsRouter);
router.use('/api/v1/admin/saml-auth-providers', samlAuthProvidersRouter); router.use('/api/v1/admin/saml-auth-providers', samlAuthProvidersRouter);
router.use('/api/v1/admin/roles', rolesRouter); router.use('/api/v1/admin/roles', rolesRouter);
router.use('/api/v1/admin/permissions', permissionsRouter); router.use('/api/v1/admin/permissions', permissionsRouter);
router.use('/api/v1/admin/users', adminUsersRouter);
router.use('/api/v1/admin/app-auth-clients', adminAppAuthClientsRouter);
export default router; export default router;

View File

@@ -1,9 +1,16 @@
import { Router } from 'express'; import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import webhooksHandler from '../controllers/paddle/webhooks.ee.js'; import webhooksHandler from '../controllers/paddle/webhooks.ee.js';
const router = Router(); const router = Router();
router.post('/webhooks', asyncHandler(webhooksHandler)); const exposeError = (handler) => async (req, res, next) => {
try {
await handler(req, res, next);
} catch (err) {
next(err);
}
};
router.post('/webhooks', exposeError(webhooksHandler));
export default router; export default router;

View File

@@ -1,10 +0,0 @@
const appAuthClientSerializer = (appAuthClient) => {
return {
id: appAuthClient.id,
appConfigId: appAuthClient.appConfigId,
name: appAuthClient.name,
active: appAuthClient.active,
};
};
export default appAuthClientSerializer;

View File

@@ -1,22 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createAppAuthClient } from '../../test/factories/app-auth-client';
import appAuthClientSerializer from './app-auth-client';
describe('appAuthClient serializer', () => {
let appAuthClient;
beforeEach(async () => {
appAuthClient = await createAppAuthClient();
});
it('should return app auth client data', async () => {
const expectedPayload = {
id: appAuthClient.id,
appConfigId: appAuthClient.appConfigId,
name: appAuthClient.name,
active: appAuthClient.active,
};
expect(appAuthClientSerializer(appAuthClient)).toEqual(expectedPayload);
});
});

View File

@@ -1,18 +0,0 @@
import stepSerializer from './step.js';
const flowSerializer = (flow) => {
let flowData = {
id: flow.id,
name: flow.name,
active: flow.active,
status: flow.status,
};
if (flow.steps) {
flowData.steps = flow.steps.map((step) => stepSerializer(step));
}
return flowData;
};
export default flowSerializer;

View File

@@ -1,44 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createFlow } from '../../test/factories/flow';
import flowSerializer from './flow';
import stepSerializer from './step';
import { createStep } from '../../test/factories/step';
describe('flowSerializer', () => {
let flow, stepOne, stepTwo;
beforeEach(async () => {
flow = await createFlow();
stepOne = await createStep({
flowId: flow.id,
type: 'trigger',
});
stepTwo = await createStep({
flowId: flow.id,
type: 'action',
});
});
it('should return flow data', async () => {
const expectedPayload = {
id: flow.id,
name: flow.name,
active: flow.active,
status: flow.status,
};
expect(flowSerializer(flow)).toEqual(expectedPayload);
});
it('should return flow data with the steps', async () => {
flow.steps = [stepOne, stepTwo];
const expectedPayload = {
steps: [stepSerializer(stepOne), stepSerializer(stepTwo)],
};
expect(flowSerializer(flow)).toMatchObject(expectedPayload);
});
});

View File

@@ -2,18 +2,12 @@ import userSerializer from './user.js';
import roleSerializer from './role.js'; import roleSerializer from './role.js';
import permissionSerializer from './permission.js'; import permissionSerializer from './permission.js';
import samlAuthProviderSerializer from './saml-auth-provider.ee.js'; import samlAuthProviderSerializer from './saml-auth-provider.ee.js';
import appAuthClientSerializer from './app-auth-client.js';
import flowSerializer from './flow.js';
import stepSerializer from './step.js';
const serializers = { const serializers = {
User: userSerializer, User: userSerializer,
Role: roleSerializer, Role: roleSerializer,
Permission: permissionSerializer, Permission: permissionSerializer,
SamlAuthProvider: samlAuthProviderSerializer, SamlAuthProvider: samlAuthProviderSerializer,
AppAuthClient: appAuthClientSerializer,
Flow: flowSerializer,
Step: stepSerializer,
}; };
export default serializers; export default serializers;

View File

@@ -1,7 +1,6 @@
import { describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect, beforeEach } from 'vitest';
import { createRole } from '../../test/factories/role'; import { createRole } from '../../test/factories/role';
import roleSerializer from './role'; import roleSerializer from './role';
import permissionSerializer from './permission';
import { createPermission } from '../../test/factories/permission'; import { createPermission } from '../../test/factories/permission';
describe('roleSerializer', () => { describe('roleSerializer', () => {
@@ -41,10 +40,7 @@ describe('roleSerializer', () => {
role.permissions = [permissionOne, permissionTwo]; role.permissions = [permissionOne, permissionTwo];
const expectedPayload = { const expectedPayload = {
permissions: [ permissions: [permissionOne, permissionTwo],
permissionSerializer(permissionOne),
permissionSerializer(permissionTwo),
],
}; };
expect(roleSerializer(role)).toMatchObject(expectedPayload); expect(roleSerializer(role)).toMatchObject(expectedPayload);

View File

@@ -1,15 +0,0 @@
const stepSerializer = (step) => {
return {
id: step.id,
type: step.type,
key: step.key,
appKey: step.appKey,
iconUrl: step.iconUrl,
webhookUrl: step.webhookUrl,
status: step.status,
position: step.position,
parameters: step.parameters,
};
};
export default stepSerializer;

View File

@@ -1,27 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createStep } from '../../test/factories/step';
import stepSerializer from './step';
describe('stepSerializer', () => {
let step;
beforeEach(async () => {
step = await createStep();
});
it('should return step data', async () => {
const expectedPayload = {
id: step.id,
type: step.type,
key: step.key,
appKey: step.appKey,
iconUrl: step.iconUrl,
webhookUrl: step.webhookUrl,
status: step.status,
position: step.position,
parameters: step.parameters,
};
expect(stepSerializer(step)).toEqual(expectedPayload);
});
});

View File

@@ -4,8 +4,6 @@ import appConfig from '../config/app';
import { createUser } from '../../test/factories/user'; import { createUser } from '../../test/factories/user';
import { createPermission } from '../../test/factories/permission'; import { createPermission } from '../../test/factories/permission';
import userSerializer from './user'; import userSerializer from './user';
import roleSerializer from './role';
import permissionSerializer from './permission';
describe('userSerializer', () => { describe('userSerializer', () => {
let user, role, permissionOne, permissionTwo; let user, role, permissionOne, permissionTwo;
@@ -45,7 +43,7 @@ describe('userSerializer', () => {
user.role = role; user.role = role;
const expectedPayload = { const expectedPayload = {
role: roleSerializer(role), role,
}; };
expect(userSerializer(user)).toMatchObject(expectedPayload); expect(userSerializer(user)).toMatchObject(expectedPayload);
@@ -55,10 +53,7 @@ describe('userSerializer', () => {
user.permissions = [permissionOne, permissionTwo]; user.permissions = [permissionOne, permissionTwo];
const expectedPayload = { const expectedPayload = {
permissions: [ permissions: [permissionOne, permissionTwo],
permissionSerializer(permissionOne),
permissionSerializer(permissionTwo),
],
}; };
expect(userSerializer(user)).toMatchObject(expectedPayload); expect(userSerializer(user)).toMatchObject(expectedPayload);

View File

@@ -1,25 +0,0 @@
import { faker } from '@faker-js/faker';
import { createAppConfig } from './app-config.js';
import AppAuthClient from '../../src/models/app-auth-client';
const formattedAuthDefaults = {
oAuthRedirectUrl: faker.internet.url(),
instanceUrl: faker.internet.url(),
clientId: faker.string.uuid(),
clientSecret: faker.string.uuid(),
};
export const createAppAuthClient = async (params = {}) => {
params.name = params?.name || faker.person.fullName();
params.id = params?.id || faker.string.uuid();
params.appConfigId = params?.appConfigId || (await createAppConfig()).id;
params.active = params?.active ?? true;
params.formattedAuthDefaults =
params?.formattedAuthDefaults || formattedAuthDefaults;
const appAuthClient = await AppAuthClient.query()
.insert(params)
.returning('*');
return appAuthClient;
};

View File

@@ -1,13 +0,0 @@
import AppConfig from '../../src/models/app-config.js';
export const createAppConfig = async (params = {}) => {
const appConfigData = {
key: params?.key || 'gitlab',
};
const appConfig = await AppConfig.query()
.insert(appConfigData)
.returning('*');
return appConfig;
};

View File

@@ -1,19 +0,0 @@
const getAdminAppAuthClientMock = (appAuthClient) => {
return {
data: {
appConfigId: appAuthClient.appConfigId,
name: appAuthClient.name,
id: appAuthClient.id,
active: appAuthClient.active,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'AppAuthClient',
},
};
};
export default getAdminAppAuthClientMock;

View File

@@ -1,18 +0,0 @@
const infoMock = () => {
return {
data: {
isCloud: false,
isMation: false,
isEnterprise: true,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'Object',
},
};
};
export default infoMock;

View File

@@ -1,19 +0,0 @@
const licenseMock = () => {
return {
data: {
expireAt: '2025-12-31T23:59:59Z',
id: '123',
name: 'license-name',
verified: true,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'Object',
},
};
};
export default licenseMock;

View File

@@ -1,32 +0,0 @@
const getFlowMock = async (flow, steps) => {
const data = {
active: flow.active,
id: flow.id,
name: flow.name,
status: flow.active ? 'published' : 'draft',
steps: steps.map((step) => ({
appKey: step.appKey,
iconUrl: step.iconUrl,
id: step.id,
key: step.key,
parameters: step.parameters,
position: step.position,
status: step.status,
type: step.type,
webhookUrl: step.webhookUrl,
})),
};
return {
data: data,
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'Flow',
},
};
};
export default getFlowMock;

View File

@@ -1,19 +0,0 @@
const getAppAuthClientMock = (appAuthClient) => {
return {
data: {
name: appAuthClient.name,
id: appAuthClient.id,
appConfigId: appAuthClient.appConfigId,
active: appAuthClient.active,
},
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'AppAuthClient',
},
};
};
export default getAppAuthClientMock;

View File

@@ -1,14 +0,0 @@
const getInvoicesMock = async (invoices) => {
return {
data: invoices,
meta: {
count: invoices.length,
currentPage: null,
isArray: true,
totalPages: null,
type: 'Object',
},
};
};
export default getInvoicesMock;

View File

@@ -73,7 +73,6 @@ export default defineConfig({
collapsible: true, collapsible: true,
collapsed: true, collapsed: true,
items: [ items: [
{ text: 'Triggers', link: '/apps/dropbox/triggers' },
{ text: 'Actions', link: '/apps/dropbox/actions' }, { text: 'Actions', link: '/apps/dropbox/actions' },
{ text: 'Connection', link: '/apps/dropbox/connection' }, { text: 'Connection', link: '/apps/dropbox/connection' },
], ],
@@ -306,7 +305,7 @@ export default defineConfig({
collapsed: true, collapsed: true,
items: [ items: [
{ text: 'Actions', link: '/apps/removebg/actions' }, { text: 'Actions', link: '/apps/removebg/actions' },
{ text: 'Connection', link: '/apps/removebg/connection' }, { text: 'Connection', link: '/apps/removebg/connection' }
], ],
}, },
{ {

View File

@@ -1,6 +1,8 @@
--- ---
favicon: /favicons/discord.svg favicon: /favicons/discord.svg
items: items:
- name: Change a scheduled event
desc: Changes a scheduled event.
- name: Send a message to channel - name: Send a message to channel
desc: Sends a message to a specific channel you specify. desc: Sends a message to a specific channel you specify.
- name: Create a scheduled event - name: Create a scheduled event

View File

@@ -1,12 +0,0 @@
---
favicon: /favicons/dropbox.svg
items:
- name: New folders
desc: Triggers when any new folder is added. Ensure that the number of files/folders within the monitored directory remains below 4000.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -1742,13 +1742,6 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04"
integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw== integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==
"@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint/eslintrc@^1.0.5": "@eslint/eslintrc@^1.0.5":
version "1.0.5" version "1.0.5"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz"
@@ -3909,11 +3902,6 @@
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/json-schema@^7.0.12":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/json5@^0.0.29": "@types/json5@^0.0.29":
version "0.0.29" version "0.0.29"
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
@@ -4090,11 +4078,6 @@
resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@types/semver@^7.5.0":
version "7.5.8"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
"@types/send@*": "@types/send@*":
version "0.17.1" version "0.17.1"
resolved "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz" resolved "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz"
@@ -4250,14 +4233,6 @@
"@typescript-eslint/types" "5.10.0" "@typescript-eslint/types" "5.10.0"
"@typescript-eslint/visitor-keys" "5.10.0" "@typescript-eslint/visitor-keys" "5.10.0"
"@typescript-eslint/scope-manager@7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz#6ec4cc03752758ddd1fdaae6fbd0ed9a2ca4fe63"
integrity sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==
dependencies:
"@typescript-eslint/types" "7.0.2"
"@typescript-eslint/visitor-keys" "7.0.2"
"@typescript-eslint/type-utils@5.10.0": "@typescript-eslint/type-utils@5.10.0":
version "5.10.0" version "5.10.0"
resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz"
@@ -4272,11 +4247,6 @@
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.0.tgz"
integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ==
"@typescript-eslint/types@7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.0.2.tgz#b6edd108648028194eb213887d8d43ab5750351c"
integrity sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==
"@typescript-eslint/typescript-estree@5.10.0": "@typescript-eslint/typescript-estree@5.10.0":
version "5.10.0" version "5.10.0"
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz"
@@ -4290,20 +4260,6 @@
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz#3c6dc8a3b9799f4ef7eca0d224ded01974e4cb39"
integrity sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==
dependencies:
"@typescript-eslint/types" "7.0.2"
"@typescript-eslint/visitor-keys" "7.0.2"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
minimatch "9.0.3"
semver "^7.5.4"
ts-api-utils "^1.0.1"
"@typescript-eslint/utils@5.10.0": "@typescript-eslint/utils@5.10.0":
version "5.10.0" version "5.10.0"
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.10.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.10.0.tgz"
@@ -4316,19 +4272,6 @@
eslint-scope "^5.1.1" eslint-scope "^5.1.1"
eslint-utils "^3.0.0" eslint-utils "^3.0.0"
"@typescript-eslint/utils@^7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.0.2.tgz#8756123054cd934c8ba7db6a6cffbc654b10b5c4"
integrity sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@types/json-schema" "^7.0.12"
"@types/semver" "^7.5.0"
"@typescript-eslint/scope-manager" "7.0.2"
"@typescript-eslint/types" "7.0.2"
"@typescript-eslint/typescript-estree" "7.0.2"
semver "^7.5.4"
"@typescript-eslint/visitor-keys@5.10.0": "@typescript-eslint/visitor-keys@5.10.0":
version "5.10.0" version "5.10.0"
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz"
@@ -4337,14 +4280,6 @@
"@typescript-eslint/types" "5.10.0" "@typescript-eslint/types" "5.10.0"
eslint-visitor-keys "^3.0.0" eslint-visitor-keys "^3.0.0"
"@typescript-eslint/visitor-keys@7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz#2899b716053ad7094962beb895d11396fc12afc7"
integrity sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==
dependencies:
"@typescript-eslint/types" "7.0.2"
eslint-visitor-keys "^3.4.1"
"@ucast/core@^1.0.0", "@ucast/core@^1.4.1", "@ucast/core@^1.6.1": "@ucast/core@^1.0.0", "@ucast/core@^1.4.1", "@ucast/core@^1.6.1":
version "1.10.2" version "1.10.2"
resolved "https://registry.npmjs.org/@ucast/core/-/core-1.10.2.tgz" resolved "https://registry.npmjs.org/@ucast/core/-/core-1.10.2.tgz"
@@ -7815,11 +7750,6 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint-visitor-keys@^3.4.1:
version "3.4.3"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint-webpack-plugin@^3.1.1: eslint-webpack-plugin@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz" resolved "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz"
@@ -8047,11 +7977,6 @@ expect@^27.4.6:
jest-matcher-utils "^27.4.6" jest-matcher-utils "^27.4.6"
jest-message-util "^27.4.6" jest-message-util "^27.4.6"
express-async-handler@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/express-async-handler/-/express-async-handler-1.2.0.tgz#ffc9896061d90f8d2e71a2d2b8668db5b0934391"
integrity sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w==
express-basic-auth@^1.2.1: express-basic-auth@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz" resolved "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz"
@@ -8770,7 +8695,7 @@ globals@^13.6.0, globals@^13.9.0:
dependencies: dependencies:
type-fest "^0.20.2" type-fest "^0.20.2"
globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4, globby@^11.1.0: globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4:
version "11.1.0" version "11.1.0"
resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
@@ -11107,13 +11032,6 @@ minimatch@3.0.4, minimatch@^3.0.4:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@9.0.3:
version "9.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
dependencies:
brace-expansion "^2.0.1"
minimatch@^5.0.1: minimatch@^5.0.1:
version "5.1.0" version "5.1.0"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz" resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz"
@@ -14209,13 +14127,6 @@ semver@^7.1.1, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semve
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
semver@^7.5.4:
version "7.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
dependencies:
lru-cache "^6.0.0"
send@0.17.2: send@0.17.2:
version "0.17.2" version "0.17.2"
resolved "https://registry.npmjs.org/send/-/send-0.17.2.tgz" resolved "https://registry.npmjs.org/send/-/send-0.17.2.tgz"
@@ -15352,11 +15263,6 @@ tryer@^1.0.1:
resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz" resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
ts-api-utils@^1.0.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b"
integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==
ts-invariant@^0.10.3: ts-invariant@^0.10.3:
version "0.10.3" version "0.10.3"
resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz" resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz"