mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
⚡ Add execution resource
This commit is contained in:
parent
e8ab7d5468
commit
ffdce3b1a2
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -134,7 +134,7 @@
|
||||||
"eslint-plugin-vue": "^7.16.0",
|
"eslint-plugin-vue": "^7.16.0",
|
||||||
"eventsource": "^1.0.7",
|
"eventsource": "^1.0.7",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"express-openapi-validator": "^4.13.7",
|
"express-openapi-validator": "^4.13.6",
|
||||||
"fast-glob": "^3.2.5",
|
"fast-glob": "^3.2.5",
|
||||||
"fflate": "^0.7.0",
|
"fflate": "^0.7.0",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
|
|
66
packages/cli/src/PublicApi/Services/execution.ts
Normal file
66
packages/cli/src/PublicApi/Services/execution.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import { In, Equal, Not, ObjectLiteral, MoreThan, LessThan } from 'typeorm';
|
||||||
|
import { Db, IExecutionFlattedDb } from '../..';
|
||||||
|
import { ExecutionStatus } from '../publicApiRequest';
|
||||||
|
|
||||||
|
function getStatusCondition(status: ExecutionStatus): ObjectLiteral {
|
||||||
|
const condition: ObjectLiteral = {};
|
||||||
|
|
||||||
|
if (status === 'success') {
|
||||||
|
condition.finished = true;
|
||||||
|
} else if (status === 'running') {
|
||||||
|
condition.stoppedAt = Equal(null);
|
||||||
|
} else if (status === 'waiting') {
|
||||||
|
condition.waitTill = Not(null);
|
||||||
|
} else if (status === 'error') {
|
||||||
|
condition.stoppedAt = Not(null);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getExecutions(data: {
|
||||||
|
limit: number;
|
||||||
|
lastId?: number;
|
||||||
|
workflowIds?: number[];
|
||||||
|
status?: ExecutionStatus;
|
||||||
|
}): Promise<IExecutionFlattedDb[]> {
|
||||||
|
const executions = await Db.collections.Execution.find({
|
||||||
|
where: {
|
||||||
|
...(data.lastId && { id: LessThan(data.lastId) }),
|
||||||
|
...(data.status && { ...getStatusCondition(data.status) }),
|
||||||
|
...(data.workflowIds && { workflowId: In(data.workflowIds) }),
|
||||||
|
},
|
||||||
|
order: { id: 'DESC' },
|
||||||
|
take: data.limit,
|
||||||
|
});
|
||||||
|
return executions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getExecutionsCount(data: {
|
||||||
|
limit: number;
|
||||||
|
lastId?: number;
|
||||||
|
workflowIds?: number[];
|
||||||
|
status?: ExecutionStatus;
|
||||||
|
}): Promise<number> {
|
||||||
|
const executions = await Db.collections.Execution.count({
|
||||||
|
where: {
|
||||||
|
id: LessThan(data.lastId),
|
||||||
|
...(data.status && { ...getStatusCondition(data.status) }),
|
||||||
|
...(data.workflowIds && { workflowId: In(data.workflowIds) }),
|
||||||
|
},
|
||||||
|
take: data.limit,
|
||||||
|
});
|
||||||
|
return executions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getExecution(id: number): Promise<IExecutionFlattedDb | undefined> {
|
||||||
|
const execution = await Db.collections.Execution.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return execution;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteExecution(execution: IExecutionFlattedDb): Promise<void> {
|
||||||
|
await Db.collections.Execution.remove(execution);
|
||||||
|
}
|
24
packages/cli/src/PublicApi/Services/workflow.ts
Normal file
24
packages/cli/src/PublicApi/Services/workflow.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { User } from '../../databases/entities/User';
|
||||||
|
import { Db } from '../..';
|
||||||
|
|
||||||
|
export async function getSharedWorkflowIds(user: User): Promise<number[]> {
|
||||||
|
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
||||||
|
where: {
|
||||||
|
user,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return sharedWorkflows.map((workflow) => workflow.workflowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkflowAccess(
|
||||||
|
user: User,
|
||||||
|
workflowId: string | undefined,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const sharedWorkflows = await Db.collections.SharedWorkflow.find({
|
||||||
|
where: {
|
||||||
|
user,
|
||||||
|
workflow: { id: workflowId },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return !!sharedWorkflows.length;
|
||||||
|
}
|
|
@ -4,11 +4,11 @@
|
||||||
/* eslint-disable import/no-cycle */
|
/* eslint-disable import/no-cycle */
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { In } from 'typeorm';
|
|
||||||
import { validate as uuidValidate } from 'uuid';
|
import { validate as uuidValidate } from 'uuid';
|
||||||
import { OpenAPIV3, Format } from 'express-openapi-validator/dist/framework/types';
|
import { OpenAPIV3, Format } from 'express-openapi-validator/dist/framework/types';
|
||||||
import express = require('express');
|
import express = require('express');
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
|
import { In } from 'typeorm';
|
||||||
import { User } from '../databases/entities/User';
|
import { User } from '../databases/entities/User';
|
||||||
import type { Role } from '../databases/entities/Role';
|
import type { Role } from '../databases/entities/Role';
|
||||||
import { ActiveWorkflowRunner, Db, InternalHooksManager, ITelemetryUserDeletionData } from '..';
|
import { ActiveWorkflowRunner, Db, InternalHooksManager, ITelemetryUserDeletionData } from '..';
|
||||||
|
@ -18,39 +18,57 @@ import { SharedWorkflow } from '../databases/entities/SharedWorkflow';
|
||||||
import { SharedCredentials } from '../databases/entities/SharedCredentials';
|
import { SharedCredentials } from '../databases/entities/SharedCredentials';
|
||||||
import { WorkflowEntity } from '../databases/entities/WorkflowEntity';
|
import { WorkflowEntity } from '../databases/entities/WorkflowEntity';
|
||||||
|
|
||||||
interface IPaginationOffsetDecoded {
|
|
||||||
offset: number;
|
|
||||||
limit: number;
|
|
||||||
}
|
|
||||||
export type OperationID = 'getUsers' | 'getUser';
|
export type OperationID = 'getUsers' | 'getUser';
|
||||||
|
|
||||||
export const decodeCursor = (cursor: string): IPaginationOffsetDecoded => {
|
type PaginationBase = { limit: number };
|
||||||
const { offset, limit } = JSON.parse(Buffer.from(cursor, 'base64').toString());
|
|
||||||
return {
|
type PaginationOffsetDecoded = PaginationBase & { offset: number };
|
||||||
offset,
|
|
||||||
limit,
|
type PaginationCursorDecoded = PaginationBase & { lastId: number };
|
||||||
};
|
|
||||||
|
type OffsetPagination = PaginationBase & { offset: number; numberOfTotalRecords: number };
|
||||||
|
|
||||||
|
type CursorPagination = PaginationBase & { lastId: number; numberOfNextRecords: number };
|
||||||
|
|
||||||
|
export const decodeCursor = (cursor: string): PaginationOffsetDecoded | PaginationCursorDecoded => {
|
||||||
|
return JSON.parse(Buffer.from(cursor, 'base64').toString()) as
|
||||||
|
| PaginationCursorDecoded
|
||||||
|
| PaginationOffsetDecoded;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const encodeNextCursor = (
|
const encodeOffSetPagination = (pagination: OffsetPagination): string | null => {
|
||||||
offset: number,
|
if (pagination.numberOfTotalRecords > pagination.offset + pagination.limit) {
|
||||||
limit: number,
|
|
||||||
numberOfRecords: number,
|
|
||||||
): string | null => {
|
|
||||||
const retrieveRecordsLength = offset + limit;
|
|
||||||
|
|
||||||
if (retrieveRecordsLength < numberOfRecords) {
|
|
||||||
return Buffer.from(
|
return Buffer.from(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
limit,
|
limit: pagination.limit,
|
||||||
offset: offset + limit,
|
offset: pagination.offset + pagination.limit,
|
||||||
}),
|
}),
|
||||||
).toString('base64');
|
).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const encodeCursoPagination = (pagination: CursorPagination): string | null => {
|
||||||
|
if (pagination.numberOfNextRecords) {
|
||||||
|
return Buffer.from(
|
||||||
|
JSON.stringify({
|
||||||
|
lastId: pagination.lastId,
|
||||||
|
limit: pagination.limit,
|
||||||
|
}),
|
||||||
|
).toString('base64');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeNextCursor = (
|
||||||
|
pagination: OffsetPagination | CursorPagination,
|
||||||
|
): string | null => {
|
||||||
|
if ('offset' in pagination) {
|
||||||
|
return encodeOffSetPagination(pagination);
|
||||||
|
}
|
||||||
|
return encodeCursoPagination(pagination);
|
||||||
|
};
|
||||||
|
|
||||||
export const getSelectableProperties = (table: 'user' | 'role'): string[] => {
|
export const getSelectableProperties = (table: 'user' | 'role'): string[] => {
|
||||||
return {
|
return {
|
||||||
user: ['id', 'email', 'firstName', 'lastName', 'createdAt', 'updatedAt', 'isPending'],
|
user: ['id', 'email', 'firstName', 'lastName', 'createdAt', 'updatedAt', 'isPending'],
|
||||||
|
@ -193,13 +211,13 @@ export async function getAllUsersAndCount(data: {
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
}): Promise<[User[], number]> {
|
}): Promise<[User[], number]> {
|
||||||
const users = await Db.collections.User!.find({
|
const users = await Db.collections.User.find({
|
||||||
where: {},
|
where: {},
|
||||||
relations: data?.includeRole ? ['globalRole'] : undefined,
|
relations: data?.includeRole ? ['globalRole'] : undefined,
|
||||||
skip: data.offset,
|
skip: data.offset,
|
||||||
take: data.limit,
|
take: data.limit,
|
||||||
});
|
});
|
||||||
const count = await Db.collections.User!.count();
|
const count = await Db.collections.User.count();
|
||||||
return [users, count];
|
return [users, count];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,9 @@ import type { UserRequest } from '../requests';
|
||||||
import * as UserManagementMailer from '../UserManagement/email/UserManagementMailer';
|
import * as UserManagementMailer from '../UserManagement/email/UserManagementMailer';
|
||||||
|
|
||||||
import { decodeCursor, getGlobalMemberRole } from './helpers';
|
import { decodeCursor, getGlobalMemberRole } from './helpers';
|
||||||
|
import { Role, PaginatatedRequest } from './publicApiRequest';
|
||||||
|
|
||||||
type Role = 'owner' | 'member';
|
export const instanceOwnerSetup = (
|
||||||
|
|
||||||
const instanceOwnerSetup = (
|
|
||||||
req: express.Request,
|
req: express.Request,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
next: express.NextFunction,
|
next: express.NextFunction,
|
||||||
|
@ -36,8 +35,8 @@ const emailSetup = (
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
const authorize =
|
export const authorize =
|
||||||
(role: [Role]) =>
|
(role: Role[]) =>
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction): any => {
|
(req: express.Request, res: express.Response, next: express.NextFunction): any => {
|
||||||
const {
|
const {
|
||||||
globalRole: { name: userRole },
|
globalRole: { name: userRole },
|
||||||
|
@ -76,17 +75,22 @@ const transferingToDeletedUser = (
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
const validCursor = (
|
export const validCursor = (
|
||||||
req: UserRequest.Get,
|
req: PaginatatedRequest,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
next: express.NextFunction,
|
next: express.NextFunction,
|
||||||
): any => {
|
): any => {
|
||||||
if (req.query.cursor) {
|
if (req.query.cursor) {
|
||||||
const { cursor } = req.query;
|
const { cursor } = req.query;
|
||||||
try {
|
try {
|
||||||
const { offset, limit } = decodeCursor(cursor);
|
const paginationData = decodeCursor(cursor);
|
||||||
req.query.offset = offset;
|
if ('offset' in paginationData) {
|
||||||
req.query.limit = limit;
|
req.query.offset = paginationData.offset;
|
||||||
|
req.query.limit = paginationData.limit;
|
||||||
|
} else {
|
||||||
|
req.query.lastId = paginationData.lastId;
|
||||||
|
req.query.limit = paginationData.limit;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
message: 'An invalid cursor was used',
|
message: 'An invalid cursor was used',
|
||||||
|
|
54
packages/cli/src/PublicApi/publicApiRequest.ts
Normal file
54
packages/cli/src/PublicApi/publicApiRequest.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* eslint-disable import/no-cycle */
|
||||||
|
import express from 'express';
|
||||||
|
|
||||||
|
import type { User } from '../databases/entities/User';
|
||||||
|
|
||||||
|
export type ExecutionStatus = 'error' | 'running' | 'success' | 'waiting' | null;
|
||||||
|
|
||||||
|
export type Role = 'owner' | 'member';
|
||||||
|
|
||||||
|
export type AuthlessRequest<
|
||||||
|
RouteParams = {},
|
||||||
|
ResponseBody = {},
|
||||||
|
RequestBody = {},
|
||||||
|
RequestQuery = {},
|
||||||
|
> = express.Request<RouteParams, ResponseBody, RequestBody, RequestQuery>;
|
||||||
|
|
||||||
|
export type AuthenticatedRequest<
|
||||||
|
RouteParams = {},
|
||||||
|
ResponseBody = {},
|
||||||
|
RequestBody = {},
|
||||||
|
RequestQuery = {},
|
||||||
|
> = express.Request<RouteParams, ResponseBody, RequestBody, RequestQuery> & {
|
||||||
|
user: User;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PaginatatedRequest = AuthenticatedRequest<
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
limit?: number;
|
||||||
|
cursor?: string;
|
||||||
|
offset?: number;
|
||||||
|
lastId?: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
export declare namespace ExecutionRequest {
|
||||||
|
type GetAll = AuthenticatedRequest<
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
status?: ExecutionStatus;
|
||||||
|
limit?: number;
|
||||||
|
cursor?: string;
|
||||||
|
offset?: number;
|
||||||
|
workflowId?: number;
|
||||||
|
lastId?: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
type Get = AuthenticatedRequest<{ executionId: number }, {}, {}, {}>;
|
||||||
|
type Delete = Get;
|
||||||
|
}
|
129
packages/cli/src/PublicApi/v1/handlers/Executions.ts
Normal file
129
packages/cli/src/PublicApi/v1/handlers/Executions.ts
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import express = require('express');
|
||||||
|
|
||||||
|
import { ExecutionRequest } from '../../publicApiRequest';
|
||||||
|
import { encodeNextCursor } from '../../helpers';
|
||||||
|
import { authorize, instanceOwnerSetup, validCursor } from '../../middlewares';
|
||||||
|
import {
|
||||||
|
getExecutions,
|
||||||
|
getExecution,
|
||||||
|
deleteExecution,
|
||||||
|
getExecutionsCount,
|
||||||
|
} from '../../Services/execution';
|
||||||
|
import { getSharedWorkflowIds, getWorkflowAccess } from '../../Services/workflow';
|
||||||
|
|
||||||
|
export = {
|
||||||
|
deleteExecution: [
|
||||||
|
instanceOwnerSetup,
|
||||||
|
authorize(['owner', 'member']),
|
||||||
|
async (req: ExecutionRequest.Delete, res: express.Response): Promise<express.Response> => {
|
||||||
|
const { executionId } = req.params;
|
||||||
|
|
||||||
|
const execution = await getExecution(executionId);
|
||||||
|
if (execution === undefined) {
|
||||||
|
return res.status(404).json({
|
||||||
|
message: 'Execution not found.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.user.globalRole.name === 'owner') {
|
||||||
|
await deleteExecution(execution);
|
||||||
|
return res.json(execution);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userHasAccessToWorkflow = await getWorkflowAccess(req.user, execution.workflowId);
|
||||||
|
|
||||||
|
if (userHasAccessToWorkflow) {
|
||||||
|
await deleteExecution(execution);
|
||||||
|
return res.json(execution);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(404).json({
|
||||||
|
message: 'Execution not found.',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
getExecution: [
|
||||||
|
instanceOwnerSetup,
|
||||||
|
authorize(['owner', 'member']),
|
||||||
|
async (req: ExecutionRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||||
|
const { executionId } = req.params;
|
||||||
|
|
||||||
|
const execution = await getExecution(executionId);
|
||||||
|
if (execution === undefined) {
|
||||||
|
return res.status(404).json({
|
||||||
|
message: 'Execution not found.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.user.globalRole.name === 'owner') {
|
||||||
|
return res.json(execution);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userHasAccessToWorkflow = await getWorkflowAccess(req.user, execution.workflowId);
|
||||||
|
|
||||||
|
if (userHasAccessToWorkflow) {
|
||||||
|
return res.json(execution);
|
||||||
|
}
|
||||||
|
return res.status(404).json({
|
||||||
|
message: 'Execution not found.',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
getExecutions: [
|
||||||
|
instanceOwnerSetup,
|
||||||
|
authorize(['owner', 'member']),
|
||||||
|
validCursor,
|
||||||
|
async (req: ExecutionRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
||||||
|
const {
|
||||||
|
lastId = undefined,
|
||||||
|
limit = 100,
|
||||||
|
status = undefined,
|
||||||
|
workflowId = undefined,
|
||||||
|
} = req.query;
|
||||||
|
|
||||||
|
const filters = {
|
||||||
|
status,
|
||||||
|
limit,
|
||||||
|
lastId,
|
||||||
|
...(workflowId && { workflowIds: [workflowId] }),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (req.user.globalRole.name === 'owner') {
|
||||||
|
const executions = await getExecutions(filters);
|
||||||
|
|
||||||
|
filters.lastId = executions.slice(-1)[0].id as number;
|
||||||
|
|
||||||
|
const count = await getExecutionsCount(filters);
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
data: executions,
|
||||||
|
nextCursor: encodeNextCursor({
|
||||||
|
lastId: filters.lastId,
|
||||||
|
limit,
|
||||||
|
numberOfNextRecords: count,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharedWorkflowsIds = [];
|
||||||
|
|
||||||
|
if (!workflowId) {
|
||||||
|
const sharedWorkflows = await getSharedWorkflowIds(req.user);
|
||||||
|
sharedWorkflowsIds.push(...sharedWorkflows);
|
||||||
|
}
|
||||||
|
|
||||||
|
const executions = await getExecutions(filters);
|
||||||
|
|
||||||
|
const count = await getExecutionsCount(filters);
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
data: executions,
|
||||||
|
nextCursor: encodeNextCursor({
|
||||||
|
lastId: executions.slice(-1)[0].id as number,
|
||||||
|
limit,
|
||||||
|
numberOfNextRecords: count,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -135,7 +135,11 @@ export = {
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
data: clean(users, { includeRole }),
|
data: clean(users, { includeRole }),
|
||||||
nextCursor: encodeNextCursor(offset, limit, count),
|
nextCursor: encodeNextCursor({
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
numberOfTotalRecords: count,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -18,8 +18,43 @@ servers:
|
||||||
tags:
|
tags:
|
||||||
- name: User
|
- name: User
|
||||||
description: Operations about user
|
description: Operations about user
|
||||||
|
- name: Execution
|
||||||
|
description: Operations about execution
|
||||||
paths:
|
paths:
|
||||||
/users:
|
/users:
|
||||||
|
post:
|
||||||
|
x-eov-operation-id: createUsers
|
||||||
|
x-eov-operation-handler: v1/handlers/Users
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
summary: Invite a user
|
||||||
|
description: Invites a user to your instance. Only available for the instance owner.
|
||||||
|
operationId: createUser
|
||||||
|
requestBody:
|
||||||
|
description: Created user object.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserInformation'
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: A User object
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserInformation'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
|
||||||
get:
|
get:
|
||||||
x-eov-operation-id: getUsers
|
x-eov-operation-id: getUsers
|
||||||
x-eov-operation-handler: v1/handlers/Users
|
x-eov-operation-handler: v1/handlers/Users
|
||||||
|
@ -66,38 +101,6 @@ paths:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Error'
|
$ref: '#/components/schemas/Error'
|
||||||
post:
|
|
||||||
x-eov-operation-id: createUsers
|
|
||||||
x-eov-operation-handler: v1/handlers/Users
|
|
||||||
tags:
|
|
||||||
- User
|
|
||||||
summary: Invite a user
|
|
||||||
description: Invites a user to your instance. Only available for the instance owner.
|
|
||||||
operationId: createUser
|
|
||||||
requestBody:
|
|
||||||
description: Created user object.
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/UserInformation'
|
|
||||||
required: true
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: A User object
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/components/schemas/UserInformation'
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/Error'
|
|
||||||
/users/{identifier}:
|
/users/{identifier}:
|
||||||
get:
|
get:
|
||||||
x-eov-operation-id: getUser
|
x-eov-operation-id: getUser
|
||||||
|
@ -177,6 +180,121 @@ paths:
|
||||||
$ref: '#/components/schemas/Error'
|
$ref: '#/components/schemas/Error'
|
||||||
"404":
|
"404":
|
||||||
description: User not found
|
description: User not found
|
||||||
|
/executions:
|
||||||
|
get:
|
||||||
|
x-eov-operation-id: getExecutions
|
||||||
|
x-eov-operation-handler: v1/handlers/Executions
|
||||||
|
tags:
|
||||||
|
- Execution
|
||||||
|
summary: Retrieve all executions
|
||||||
|
description: Retrieve all executions from your instance.
|
||||||
|
parameters:
|
||||||
|
- name: status
|
||||||
|
in: query
|
||||||
|
description: Status to filter the executions by.
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum: ['error', 'running', 'success', 'waiting']
|
||||||
|
default: 'any'
|
||||||
|
- name: workflowId
|
||||||
|
in: query
|
||||||
|
description: Workflow to filter the executions by.
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
example: 1000
|
||||||
|
- name: limit
|
||||||
|
in: query
|
||||||
|
description: The maximum number of items to return.
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
example: 100
|
||||||
|
default: 100
|
||||||
|
- name: cursor
|
||||||
|
in: query
|
||||||
|
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request's response. Default value fetches the first "page" of the collection. See pagination for more detail.
|
||||||
|
required: false
|
||||||
|
style: form
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Operation successful.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ExecutionDetailsResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
/executions/{executionId}:
|
||||||
|
get:
|
||||||
|
x-eov-operation-id: getExecution
|
||||||
|
x-eov-operation-handler: v1/handlers/Executions
|
||||||
|
tags:
|
||||||
|
- Execution
|
||||||
|
summary: Retrieve an execution
|
||||||
|
description: Retrieve an execution from you instance.
|
||||||
|
parameters:
|
||||||
|
- name: executionId
|
||||||
|
in: path
|
||||||
|
description: The ID of the execution.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Operation successful.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ExecutionInformation'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
delete:
|
||||||
|
x-eov-operation-id: deleteExecution
|
||||||
|
x-eov-operation-handler: v1/handlers/Executions
|
||||||
|
tags:
|
||||||
|
- Execution
|
||||||
|
summary: Delete an execution
|
||||||
|
description: Deletes an execution from your instance.
|
||||||
|
parameters:
|
||||||
|
- name: executionId
|
||||||
|
in: path
|
||||||
|
description: The ID of the execution to be deleted.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Operation successful.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ExecutionInformation'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
Error:
|
Error:
|
||||||
|
@ -233,6 +351,18 @@ components:
|
||||||
readOnly: true
|
readOnly: true
|
||||||
globalRole:
|
globalRole:
|
||||||
$ref: '#/components/schemas/RoleInformation'
|
$ref: '#/components/schemas/RoleInformation'
|
||||||
|
ExecutionDetailsResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ExecutionInformation'
|
||||||
|
nextCursor:
|
||||||
|
type: string
|
||||||
|
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
|
||||||
|
nullable: true
|
||||||
|
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||||
UserDetailsResponse:
|
UserDetailsResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -245,6 +375,39 @@ components:
|
||||||
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
|
description: Paginate through users by setting the cursor parameter to a nextCursor attribute returned by a previous request. Default value fetches the first "page" of the collection.
|
||||||
nullable: true
|
nullable: true
|
||||||
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
example: MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDA
|
||||||
|
ExecutionInformation:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: number
|
||||||
|
example: 1000
|
||||||
|
data:
|
||||||
|
type: string
|
||||||
|
finished:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
mode:
|
||||||
|
type: string
|
||||||
|
enum: ['cli', 'error', 'integrated', 'internal', 'manual', 'retry', 'trigger', 'webhook']
|
||||||
|
retryOf:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
retrySuccessId:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
startedAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
stoppedAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
workflowId:
|
||||||
|
type: string
|
||||||
|
example: 1000
|
||||||
|
waitTill:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
format: date-time
|
||||||
RoleInformation:
|
RoleInformation:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
Loading…
Reference in a new issue