diff --git a/packages/cli/src/license/license.controller.ts b/packages/cli/src/license/license.controller.ts index c9b70609d3..1c0ca8c0d6 100644 --- a/packages/cli/src/license/license.controller.ts +++ b/packages/cli/src/license/license.controller.ts @@ -1,5 +1,5 @@ import { Get, Post, RestController, GlobalScope } from '@/decorators'; -import { LicenseRequest } from '@/requests'; +import { AuthenticatedRequest, LicenseRequest } from '@/requests'; import { LicenseService } from './license.service'; @RestController('/license') @@ -11,6 +11,12 @@ export class LicenseController { return await this.licenseService.getLicenseData(); } + @Post('/enterprise/request_trial') + @GlobalScope('license:manage') + async requestEnterpriseTrial(req: AuthenticatedRequest) { + await this.licenseService.requestEnterpriseTrial(req.user); + } + @Post('/activate') @GlobalScope('license:manage') async activateLicense(req: LicenseRequest.Activate) { diff --git a/packages/cli/src/license/license.service.ts b/packages/cli/src/license/license.service.ts index 32d30b16c5..543b953737 100644 --- a/packages/cli/src/license/license.service.ts +++ b/packages/cli/src/license/license.service.ts @@ -1,9 +1,13 @@ import { Service } from 'typedi'; +import axios from 'axios'; + import { Logger } from '@/Logger'; import { License } from '@/License'; import { InternalHooks } from '@/InternalHooks'; +import type { User } from '@db/entities/User'; import { WorkflowRepository } from '@db/repositories/workflow.repository'; import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { UrlService } from '@/services/url.service'; type LicenseError = Error & { errorId?: keyof typeof LicenseErrors }; @@ -24,6 +28,7 @@ export class LicenseService { private readonly license: License, private readonly internalHooks: InternalHooks, private readonly workflowRepository: WorkflowRepository, + private readonly urlService: UrlService, ) {} async getLicenseData() { @@ -45,6 +50,16 @@ export class LicenseService { }; } + async requestEnterpriseTrial(user: User) { + await axios.post('https://enterprise.n8n.io/enterprise-trial', { + licenseType: 'enterprise', + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + instanceUrl: this.urlService.getWebhookBaseUrl(), + }); + } + getManagementJwt(): string { return this.license.getManagementJwt(); } diff --git a/packages/cli/test/integration/license.api.test.ts b/packages/cli/test/integration/license.api.test.ts index f00404953b..d5e434b3c8 100644 --- a/packages/cli/test/integration/license.api.test.ts +++ b/packages/cli/test/integration/license.api.test.ts @@ -1,3 +1,4 @@ +import nock from 'nock'; import config from '@/config'; import { RESPONSE_ERROR_MESSAGES } from '@/constants'; import type { User } from '@db/entities/User'; @@ -47,6 +48,20 @@ describe('GET /license', () => { }); }); +describe('POST /license/enterprise/request_trial', () => { + nock('https://enterprise.n8n.io').post('/enterprise-trial').reply(200); + + test('should work for instance owner', async () => { + await authOwnerAgent.post('/license/enterprise/request_trial').expect(200); + }); + + test('does not work for regular users', async () => { + await authMemberAgent + .post('/license/enterprise/request_trial') + .expect(403, { status: 'error', message: RESPONSE_ERROR_MESSAGES.MISSING_SCOPE }); + }); +}); + describe('POST /license/activate', () => { test('should work for instance owner', async () => { await authOwnerAgent diff --git a/packages/editor-ui/src/api/usage.ts b/packages/editor-ui/src/api/usage.ts index 77ce3e3e1a..321d05131a 100644 --- a/packages/editor-ui/src/api/usage.ts +++ b/packages/editor-ui/src/api/usage.ts @@ -1,4 +1,4 @@ -import { makeRestApiRequest, request } from '@/utils/apiUtils'; +import { makeRestApiRequest } from '@/utils/apiUtils'; import type { IRestApiContext, UsageState } from '@/Interface'; export const getLicense = async (context: IRestApiContext): Promise => { @@ -16,21 +16,8 @@ export const renewLicense = async (context: IRestApiContext): Promise => { - return await request({ - method: 'POST', - baseURL: 'https://enterprise.n8n.io', - endpoint: '/enterprise-trial', - data, - withCredentials: false, - headers: { - 'Content-Type': 'application/json', - }, - }); +export const requestLicenseTrial = async ( + context: IRestApiContext, +): Promise => { + return await makeRestApiRequest(context, 'POST', '/license/enterprise/request_trial'); }; diff --git a/packages/editor-ui/src/stores/usage.store.ts b/packages/editor-ui/src/stores/usage.store.ts index 2f9251a846..30e2a60ea6 100644 --- a/packages/editor-ui/src/stores/usage.store.ts +++ b/packages/editor-ui/src/stores/usage.store.ts @@ -85,19 +85,7 @@ export const useUsageStore = defineStore('usage', () => { }; const requestEnterpriseLicenseTrial = async () => { - if (!usersStore.currentUser) { - throw new Error('User is not logged in'); - } - - const data = await requestLicenseTrial({ - licenseType: 'enterprise', - firstName: usersStore.currentUser.firstName ?? '', - lastName: usersStore.currentUser.lastName ?? '', - email: usersStore.currentUser.email ?? '', - instanceUrl: window.location.origin, - }); - - return data; + await requestLicenseTrial(rootStore.getRestApiContext); }; return {