Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/tidy-laws-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": major
"@rocket.chat/rest-typings": major
---

Removes the deprecated `GET` Method from `/api/v1/apps`
7 changes: 3 additions & 4 deletions apps/meteor/client/views/marketplace/hooks/useAppMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down Expand Up @@ -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;
Expand Down
88 changes: 0 additions & 88 deletions apps/meteor/ee/server/apps/communication/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -253,93 +252,6 @@ export class AppsRestApi {
'',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
async get() {
const baseUrl = orchestrator.getMarketplaceUrl();

// 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();

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;
Expand Down
4 changes: 4 additions & 0 deletions apps/meteor/tests/data/apps/apps-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 2 additions & 2 deletions apps/meteor/tests/data/apps/helper.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
29 changes: 0 additions & 29 deletions packages/rest-typings/src/apps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading