Skip to content

Commit 9a74d75

Browse files
authored
Merge pull request #833 from gitroomhq/feat/3rdparties
Add Integrations
2 parents ce60edb + 0c1d854 commit 9a74d75

File tree

28 files changed

+1535
-8
lines changed

28 files changed

+1535
-8
lines changed

apps/backend/src/api/api.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { AutopostController } from '@gitroom/backend/api/routes/autopost.control
3434
import { McpService } from '@gitroom/nestjs-libraries/mcp/mcp.service';
3535
import { McpController } from '@gitroom/backend/api/routes/mcp.controller';
3636
import { SetsController } from '@gitroom/backend/api/routes/sets.controller';
37+
import { ThirdPartyController } from '@gitroom/backend/api/routes/third-party.controller';
3738

3839
const authenticatedController = [
3940
UsersController,
@@ -52,6 +53,7 @@ const authenticatedController = [
5253
SignatureController,
5354
AutopostController,
5455
SetsController,
56+
ThirdPartyController,
5557
];
5658
@Module({
5759
imports: [UploadModule],

apps/backend/src/api/routes/posts.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class PostsController {
3838
private _starsService: StarsService,
3939
private _messagesService: MessagesService,
4040
private _agentGraphService: AgentGraphService,
41-
private _shortLinkService: ShortLinkService
41+
private _shortLinkService: ShortLinkService,
4242
) {}
4343

4444
@Get('/:id/statistics')
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import {
2+
Body,
3+
Controller,
4+
Get,
5+
HttpException,
6+
Param,
7+
Post,
8+
Delete,
9+
} from '@nestjs/common';
10+
import { ApiTags } from '@nestjs/swagger';
11+
import { ThirdPartyManager } from '@gitroom/nestjs-libraries/3rdparties/thirdparty.manager';
12+
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
13+
import { Organization } from '@prisma/client';
14+
import { AuthService } from '@gitroom/helpers/auth/auth.service';
15+
import { UploadFactory } from '@gitroom/nestjs-libraries/upload/upload.factory';
16+
import { MediaService } from '@gitroom/nestjs-libraries/database/prisma/media/media.service';
17+
18+
@ApiTags('Third Party')
19+
@Controller('/third-party')
20+
export class ThirdPartyController {
21+
private storage = UploadFactory.createStorage();
22+
23+
constructor(
24+
private _thirdPartyManager: ThirdPartyManager,
25+
private _mediaService: MediaService,
26+
) {}
27+
28+
@Get('/list')
29+
async getThirdPartyList() {
30+
return this._thirdPartyManager.getAllThirdParties();
31+
}
32+
33+
@Get('/')
34+
async getSavedThirdParty(@GetOrgFromRequest() organization: Organization) {
35+
return Promise.all(
36+
(
37+
await this._thirdPartyManager.getAllThirdPartiesByOrganization(
38+
organization.id
39+
)
40+
).map((thirdParty) => {
41+
const { description, fields, position, title, identifier } =
42+
this._thirdPartyManager.getThirdPartyByName(thirdParty.identifier);
43+
return {
44+
...thirdParty,
45+
title,
46+
position,
47+
fields,
48+
description,
49+
};
50+
})
51+
);
52+
}
53+
54+
@Delete('/:id')
55+
deleteById(
56+
@GetOrgFromRequest() organization: Organization,
57+
@Param('id') id: string
58+
) {
59+
return this._thirdPartyManager.deleteIntegration(organization.id, id);
60+
}
61+
62+
@Post('/:id/submit')
63+
async generate(
64+
@GetOrgFromRequest() organization: Organization,
65+
@Param('id') id: string,
66+
@Body() data: any
67+
) {
68+
const thirdParty = await this._thirdPartyManager.getIntegrationById(
69+
organization.id,
70+
id
71+
);
72+
73+
if (!thirdParty) {
74+
throw new HttpException('Integration not found', 404);
75+
}
76+
77+
const thirdPartyInstance = this._thirdPartyManager.getThirdPartyByName(
78+
thirdParty.identifier
79+
);
80+
81+
if (!thirdPartyInstance) {
82+
throw new HttpException('Invalid identifier', 400);
83+
}
84+
85+
const loadedData = await thirdPartyInstance?.instance?.sendData(
86+
AuthService.fixedDecryption(thirdParty.apiKey),
87+
data
88+
);
89+
90+
const file = await this.storage.uploadSimple(loadedData);
91+
return this._mediaService.saveFile(organization.id, file.split('/').pop(), file);
92+
}
93+
94+
@Post('/function/:id/:functionName')
95+
async callFunction(
96+
@GetOrgFromRequest() organization: Organization,
97+
@Param('id') id: string,
98+
@Param('functionName') functionName: string,
99+
@Body() data: any
100+
) {
101+
const thirdParty = await this._thirdPartyManager.getIntegrationById(
102+
organization.id,
103+
id
104+
);
105+
106+
if (!thirdParty) {
107+
throw new HttpException('Integration not found', 404);
108+
}
109+
110+
const thirdPartyInstance = this._thirdPartyManager.getThirdPartyByName(
111+
thirdParty.identifier
112+
);
113+
114+
if (!thirdPartyInstance) {
115+
throw new HttpException('Invalid identifier', 400);
116+
}
117+
118+
return thirdPartyInstance?.instance?.[functionName](
119+
AuthService.fixedDecryption(thirdParty.apiKey),
120+
data
121+
);
122+
}
123+
124+
@Post('/:identifier')
125+
async addApiKey(
126+
@GetOrgFromRequest() organization: Organization,
127+
@Param('identifier') identifier: string,
128+
@Body('api') api: string
129+
) {
130+
const thirdParty = this._thirdPartyManager.getThirdPartyByName(identifier);
131+
if (!thirdParty) {
132+
throw new HttpException('Invalid identifier', 400);
133+
}
134+
135+
const connect = await thirdParty.instance.checkConnection(api);
136+
if (!connect) {
137+
throw new HttpException('Invalid API key', 400);
138+
}
139+
140+
try {
141+
const save = await this._thirdPartyManager.saveIntegration(
142+
organization.id,
143+
identifier,
144+
api,
145+
{
146+
name: connect.name,
147+
username: connect.username,
148+
id: connect.id,
149+
}
150+
);
151+
152+
return {
153+
id: save.id,
154+
};
155+
} catch (e) {
156+
console.log(e);
157+
throw new HttpException('Integration Already Exists', 400);
158+
}
159+
}
160+
}

apps/backend/src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ThrottlerBehindProxyGuard } from '@gitroom/nestjs-libraries/throttler/t
1111
import { ThrottlerModule } from '@nestjs/throttler';
1212
import { AgentModule } from '@gitroom/nestjs-libraries/agent/agent.module';
1313
import { McpModule } from '@gitroom/backend/mcp/mcp.module';
14+
import { ThirdPartyModule } from '@gitroom/nestjs-libraries/3rdparties/thirdparty.module';
1415

1516
@Global()
1617
@Module({
@@ -22,6 +23,7 @@ import { McpModule } from '@gitroom/backend/mcp/mcp.module';
2223
PublicApiModule,
2324
AgentModule,
2425
McpModule,
26+
ThirdPartyModule,
2527
ThrottlerModule.forRoot([
2628
{
2729
ttl: 3600000,
7.33 KB
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ThirdPartyComponent } from '@gitroom/frontend/components/third-parties/third-party.component';
2+
3+
export const dynamic = 'force-dynamic';
4+
import { Metadata } from 'next';
5+
import { isGeneralServerSide } from '@gitroom/helpers/utils/is.general.server.side';
6+
export const metadata: Metadata = {
7+
title: `${
8+
isGeneralServerSide() ? 'Postiz Integrations' : 'Gitroom Integrations'
9+
}`,
10+
description: '',
11+
};
12+
export default async function Index() {
13+
return <ThirdPartyComponent />;
14+
}

apps/frontend/src/components/launches/add.edit.model.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ export const AddEditModal: FC<{
558558

559559
// @ts-ignore
560560
for (const item of clipboardItems) {
561-
console.log(item);
562561
if (item.kind === 'file') {
563562
const file = item.getAsFile();
564563
if (file) {
@@ -779,6 +778,7 @@ Here are the things you can do:
779778
<div className="flex">
780779
<div className="flex-1">
781780
<MultiMediaComponent
781+
allData={value}
782782
text={p.content}
783783
label={t('attachments', 'Attachments')}
784784
description=""

apps/frontend/src/components/launches/providers/high.order.provider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ export const withProvider = function <T extends object>(
392392

393393
// @ts-ignore
394394
for (const item of clipboardItems) {
395-
console.log(item);
396395
if (item.kind === 'file') {
397396
const file = item.getAsFile();
398397
if (file) {
@@ -567,6 +566,7 @@ export const withProvider = function <T extends object>(
567566
<div className="flex">
568567
<div className="flex-1">
569568
<MultiMediaComponent
569+
allData={InPlaceValue}
570570
text={val.content}
571571
label="Attachments"
572572
description=""

apps/frontend/src/components/launches/providers/reddit/subreddit.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ export const Subreddit: FC<{
234234
<div className="w-full h-[10px] bg-input rounded-tr-[8px] rounded-tl-[8px]" />
235235
<div className="flex flex-col text-nowrap">
236236
<MultiMediaComponent
237+
allData={[]}
237238
text=""
238239
description=""
239240
name="media"

apps/frontend/src/components/layout/top.menu.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ export const useMenuItems = () => {
5050
icon: 'plugs',
5151
path: '/plugs',
5252
},
53+
{
54+
name: t('integrations', 'Integrations'),
55+
icon: 'integrations',
56+
path: '/third-party',
57+
},
5358
{
5459
name: t('billing', 'Billing'),
5560
icon: 'billing',
@@ -80,7 +85,7 @@ export const TopMenu: FC = () => {
8085
const menuItems = useMenuItems();
8186
return (
8287
<div className="flex flex-col h-full animate-normalFadeDown order-3 md:order-2 col-span-2 md:col-span-1">
83-
<ul className="gap-0 md:gap-5 flex flex-1 items-center text-[18px]">
88+
<ul className="gap-0 md:gap-1 flex flex-1 items-center text-[18px]">
8489
{menuItems
8590
.filter((f) => {
8691
if (f.hide) {

0 commit comments

Comments
 (0)