Skip to content

Commit b72de3c

Browse files
committed
add devTo publish for podcast
1 parent 26ed537 commit b72de3c

7 files changed

Lines changed: 278 additions & 0 deletions

File tree

backend/firebase/functions/package-lock.json

Lines changed: 68 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/firebase/functions/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@notionhq/client": "^1.0.4",
1919
"@types/algoliasearch": "^3.34.11",
2020
"algoliasearch": "^4.8.3",
21+
"axios": "^0.27.2",
2122
"cloudinary": "^1.23.0",
2223
"firebase-admin": "^9.2.0",
2324
"firebase-functions": "^3.21.2",

backend/firebase/functions/src/config/config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ export const notionTutorials = checkMain('notion', 'tutorials');
6767
export const notionPages = checkMain('notion', 'pages');
6868
export const notionSections = checkMain('notion', 'sections');
6969
export const notionLanguages = checkMain('notion', 'languages');
70+
71+
// Dev.to
72+
export const devto = checkMain('devto', 'key');
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import * as functions from 'firebase-functions';
2+
import { sendTopic } from '../utilities/googleapis';
3+
import {
4+
queryPurrfectStreamDevTo,
5+
patchPurrfectPage,
6+
} from '../utilities/notion.server';
7+
import { addArticle } from '../utilities/devto';
8+
9+
const topicId = 'devtoCreateFromNotion';
10+
11+
export const scheduledNotionToDevto = functions.pubsub
12+
.schedule('every 5 minutes')
13+
.onRun(async () => {
14+
// Check to see if ther are scheduled pods
15+
console.log('Checking for scheduled pods');
16+
const scheduledRes = await queryPurrfectStreamDevTo(1);
17+
console.log('Scheduled Result:', JSON.stringify(scheduledRes));
18+
19+
if (scheduledRes?.results) {
20+
const needCloudinaryPods = scheduledRes?.results;
21+
console.log('Pods to add to pub/sub', JSON.stringify(needCloudinaryPods));
22+
23+
for (const pod of needCloudinaryPods) {
24+
await sendTopic(topicId, pod);
25+
}
26+
}
27+
return true;
28+
});
29+
30+
export const devtoToNotionPubSub = functions.pubsub
31+
.topic(topicId)
32+
.onPublish(async (message, context) => {
33+
console.log('The function was triggered at ', context.timestamp);
34+
console.log('The unique ID for the event is', context.eventId);
35+
const page = JSON.parse(JSON.stringify(message.json));
36+
console.log('page', page);
37+
38+
let data;
39+
switch (page._type) {
40+
case 'podcast':
41+
data = {
42+
article: {
43+
title: page.title,
44+
published: true,
45+
tags: ['podcast', 'webdev', 'javascript', 'beginners'],
46+
series: `codingcatdev_podcast_${page.properties.Season.number}`,
47+
main_image: `https://media.codingcat.dev/image/upload/b_rgb:5e1186,c_pad,w_1000,h_420/${page?.coverPhoto?.public_id}`,
48+
canonical_url: `https://codingcat.dev/${page._type}/${page.slug}`,
49+
description: page.excerpt,
50+
organization_id: '1009',
51+
body_markdown: `Original: https://codingcat.dev/${page._type}/${
52+
page.slug
53+
}
54+
{% youtube ${page.properties.youtube.url} %}
55+
{% spotify spotify:episode:${page.properties.spotify.url
56+
.split('/')
57+
.at(-1)
58+
.split('?')
59+
.at(0)} %}
60+
61+
`,
62+
},
63+
};
64+
break;
65+
default:
66+
break;
67+
}
68+
69+
if (data) {
70+
const response = await addArticle(data);
71+
console.log('addArticle result:', response);
72+
73+
const devto = response?.data?.url;
74+
75+
if (!devto) {
76+
console.log('devto url missing');
77+
return;
78+
}
79+
80+
const update = {
81+
page_id: page.id,
82+
properties: {
83+
devto: {
84+
id: 'remote',
85+
type: 'url',
86+
url: devto,
87+
},
88+
},
89+
};
90+
console.log('Updating page with: ', JSON.stringify(update));
91+
const purrfectPagePatchRes = await patchPurrfectPage(update);
92+
console.log('Page update result:', JSON.stringify(purrfectPagePatchRes));
93+
94+
return purrfectPagePatchRes;
95+
} else {
96+
console.log('No Data matched for article');
97+
return;
98+
}
99+
});
100+
101+
// Used for testing don't forget to remove for production
102+
export const httpNotionToDevto = functions.https.onRequest(async (req, res) => {
103+
// Check to see if ther are scheduled pods
104+
console.log('Checking for scheduled pods');
105+
const scheduledRes = await queryPurrfectStreamDevTo(1);
106+
console.log('Scheduled Result:', JSON.stringify(scheduledRes));
107+
108+
if (scheduledRes?.results) {
109+
const needCloudinaryPods = scheduledRes?.results;
110+
console.log('Pods to add to pub/sub', JSON.stringify(needCloudinaryPods));
111+
112+
for (const pod of needCloudinaryPods) {
113+
await sendTopic(topicId, pod);
114+
}
115+
}
116+
res.send({ msg: 'started' });
117+
});

backend/firebase/functions/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,9 @@ export { calendlyCreateNotionCardPubSub } from './calendly/pubsub';
2727

2828
// Notion to Firestore
2929
export { scheduledNotionToFirestore } from './firebase/notion';
30+
31+
// Notion to Devto
32+
export {
33+
scheduledNotionToDevto,
34+
devtoToNotionPubSub,
35+
} from './devto/scheduledNotionToDevto';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import axios, { AxiosRequestConfig } from 'axios';
2+
import { devto } from '../config/config';
3+
4+
export const addArticle = async (data: any) => {
5+
const URL = 'https://dev.to/api/articles/';
6+
7+
const options: AxiosRequestConfig = {
8+
headers: {
9+
'api-key': devto,
10+
'Content-Type': 'application/json',
11+
},
12+
};
13+
14+
return await axios.post(URL, data, options);
15+
};

backend/firebase/functions/src/utilities/notion.server.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,74 @@ export const queryPurrfectStreamByReleased = async (
692692
return await formatPosts(raw, 'podcast');
693693
};
694694

695+
export const queryPurrfectStreamDevTo = async (
696+
page_size?: number,
697+
start_cursor?: string | null
698+
) => {
699+
const raw = await notionClient.databases.query({
700+
database_id: notionConfig.purrfectStreamsDb,
701+
start_cursor: start_cursor ? start_cursor : undefined,
702+
page_size,
703+
filter: {
704+
and: [
705+
{
706+
property: 'slug',
707+
url: {
708+
is_not_empty: true,
709+
},
710+
},
711+
{
712+
property: 'Status',
713+
select: {
714+
equals: 'Released',
715+
},
716+
},
717+
{
718+
property: 'Episode',
719+
number: {
720+
is_not_empty: true,
721+
},
722+
},
723+
{
724+
property: 'start',
725+
date: {
726+
on_or_before: new Date().toISOString(),
727+
},
728+
},
729+
{
730+
property: 'devto',
731+
url: {
732+
is_empty: true,
733+
},
734+
},
735+
{
736+
property: 'youtube',
737+
url: {
738+
is_not_empty: true,
739+
},
740+
},
741+
{
742+
property: 'spotify',
743+
url: {
744+
is_not_empty: true,
745+
},
746+
},
747+
],
748+
},
749+
sorts: [
750+
{
751+
property: 'Season',
752+
direction: 'ascending',
753+
},
754+
{
755+
property: 'Episode',
756+
direction: 'ascending',
757+
},
758+
],
759+
});
760+
return await formatPosts(raw, 'podcast');
761+
};
762+
695763
export const queryPurrfectStreamBySlug = async (slug: string) => {
696764
const raw = await notionClient.databases.query({
697765
database_id: notionConfig.purrfectStreamsDb,

0 commit comments

Comments
 (0)