refactor(core): Use Dependency Injection for all Controller classes (no-changelog) (#8146)
## Review / Merge checklist - [x] PR title and summary are descriptive
This commit is contained in:
committed by
GitHub
parent
518a99e528
commit
f69ddcd796
@@ -1,9 +1,7 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Authorized, Get, RestController } from '@/decorators';
|
||||
import { WorkflowRequest } from '@/requests';
|
||||
import { ActiveWorkflowsService } from '@/services/activeWorkflows.service';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/active-workflows')
|
||||
export class ActiveWorkflowsController {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import validator from 'validator';
|
||||
import { In } from 'typeorm';
|
||||
import { Service } from 'typedi';
|
||||
import { Authorized, Get, Post, RestController } from '@/decorators';
|
||||
import { issueCookie, resolveJwt } from '@/auth/jwt';
|
||||
import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
@@ -27,7 +26,6 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
@Service()
|
||||
@RestController()
|
||||
export class AuthController {
|
||||
constructor(
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { Service } from 'typedi';
|
||||
import express from 'express';
|
||||
import { BinaryDataService, FileNotFoundError, isValidNonDefaultMode } from 'n8n-core';
|
||||
import { Get, RestController } from '@/decorators';
|
||||
import { BinaryDataRequest } from '@/requests';
|
||||
|
||||
@RestController('/binary-data')
|
||||
@Service()
|
||||
export class BinaryDataController {
|
||||
constructor(private readonly binaryDataService: BinaryDataService) {}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import config from '@/config';
|
||||
import {
|
||||
@@ -42,14 +41,13 @@ export function isNpmError(error: unknown): error is { code: number; stdout: str
|
||||
return typeof error === 'object' && error !== null && 'code' in error && 'stdout' in error;
|
||||
}
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/community-packages')
|
||||
export class CommunityPackagesController {
|
||||
constructor(
|
||||
private push: Push,
|
||||
private internalHooks: InternalHooks,
|
||||
private communityPackagesService: CommunityPackagesService,
|
||||
private readonly push: Push,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly communityPackagesService: CommunityPackagesService,
|
||||
) {}
|
||||
|
||||
// TODO: move this into a new decorator `@IfConfig('executions.mode', 'queue')`
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Get, RestController } from '@/decorators';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee';
|
||||
@@ -6,7 +5,6 @@ import { WorkflowRepository } from '@/databases/repositories/workflow.repository
|
||||
import { In } from 'typeorm';
|
||||
|
||||
@RestController('/debug')
|
||||
@Service()
|
||||
export class DebugController {
|
||||
constructor(
|
||||
private readonly multiMainSetup: MultiMainSetup,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import type { RequestHandler } from 'express';
|
||||
import { NextFunction, Response } from 'express';
|
||||
import type {
|
||||
@@ -22,7 +21,6 @@ const assertMethodName: RequestHandler = (req, res, next) => {
|
||||
next();
|
||||
};
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/dynamic-node-parameters')
|
||||
export class DynamicNodeParametersController {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Request } from 'express';
|
||||
import { Container, Service } from 'typedi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import config from '@/config';
|
||||
import type { Role } from '@db/entities/Role';
|
||||
@@ -64,7 +63,6 @@ type PushRequest = Request<
|
||||
}
|
||||
>;
|
||||
|
||||
@Service()
|
||||
@NoAuthRequired()
|
||||
@RestController('/e2e')
|
||||
export class E2EController {
|
||||
@@ -89,12 +87,13 @@ export class E2EController {
|
||||
|
||||
constructor(
|
||||
license: License,
|
||||
private roleRepo: RoleRepository,
|
||||
private settingsRepo: SettingsRepository,
|
||||
private userRepo: UserRepository,
|
||||
private workflowRunner: ActiveWorkflowRunner,
|
||||
private mfaService: MfaService,
|
||||
private cacheService: CacheService,
|
||||
private readonly roleRepo: RoleRepository,
|
||||
private readonly settingsRepo: SettingsRepository,
|
||||
private readonly userRepo: UserRepository,
|
||||
private readonly workflowRunner: ActiveWorkflowRunner,
|
||||
private readonly mfaService: MfaService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly push: Push,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
) {
|
||||
license.isFeatureEnabled = (feature: BooleanLicenseFeature) =>
|
||||
@@ -112,14 +111,8 @@ export class E2EController {
|
||||
}
|
||||
|
||||
@Post('/push')
|
||||
async push(req: PushRequest) {
|
||||
const pushInstance = Container.get(Push);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const sessionId = Object.keys(pushInstance.getBackend().connections as object)[0];
|
||||
|
||||
pushInstance.send(req.body.type, req.body.data, sessionId);
|
||||
async pushSend(req: PushRequest) {
|
||||
this.push.broadcast(req.body.type, req.body.data);
|
||||
}
|
||||
|
||||
@Patch('/feature')
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { In } from 'typeorm';
|
||||
import Container, { Service } from 'typedi';
|
||||
import { Response } from 'express';
|
||||
|
||||
import config from '@/config';
|
||||
import { Authorized, NoAuthRequired, Post, RequireGlobalScope, RestController } from '@/decorators';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { Response } from 'express';
|
||||
import { UserRequest } from '@/requests';
|
||||
import { Config } from '@/config';
|
||||
import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||
import { License } from '@/License';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { Logger } from '@/Logger';
|
||||
@@ -17,20 +16,20 @@ import type { User } from '@/databases/entities/User';
|
||||
import validator from 'validator';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/invitations')
|
||||
export class InvitationController {
|
||||
constructor(
|
||||
private readonly config: Config,
|
||||
private readonly logger: Logger,
|
||||
private readonly internalHooks: IInternalHooksClass,
|
||||
private readonly externalHooks: IExternalHooksClass,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly externalHooks: ExternalHooks,
|
||||
private readonly userService: UserService,
|
||||
private readonly license: License,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly postHog?: PostHogClient,
|
||||
private readonly postHog: PostHogClient,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -40,7 +39,7 @@ export class InvitationController {
|
||||
@Post('/')
|
||||
@RequireGlobalScope('user:create')
|
||||
async inviteUser(req: UserRequest.Invite) {
|
||||
const isWithinUsersLimit = Container.get(License).isWithinUsersLimit();
|
||||
const isWithinUsersLimit = this.license.isWithinUsersLimit();
|
||||
|
||||
if (isSamlLicensedAndEnabled()) {
|
||||
this.logger.debug(
|
||||
@@ -58,7 +57,7 @@ export class InvitationController {
|
||||
throw new UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED);
|
||||
}
|
||||
|
||||
if (!this.config.getEnv('userManagement.isInstanceOwnerSetUp')) {
|
||||
if (!config.getEnv('userManagement.isInstanceOwnerSetUp')) {
|
||||
this.logger.debug(
|
||||
'Request to send email invite(s) to user(s) failed because the owner account is not set up',
|
||||
);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import pick from 'lodash/pick';
|
||||
import { Authorized, Get, Post, Put, RestController, RequireGlobalScope } from '@/decorators';
|
||||
import { getLdapConfig, getLdapSynchronizations, updateLdapConfig } from '@/Ldap/helpers';
|
||||
import { LdapService } from '@/Ldap/LdapService.ee';
|
||||
import { LdapSync } from '@/Ldap/LdapSync.ee';
|
||||
import { LdapManager } from '@/Ldap/LdapManager.ee';
|
||||
import type { LdapService } from '@/Ldap/LdapService.ee';
|
||||
import type { LdapSync } from '@/Ldap/LdapSync.ee';
|
||||
import { LdapConfiguration } from '@/Ldap/types';
|
||||
import { NON_SENSIBLE_LDAP_CONFIG_PROPERTIES } from '@/Ldap/constants';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
@@ -11,11 +12,15 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
@Authorized()
|
||||
@RestController('/ldap')
|
||||
export class LdapController {
|
||||
constructor(
|
||||
private ldapService: LdapService,
|
||||
private ldapSync: LdapSync,
|
||||
private internalHooks: InternalHooks,
|
||||
) {}
|
||||
private ldapService: LdapService;
|
||||
|
||||
private ldapSync: LdapSync;
|
||||
|
||||
constructor(private readonly internalHooks: InternalHooks) {
|
||||
const { service, sync } = LdapManager.getInstance();
|
||||
this.ldapService = service;
|
||||
this.ldapSync = sync;
|
||||
}
|
||||
|
||||
@Get('/config')
|
||||
@RequireGlobalScope('ldap:manage')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import validator from 'validator';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { Response } from 'express';
|
||||
import { Service } from 'typedi';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { Authorized, Delete, Get, Patch, Post, RestController } from '@/decorators';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
@@ -22,7 +21,6 @@ import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/me')
|
||||
export class MeController {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Authorized, Delete, Get, Post, RestController } from '@/decorators';
|
||||
import { AuthenticatedRequest, MFA } from '@/requests';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/mfa')
|
||||
export class MFAController {
|
||||
|
||||
@@ -3,22 +3,19 @@ import get from 'lodash/get';
|
||||
import { Request } from 'express';
|
||||
import type { INodeTypeDescription, INodeTypeNameVersion } from 'n8n-workflow';
|
||||
import { Authorized, Post, RestController } from '@/decorators';
|
||||
import { Config } from '@/config';
|
||||
import config from '@/config';
|
||||
import { NodeTypes } from '@/NodeTypes';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/node-types')
|
||||
export class NodeTypesController {
|
||||
constructor(
|
||||
private readonly config: Config,
|
||||
private readonly nodeTypes: NodeTypes,
|
||||
) {}
|
||||
constructor(private readonly nodeTypes: NodeTypes) {}
|
||||
|
||||
@Post('/')
|
||||
async getNodeInfo(req: Request) {
|
||||
const nodeInfos = get(req, 'body.nodeInfos', []) as INodeTypeNameVersion[];
|
||||
|
||||
const defaultLocale = this.config.getEnv('defaultLocale');
|
||||
const defaultLocale = config.getEnv('defaultLocale');
|
||||
|
||||
if (defaultLocale === 'en') {
|
||||
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Response } from 'express';
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import axios from 'axios';
|
||||
@@ -30,7 +29,6 @@ const algorithmMap = {
|
||||
/* eslint-enable */
|
||||
} as const;
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/oauth1-credential')
|
||||
export class OAuth1CredentialController extends AbstractOAuthController {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import type { ClientOAuth2Options } from '@n8n/client-oauth2';
|
||||
import { ClientOAuth2 } from '@n8n/client-oauth2';
|
||||
import Csrf from 'csrf';
|
||||
@@ -31,7 +30,6 @@ interface CsrfStateParam {
|
||||
token: string;
|
||||
}
|
||||
|
||||
@Service()
|
||||
@Authorized()
|
||||
@RestController('/oauth2-credential')
|
||||
export class OAuth2CredentialController extends AbstractOAuthController {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { Authorized, Post, RestController, RequireGlobalScope } from '@/decorators';
|
||||
import { OrchestrationRequest } from '@/requests';
|
||||
import { Service } from 'typedi';
|
||||
import { SingleMainSetup } from '@/services/orchestration/main/SingleMainSetup';
|
||||
import { License } from '../License';
|
||||
import { License } from '@/License';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/orchestration')
|
||||
@Service()
|
||||
export class OrchestrationController {
|
||||
constructor(
|
||||
private readonly singleMainSetup: SingleMainSetup,
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import validator from 'validator';
|
||||
import { Response } from 'express';
|
||||
|
||||
import config from '@/config';
|
||||
import { validateEntity } from '@/GenericHelpers';
|
||||
import { Authorized, Post, RestController } from '@/decorators';
|
||||
import { PasswordUtility } from '@/services/password.utility';
|
||||
import { issueCookie } from '@/auth/jwt';
|
||||
import { Response } from 'express';
|
||||
import { Config } from '@/config';
|
||||
import { OwnerRequest } from '@/requests';
|
||||
import { IInternalHooksClass } from '@/Interfaces';
|
||||
import { SettingsRepository } from '@db/repositories/settings.repository';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
|
||||
@Authorized(['global', 'owner'])
|
||||
@RestController('/owner')
|
||||
export class OwnerController {
|
||||
constructor(
|
||||
private readonly config: Config,
|
||||
private readonly logger: Logger,
|
||||
private readonly internalHooks: IInternalHooksClass,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly settingsRepository: SettingsRepository,
|
||||
private readonly userService: UserService,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly postHog?: PostHogClient,
|
||||
private readonly postHog: PostHogClient,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ export class OwnerController {
|
||||
const { email, firstName, lastName, password } = req.body;
|
||||
const { id: userId, globalRole } = req.user;
|
||||
|
||||
if (this.config.getEnv('userManagement.isInstanceOwnerSetUp')) {
|
||||
if (config.getEnv('userManagement.isInstanceOwnerSetUp')) {
|
||||
this.logger.debug(
|
||||
'Request to claim instance ownership failed because instance owner already exists',
|
||||
{
|
||||
@@ -94,7 +94,7 @@ export class OwnerController {
|
||||
{ value: JSON.stringify(true) },
|
||||
);
|
||||
|
||||
this.config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', true);
|
||||
|
||||
this.logger.debug('Setting isInstanceOwnerSetUp updated successfully', { userId });
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Response } from 'express';
|
||||
import { rateLimit } from 'express-rate-limit';
|
||||
import { Service } from 'typedi';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import validator from 'validator';
|
||||
|
||||
@@ -31,7 +30,6 @@ const throttle = rateLimit({
|
||||
message: { message: 'Too many requests' },
|
||||
});
|
||||
|
||||
@Service()
|
||||
@RestController()
|
||||
export class PasswordResetController {
|
||||
constructor(
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { License } from '@/License';
|
||||
import { Get, RestController } from '@/decorators';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { Service } from 'typedi';
|
||||
|
||||
@Service()
|
||||
@RestController('/roles')
|
||||
export class RoleController {
|
||||
constructor(
|
||||
|
||||
@@ -12,16 +12,14 @@ import {
|
||||
} from '@/decorators';
|
||||
import { TagService } from '@/services/tag.service';
|
||||
import { TagsRequest } from '@/requests';
|
||||
import { Service } from 'typedi';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/tags')
|
||||
@Service()
|
||||
export class TagsController {
|
||||
private config = config;
|
||||
|
||||
constructor(private tagService: TagService) {}
|
||||
constructor(private readonly tagService: TagService) {}
|
||||
|
||||
// TODO: move this into a new decorator `@IfEnabled('workflowTagsDisabled')`
|
||||
@Middleware()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Request } from 'express';
|
||||
import { ICredentialTypes } from 'n8n-workflow';
|
||||
import { join } from 'path';
|
||||
import { access } from 'fs/promises';
|
||||
import { Authorized, Get, RestController } from '@/decorators';
|
||||
import { Config } from '@/config';
|
||||
import config from '@/config';
|
||||
import { NODES_BASE_DIR } from '@/constants';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { CredentialTypes } from '@/CredentialTypes';
|
||||
|
||||
export const CREDENTIAL_TRANSLATIONS_DIR = 'n8n-nodes-base/dist/credentials/translations';
|
||||
export const NODE_HEADERS_PATH = join(NODES_BASE_DIR, 'dist/nodes/headers');
|
||||
@@ -18,10 +18,7 @@ export declare namespace TranslationRequest {
|
||||
@Authorized()
|
||||
@RestController('/')
|
||||
export class TranslationController {
|
||||
constructor(
|
||||
private config: Config,
|
||||
private credentialTypes: ICredentialTypes,
|
||||
) {}
|
||||
constructor(private readonly credentialTypes: CredentialTypes) {}
|
||||
|
||||
@Get('/credential-translation')
|
||||
async getCredentialTranslation(req: TranslationRequest.Credential) {
|
||||
@@ -30,7 +27,7 @@ export class TranslationController {
|
||||
if (!this.credentialTypes.recognizes(credentialType))
|
||||
throw new BadRequestError(`Invalid Credential type: "${credentialType}"`);
|
||||
|
||||
const defaultLocale = this.config.getEnv('defaultLocale');
|
||||
const defaultLocale = config.getEnv('defaultLocale');
|
||||
const translationPath = join(
|
||||
CREDENTIAL_TRANSLATIONS_DIR,
|
||||
defaultLocale,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { SharedWorkflow } from '@db/entities/SharedWorkflow';
|
||||
import { RequireGlobalScope, Authorized, Delete, Get, RestController, Patch } from '@/decorators';
|
||||
import { ListQuery, UserRequest, UserSettingsUpdatePayload } from '@/requests';
|
||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||
import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces';
|
||||
import type { PublicUser, ITelemetryUserDeletionData } from '@/Interfaces';
|
||||
import { AuthIdentity } from '@db/entities/AuthIdentity';
|
||||
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
|
||||
@@ -20,14 +19,16 @@ import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { License } from '@/License';
|
||||
import { ExternalHooks } from '@/ExternalHooks';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
|
||||
@Authorized()
|
||||
@RestController('/users')
|
||||
export class UsersController {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly externalHooks: IExternalHooksClass,
|
||||
private readonly internalHooks: IInternalHooksClass,
|
||||
private readonly externalHooks: ExternalHooks,
|
||||
private readonly internalHooks: InternalHooks,
|
||||
private readonly sharedCredentialsRepository: SharedCredentialsRepository,
|
||||
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private readonly activeWorkflowRunner: ActiveWorkflowRunner,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Service } from 'typedi';
|
||||
import { Response, NextFunction } from 'express';
|
||||
import { Get, Middleware, RestController } from '@/decorators';
|
||||
import type { WorkflowStatistics } from '@db/entities/WorkflowStatistics';
|
||||
@@ -18,12 +17,11 @@ interface WorkflowStatisticsData<T> {
|
||||
manualError: T;
|
||||
}
|
||||
|
||||
@Service()
|
||||
@RestController('/workflow-stats')
|
||||
export class WorkflowStatisticsController {
|
||||
constructor(
|
||||
private sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private workflowStatisticsRepository: WorkflowStatisticsRepository,
|
||||
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private readonly workflowStatisticsRepository: WorkflowStatisticsRepository,
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user