Skip to content

Commit fd9bfec

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 0b69f65 + f06315d commit fd9bfec

File tree

5 files changed

+137
-2
lines changed

5 files changed

+137
-2
lines changed

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,9 @@ POSTIZ_OAUTH_CLIENT_SECRET=""
104104
# DUB_TOKEN="" # Your self-hosted Dub API token
105105
# DUB_API_ENDPOINT="https://api.dub.co" # Your self-hosted Dub API endpoint
106106
# DUB_SHORT_LINK_DOMAIN="dub.sh" # Your self-hosted Dub domain
107+
108+
# SHORT_IO_SECRET_KEY="" # Your Short.io API secret key
109+
110+
# KUTT_API_KEY="" # Your Kutt.it API key
111+
# KUTT_API_ENDPOINT="https://kutt.it/api/v2" # Your self-hosted Kutt API endpoint
112+
# KUTT_SHORT_LINK_DOMAIN="kutt.it" # Your self-hosted Kutt domain

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
</p>
1515

1616
<p align="center">
17-
<a href="https://opensource.org/licenses/Apache-2.0">
18-
<img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License">
17+
<a href="https://opensource.org/license/agpl-v3">
18+
<img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License">
1919
</a>
2020
</p>
2121

apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const PinterestSettings: FC = () => {
1010
return (
1111
<div className="flex flex-col">
1212
<Input label={'Title'} {...register('title')} />
13+
<Input label={'Link'} {...register('link')} />
1314
<PinterestBoard {...register('board')} />
1415
<ColorPicker
1516
label="Select Pin Color"
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { ShortLinking } from '@gitroom/nestjs-libraries/short-linking/short-linking.interface';
2+
3+
const KUTT_API_ENDPOINT = process.env.KUTT_API_ENDPOINT || 'https://kutt.it/api/v2';
4+
const KUTT_SHORT_LINK_DOMAIN = process.env.KUTT_SHORT_LINK_DOMAIN || 'kutt.it';
5+
6+
const getOptions = () => ({
7+
headers: {
8+
'X-API-Key': process.env.KUTT_API_KEY,
9+
'Content-Type': 'application/json',
10+
},
11+
});
12+
13+
export class Kutt implements ShortLinking {
14+
shortLinkDomain = KUTT_SHORT_LINK_DOMAIN;
15+
16+
async linksStatistics(links: string[]) {
17+
return Promise.all(
18+
links.map(async (link) => {
19+
const linkId = link.split('/').pop();
20+
21+
try {
22+
const response = await fetch(
23+
`${KUTT_API_ENDPOINT}/links/${linkId}/stats`,
24+
getOptions()
25+
);
26+
27+
if (!response.ok) {
28+
throw new Error(`HTTP error! status: ${response.status}`);
29+
}
30+
31+
const data = await response.json();
32+
33+
return {
34+
short: link,
35+
original: data.address || '',
36+
clicks: data.lastDay?.stats?.reduce((total: number, stat: any) => total + stat, 0)?.toString() || '0',
37+
};
38+
} catch (error) {
39+
return {
40+
short: link,
41+
original: '',
42+
clicks: '0',
43+
};
44+
}
45+
})
46+
);
47+
}
48+
49+
async convertLinkToShortLink(id: string, link: string) {
50+
try {
51+
const response = await fetch(`${KUTT_API_ENDPOINT}/links`, {
52+
...getOptions(),
53+
method: 'POST',
54+
body: JSON.stringify({
55+
target: link,
56+
domain: this.shortLinkDomain,
57+
reuse: false,
58+
}),
59+
});
60+
61+
if (!response.ok) {
62+
throw new Error(`HTTP error! status: ${response.status}`);
63+
}
64+
65+
const data = await response.json();
66+
return data.link;
67+
} catch (error) {
68+
throw new Error(`Failed to create short link: ${error}`);
69+
}
70+
}
71+
72+
async convertShortLinkToLink(shortLink: string) {
73+
const linkId = shortLink.split('/').pop();
74+
75+
try {
76+
const response = await fetch(
77+
`${KUTT_API_ENDPOINT}/links/${linkId}/stats`,
78+
getOptions()
79+
);
80+
81+
if (!response.ok) {
82+
throw new Error(`HTTP error! status: ${response.status}`);
83+
}
84+
85+
const data = await response.json();
86+
return data.address || '';
87+
} catch (error) {
88+
throw new Error(`Failed to get original link: ${error}`);
89+
}
90+
}
91+
92+
async getAllLinksStatistics(
93+
id: string,
94+
page = 1
95+
): Promise<{ short: string; original: string; clicks: string }[]> {
96+
try {
97+
const response = await fetch(
98+
`${KUTT_API_ENDPOINT}/links?limit=100&skip=${(page - 1) * 100}`,
99+
getOptions()
100+
);
101+
102+
if (!response.ok) {
103+
throw new Error(`HTTP error! status: ${response.status}`);
104+
}
105+
106+
const data = await response.json();
107+
108+
const mapLinks = data.data?.map((link: any) => ({
109+
short: link.link,
110+
original: link.address,
111+
clicks: link.visit_count?.toString() || '0',
112+
})) || [];
113+
114+
if (mapLinks.length < 100) {
115+
return mapLinks;
116+
}
117+
118+
return [...mapLinks, ...(await this.getAllLinksStatistics(id, page + 1))];
119+
} catch (error) {
120+
return [];
121+
}
122+
}
123+
}

libraries/nestjs-libraries/src/short-linking/short.link.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Empty } from '@gitroom/nestjs-libraries/short-linking/providers/empty';
33
import { ShortLinking } from '@gitroom/nestjs-libraries/short-linking/short-linking.interface';
44
import { Injectable } from '@nestjs/common';
55
import { ShortIo } from './providers/short.io';
6+
import { Kutt } from './providers/kutt';
67

78
const getProvider = (): ShortLinking => {
89
if (process.env.DUB_TOKEN) {
@@ -13,6 +14,10 @@ const getProvider = (): ShortLinking => {
1314
return new ShortIo();
1415
}
1516

17+
if (process.env.KUTT_API_KEY) {
18+
return new Kutt();
19+
}
20+
1621
return new Empty();
1722
};
1823

0 commit comments

Comments
 (0)