mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-24 23:22:38 +08:00
chore(core): Update workflow status endpoint to use absolute URL (#23285)
This commit is contained in:
+43
-4
@@ -5,10 +5,14 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { WorkflowStatusController } from '../workflow-status.controller';
|
||||
import type { CredentialResolverWorkflowService } from '../services/credential-resolver-workflow.service';
|
||||
import { UnauthenticatedError } from '@/errors/response-errors/unauthenticated.error';
|
||||
import type { UrlService } from '@/services/url.service';
|
||||
import type { GlobalConfig } from '@n8n/config';
|
||||
|
||||
describe('WorkflowStatusController', () => {
|
||||
let controller: WorkflowStatusController;
|
||||
let mockService: jest.Mocked<CredentialResolverWorkflowService>;
|
||||
let mockUrlService: jest.Mocked<UrlService>;
|
||||
let mockGlobalConfig: jest.Mocked<GlobalConfig>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -17,7 +21,17 @@ describe('WorkflowStatusController', () => {
|
||||
getWorkflowStatus: jest.fn(),
|
||||
} as unknown as jest.Mocked<CredentialResolverWorkflowService>;
|
||||
|
||||
controller = new WorkflowStatusController(mockService);
|
||||
mockUrlService = {
|
||||
getInstanceBaseUrl: jest.fn().mockReturnValue('https://n8n.example.com'),
|
||||
} as unknown as jest.Mocked<UrlService>;
|
||||
|
||||
mockGlobalConfig = {
|
||||
endpoints: {
|
||||
rest: 'rest',
|
||||
},
|
||||
} as unknown as jest.Mocked<GlobalConfig>;
|
||||
|
||||
controller = new WorkflowStatusController(mockService, mockUrlService, mockGlobalConfig);
|
||||
});
|
||||
|
||||
describe('checkWorkflowForExecution', () => {
|
||||
@@ -165,7 +179,7 @@ describe('WorkflowStatusController', () => {
|
||||
const result = await controller.checkWorkflowForExecution(req, res);
|
||||
|
||||
expect(result.credentials?.[0].authorizationUrl).toBe(
|
||||
'/credentials/cred-1/authorize?resolverId=resolver-1',
|
||||
'https://n8n.example.com/rest/credentials/cred-1/authorize?resolverId=resolver-1',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -188,10 +202,34 @@ describe('WorkflowStatusController', () => {
|
||||
const result = await controller.checkWorkflowForExecution(req, res);
|
||||
|
||||
expect(result.credentials?.[0].authorizationUrl).toBe(
|
||||
'/credentials/cred-1/authorize?resolverId=resolver%2Fwith%2Fspecial%20chars',
|
||||
'https://n8n.example.com/rest/credentials/cred-1/authorize?resolverId=resolver%2Fwith%2Fspecial%20chars',
|
||||
);
|
||||
});
|
||||
|
||||
it('should return absolute URLs with base path from UrlService', async () => {
|
||||
const req = mock<Request>({
|
||||
params: { workflowId: 'workflow-1' },
|
||||
headers: { authorization: 'Bearer token-123' },
|
||||
});
|
||||
const res = mock<Response>();
|
||||
|
||||
mockService.getWorkflowStatus.mockResolvedValue([
|
||||
{
|
||||
credentialId: 'cred-1',
|
||||
resolverId: 'resolver-1',
|
||||
status: 'configured',
|
||||
credentialType: 'oauth2Api',
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await controller.checkWorkflowForExecution(req, res);
|
||||
|
||||
// Verify that the URL is absolute and starts with the base URL
|
||||
expect(result.credentials?.[0].authorizationUrl).toMatch(/^https:\/\//);
|
||||
expect(result.credentials?.[0].authorizationUrl).toContain('https://n8n.example.com');
|
||||
expect(mockUrlService.getInstanceBaseUrl).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should map service response to DTO correctly', async () => {
|
||||
const req = mock<Request>({
|
||||
params: { workflowId: 'workflow-1' },
|
||||
@@ -218,7 +256,8 @@ describe('WorkflowStatusController', () => {
|
||||
credentialId: 'cred-1',
|
||||
credentialStatus: 'missing',
|
||||
credentialType: 'oauth2Api',
|
||||
authorizationUrl: '/credentials/cred-1/authorize?resolverId=resolver-1',
|
||||
authorizationUrl:
|
||||
'https://n8n.example.com/rest/credentials/cred-1/authorize?resolverId=resolver-1',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -5,11 +5,15 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { CredentialResolverWorkflowService } from './services/credential-resolver-workflow.service';
|
||||
import { WorkflowExecutionStatus } from '@n8n/api-types';
|
||||
import { getBearerToken } from './utils';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
|
||||
@RestController('/workflows')
|
||||
export class WorkflowStatusController {
|
||||
constructor(
|
||||
private readonly credentialResolverWorkflowService: CredentialResolverWorkflowService,
|
||||
private readonly urlService: UrlService,
|
||||
private readonly globalConfig: GlobalConfig,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -37,6 +41,9 @@ export class WorkflowStatusController {
|
||||
|
||||
const isReady = status.every((s) => s.status === 'configured');
|
||||
|
||||
const basePath = this.urlService.getInstanceBaseUrl();
|
||||
const restPath = this.globalConfig.endpoints.rest;
|
||||
|
||||
const executionStatus: WorkflowExecutionStatus = {
|
||||
workflowId,
|
||||
readyToExecute: isReady,
|
||||
@@ -44,7 +51,7 @@ export class WorkflowStatusController {
|
||||
credentialId: s.credentialId,
|
||||
credentialStatus: s.status,
|
||||
credentialType: s.credentialType,
|
||||
authorizationUrl: `/credentials/${s.credentialId}/authorize?resolverId=${encodeURIComponent(s.resolverId)}`,
|
||||
authorizationUrl: `${basePath}/${restPath}/credentials/${s.credentialId}/authorize?resolverId=${encodeURIComponent(s.resolverId)}`,
|
||||
})),
|
||||
};
|
||||
return executionStatus;
|
||||
|
||||
Reference in New Issue
Block a user