chore!: Remove GET method from /api/v1/apps (#36907)

This commit is contained in:
Martin Schoeler 2025-09-15 11:21:45 -03:00 committed by Guilherme Gazzo
parent cb3c5e3455
commit 5ac1863be4
6 changed files with 15 additions and 123 deletions

View File

@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": major
"@rocket.chat/rest-typings": major
---
Removes the deprecated `GET` Method from `/api/v1/apps`

View File

@ -79,7 +79,7 @@ export const useAppMenu = (app: App, isAppDetailsPage: boolean) => {
const action = button?.action || '';
const setAppStatus = useEndpoint<'POST', '/apps/:id/status'>('POST', '/apps/:id/status', { id: app.id });
const buildExternalUrl = useEndpoint('GET', '/apps');
const buildExternalUrl = useEndpoint('GET', '/apps/buildExternalUrl');
const syncApp = useEndpoint<'POST', '/apps/:id/sync'>('POST', '/apps/:id/sync', { id: app.id });
const uninstallApp = useEndpoint<'DELETE', '/apps/:id'>('DELETE', '/apps/:id', { id: app.id });
@ -161,12 +161,11 @@ export const useAppMenu = (app: App, isAppDetailsPage: boolean) => {
let data;
try {
data = (await buildExternalUrl({
buildExternalUrl: 'true',
data = await buildExternalUrl({
appId: app.id,
purchaseType: app.purchaseType,
details: 'true',
})) as { url: string };
});
} catch (error) {
handleAPIError(error);
return;

View File

@ -24,7 +24,6 @@ import { loggerMiddleware } from '../../../../app/api/server/middlewares/logger'
import { metricsMiddleware } from '../../../../app/api/server/middlewares/metrics';
import { tracerSpanMiddleware } from '../../../../app/api/server/middlewares/tracer';
import { getWorkspaceAccessToken, getWorkspaceAccessTokenWithScope } from '../../../../app/cloud/server';
import { apiDeprecationLogger } from '../../../../app/lib/server/lib/deprecationWarningLogger';
import { metrics } from '../../../../app/metrics/server';
import { settings } from '../../../../app/settings/server';
import { Info } from '../../../../app/utils/rocketchat.info';
@ -253,93 +252,6 @@ export class AppsRestApi {
'',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
async get() {
// Gets the Apps from the marketplace
if ('marketplace' in this.queryParams && this.queryParams.marketplace) {
apiDeprecationLogger.endpoint(this.route, '7.0.0', this.response, 'Use /apps/marketplace to get the apps list.');
try {
const apps = await fetchMarketplaceApps();
return API.v1.success(apps);
} catch (e) {
if (e instanceof MarketplaceConnectionError) {
return handleError('Unable to access Marketplace. Does the server has access to the internet?', e);
}
if (e instanceof MarketplaceAppsError || e instanceof MarketplaceUnsupportedVersionError) {
return API.v1.failure({ error: e.message });
}
if (e instanceof ZodError) {
orchestrator.getRocketChatLogger().error('Error parsing the Marketplace Apps:', e.issues);
return API.v1.failure({ error: i18n.t('Marketplace_Failed_To_Fetch_Apps') });
}
return API.v1.internalError();
}
}
if ('categories' in this.queryParams && this.queryParams.categories) {
apiDeprecationLogger.endpoint(this.route, '7.0.0', this.response, 'Use /apps/categories to get the categories list.');
try {
const categories = await fetchMarketplaceCategories();
return API.v1.success(categories);
} catch (err) {
orchestrator.getRocketChatLogger().error('Error getting the categories from the Marketplace:', err);
if (err instanceof MarketplaceConnectionError) {
return handleError('Unable to access Marketplace. Does the server has access to the internet?', err);
}
if (err instanceof MarketplaceAppsError || err instanceof MarketplaceUnsupportedVersionError) {
return API.v1.failure({ error: err.message });
}
if (err instanceof ZodError) {
orchestrator.getRocketChatLogger().error('Error validating the response from the Marketplace:', err.issues);
return API.v1.failure({ error: i18n.t('Marketplace_Failed_To_Fetch_Categories') });
}
return API.v1.internalError();
}
}
if (
'buildExternalUrl' in this.queryParams &&
'appId' in this.queryParams &&
this.queryParams.buildExternalUrl &&
this.queryParams.appId
) {
apiDeprecationLogger.endpoint(this.route, '7.0.0', this.response, 'Use /apps/buildExternalUrl to get the modal URLs.');
const workspaceId = settings.get('Cloud_Workspace_Id');
if (!this.queryParams.purchaseType || !purchaseTypes.has(this.queryParams.purchaseType)) {
return API.v1.failure({ error: 'Invalid purchase type' });
}
const token = await getWorkspaceAccessTokenWithScope({ scope: 'marketplace:purchase' });
if (!token) {
return API.v1.failure({ error: 'Unauthorized' });
}
const subscribeRoute = this.queryParams.details === 'true' ? 'subscribe/details' : 'subscribe';
const seats = await Users.getActiveLocalUserCount();
const baseUrl = orchestrator.getMarketplaceClient().getMarketplaceUrl();
return API.v1.success({
url: `${baseUrl}/apps/${this.queryParams.appId}/${
this.queryParams.purchaseType === 'buy' ? this.queryParams.purchaseType : subscribeRoute
}?workspaceId=${workspaceId}&token=${token.token}&seats=${seats}`,
});
}
apiDeprecationLogger.endpoint(this.route, '7.0.0', this.response, 'Use /apps/installed to get the installed apps list.');
const proxiedApps = await manager.get();
const apps = await Promise.all(proxiedApps.map((app) => formatAppInstanceForRest(app)));
return API.v1.success({ apps });
},
async post() {
let buff;
let marketplaceInfo: IMarketplaceInfo[] | undefined;

View File

@ -10,3 +10,7 @@ export function apps<TPath extends PathWithoutPrefix<Path>>(path: TPath): `/api/
export function apps(path = '') {
return `/api/apps${path}` as const;
}
export function installedApps() {
return `/api/apps/installed` as const;
}

View File

@ -1,12 +1,12 @@
import type { App } from '@rocket.chat/core-typings';
import { request, credentials } from '../api-data';
import { apps, APP_URL, APP_NAME } from './apps-data';
import { apps, APP_URL, APP_NAME, installedApps } from './apps-data';
const getApps = () =>
new Promise<App[]>((resolve) => {
void request
.get(apps())
.get(installedApps())
.set(credentials)
.end((_err, res) => {
resolve(res.body.apps);

View File

@ -220,35 +220,6 @@ export type AppsEndpoints = {
};
'/apps': {
GET:
| ((params: { buildExternalUrl: 'true'; purchaseType?: 'buy' | 'subscription'; appId?: string; details?: 'true' | 'false' }) => {
url: string;
})
| ((params: {
purchaseType?: 'buy' | 'subscription';
marketplace?: 'false';
version?: string;
appId?: string;
details?: 'true' | 'false';
}) => {
apps: App[];
})
| ((params: {
purchaseType?: 'buy' | 'subscription';
marketplace: 'true';
version?: string;
appId?: string;
details?: 'true' | 'false';
}) => App[])
| ((params: { categories: 'true' }) => {
createdDate: Date;
description: string;
id: string;
modifiedDate: Date;
title: string;
}[])
| (() => { apps: App[] });
POST: {
(
params: