Skip to content

Commit 848305f

Browse files
New Components - guru (#16623)
* guru init * [Components] guru #13217 Sources - Announcement Read (Instant) - New Card (Instant) - Card Updated (Instant) Actions - Create Card - Add Tag To Card - Export Card To PDF * pnpm update * Update components/guru/sources/common/base.mjs Co-authored-by: Jorge Cortes <[email protected]> --------- Co-authored-by: Jorge Cortes <[email protected]>
1 parent 333f89b commit 848305f

File tree

17 files changed

+519
-22
lines changed

17 files changed

+519
-22
lines changed

components/guru/.gitignore

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import guru from "../../guru.app.mjs";
2+
3+
export default {
4+
key: "guru-add-tag-to-card",
5+
name: "Add Tag to Card",
6+
description: "Links an existing tag to a specified card in Guru. [See the documentation](https://developer.getguru.com/reference/getv1cardsgetextendedfact)",
7+
version: "0.0.1",
8+
type: "action",
9+
props: {
10+
guru,
11+
cardId: {
12+
propDefinition: [
13+
guru,
14+
"cardId",
15+
],
16+
},
17+
tags: {
18+
propDefinition: [
19+
guru,
20+
"tags",
21+
],
22+
type: "string",
23+
label: "Tag",
24+
description: "The ID of the tag to add to the card",
25+
},
26+
},
27+
async run({ $ }) {
28+
const response = await this.guru.linkTagToCard({
29+
$,
30+
cardId: this.cardId,
31+
tagId: this.tags,
32+
});
33+
34+
$.export("$summary", `Successfully linked tag ${this.tags} to card ${this.cardId}`);
35+
return response;
36+
},
37+
};
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { SHARE_STATUS_OPTIONS } from "../../common/constants.mjs";
2+
import { parseObject } from "../../common/utils.mjs";
3+
import guru from "../../guru.app.mjs";
4+
5+
export default {
6+
key: "guru-create-card",
7+
name: "Create Card",
8+
description: "Creates a new card on your Guru account. [See the documentation](https://developer.getguru.com/reference/postv1cardscreateextendedfact)",
9+
version: "0.0.1",
10+
type: "action",
11+
props: {
12+
guru,
13+
title: {
14+
type: "string",
15+
label: "Card Title",
16+
description: "The title of the card to create",
17+
},
18+
content: {
19+
type: "string",
20+
label: "Content",
21+
description: "The content of the card to create",
22+
},
23+
shareStatus: {
24+
type: "string",
25+
label: "Share Status",
26+
description: "The share status of the card.",
27+
options: SHARE_STATUS_OPTIONS,
28+
optional: true,
29+
},
30+
collection: {
31+
propDefinition: [
32+
guru,
33+
"collection",
34+
],
35+
},
36+
folderIds: {
37+
propDefinition: [
38+
guru,
39+
"folderIds",
40+
],
41+
},
42+
tags: {
43+
propDefinition: [
44+
guru,
45+
"tags",
46+
],
47+
optional: true,
48+
},
49+
},
50+
async run({ $ }) {
51+
const response = await this.guru.createCard({
52+
$,
53+
data: {
54+
preferredPhrase: this.title,
55+
content: this.content,
56+
shareStatus: this.shareStatus,
57+
collection: {
58+
id: this.collection,
59+
},
60+
folderIds: parseObject(this.folderIds),
61+
tags: parseObject(this.tags)?.map((item) => ({
62+
id: item,
63+
})),
64+
},
65+
});
66+
67+
$.export("$summary", `Created card "${this.title}" successfully`);
68+
return response;
69+
},
70+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import fs from "fs";
2+
import stream from "stream";
3+
import { promisify } from "util";
4+
import guru from "../../guru.app.mjs";
5+
6+
export default {
7+
key: "guru-export-card-to-pdf",
8+
name: "Export Card to PDF",
9+
description: "Export a specific card identified by its ID to a PDF file. [See the documentation](https://developer.getguru.com/docs/download-cards-to-pdf)",
10+
version: "0.0.1",
11+
type: "action",
12+
props: {
13+
guru,
14+
cardId: {
15+
propDefinition: [
16+
guru,
17+
"cardId",
18+
],
19+
},
20+
},
21+
async run({ $ }) {
22+
const {
23+
headers, data,
24+
} = await this.guru.exportCardToPdf({
25+
$,
26+
cardId: this.cardId,
27+
returnFullResponse: true,
28+
});
29+
30+
const fileName = headers["content-disposition"]?.split("filename=")[1]?.split("/")[1].slice(0, -1);
31+
const filePath = `/tmp/${fileName}`;
32+
33+
const pipeline = promisify(stream.pipeline);
34+
await pipeline(data, fs.createWriteStream(filePath));
35+
36+
$.export("$summary", `Successfully exported card ID ${this.cardId} to PDF.`);
37+
return {
38+
filePath,
39+
};
40+
},
41+
};

components/guru/app/guru.app.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const SHARE_STATUS_OPTIONS = [
2+
"TEAM",
3+
"PRIVATE",
4+
];

components/guru/common/utils.mjs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export const parseObject = (obj) => {
2+
if (!obj) return undefined;
3+
4+
if (Array.isArray(obj)) {
5+
return obj.map((item) => {
6+
if (typeof item === "string") {
7+
try {
8+
return JSON.parse(item);
9+
} catch (e) {
10+
return item;
11+
}
12+
}
13+
return item;
14+
});
15+
}
16+
if (typeof obj === "string") {
17+
try {
18+
return JSON.parse(obj);
19+
} catch (e) {
20+
return obj;
21+
}
22+
}
23+
return obj;
24+
};

components/guru/guru.app.mjs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import { axios } from "@pipedream/platform";
2+
3+
export default {
4+
type: "app",
5+
app: "guru",
6+
propDefinitions: {
7+
collection: {
8+
type: "string",
9+
label: "Collection",
10+
description: "The collection to create the card in",
11+
async options() {
12+
const data = await this.listCollections();
13+
14+
return data.map(({
15+
id: value, name: label,
16+
}) => ({
17+
label,
18+
value,
19+
}));
20+
},
21+
},
22+
folderIds: {
23+
type: "string[]",
24+
label: "Folder Ids",
25+
description: "The IDs of the folders to create the card in",
26+
async options() {
27+
const data = await this.listFolders();
28+
29+
return data.map(({
30+
id: value, title: label,
31+
}) => ({
32+
label,
33+
value,
34+
}));
35+
},
36+
},
37+
tags: {
38+
type: "string[]",
39+
label: "Tags",
40+
description: "The IDs of the tags to add to the card",
41+
async options() {
42+
const { team: { id: teamId } } = await this.whoAmI();
43+
const data = await this.listTags({
44+
teamId,
45+
});
46+
47+
return data[0]?.tags.map(({
48+
id: value, value: label,
49+
}) => ({
50+
label,
51+
value,
52+
}));
53+
},
54+
},
55+
cardId: {
56+
type: "string",
57+
label: "Card ID",
58+
description: "The ID of the card",
59+
async options({ prevContext }) {
60+
const {
61+
data, headers,
62+
} = await this.listCards({
63+
params: {
64+
token: prevContext.token,
65+
},
66+
});
67+
let token;
68+
69+
if (headers.link) {
70+
const link = headers.link.split(">")[0].slice(1);
71+
const url = new URL(link);
72+
const params = new URLSearchParams(url.search);
73+
token = params.get("token");
74+
}
75+
return {
76+
options: data.map(({
77+
id: value, preferredPhrase: label,
78+
}) => ({
79+
label,
80+
value,
81+
})),
82+
context: {
83+
token,
84+
},
85+
};
86+
},
87+
},
88+
89+
folderId: {
90+
type: "string",
91+
label: "Folder ID",
92+
description: "The ID of the folder to export to PDF",
93+
},
94+
},
95+
methods: {
96+
_baseUrl() {
97+
return "https://api.getguru.com/api/v1";
98+
},
99+
_auth() {
100+
return {
101+
username: `${this.$auth.username}`,
102+
password: `${this.$auth.api_key}`,
103+
};
104+
},
105+
_makeRequest({
106+
$ = this, path, ...opts
107+
}) {
108+
return axios($, {
109+
url: this._baseUrl() + path,
110+
auth: this._auth(),
111+
...opts,
112+
});
113+
},
114+
whoAmI(opts = {}) {
115+
return this._makeRequest({
116+
path: "/whoami",
117+
...opts,
118+
});
119+
},
120+
createCard(opts = {}) {
121+
return this._makeRequest({
122+
method: "POST",
123+
path: "/cards/extended",
124+
...opts,
125+
});
126+
},
127+
linkTagToCard({
128+
cardId, tagId, ...opts
129+
}) {
130+
return this._makeRequest({
131+
method: "PUT",
132+
path: `/cards/${cardId}/tags/${tagId}`,
133+
headers: {
134+
"Accept": "application/json",
135+
"Content-Type": "application/json",
136+
},
137+
...opts,
138+
});
139+
},
140+
exportCardToPdf({
141+
cardId, ...opts
142+
}) {
143+
return this._makeRequest({
144+
path: `/cards/${cardId}/pdf`,
145+
responseType: "stream",
146+
...opts,
147+
});
148+
},
149+
listCollections(opts = {}) {
150+
return this._makeRequest({
151+
path: "/collections",
152+
...opts,
153+
});
154+
},
155+
listFolders(opts = {}) {
156+
return this._makeRequest({
157+
path: "/folders",
158+
...opts,
159+
});
160+
},
161+
listTags({
162+
teamId, ...opts
163+
}) {
164+
return this._makeRequest({
165+
path: `/teams/${teamId}/tagcategories`,
166+
...opts,
167+
});
168+
},
169+
listCards(opts = {}) {
170+
return this._makeRequest({
171+
path: "/search/cardmgr",
172+
returnFullResponse: true,
173+
...opts,
174+
});
175+
},
176+
createWebhook(opts = {}) {
177+
return this._makeRequest({
178+
method: "POST",
179+
path: "/webhooks",
180+
...opts,
181+
});
182+
},
183+
deleteWebhook(webhookId) {
184+
return this._makeRequest({
185+
method: "DELETE",
186+
path: `/webhooks/${webhookId}`,
187+
});
188+
},
189+
},
190+
};

0 commit comments

Comments
 (0)