Skip to content

Commit 44b751e

Browse files
committed
Implements #3461
1 parent 63d2907 commit 44b751e

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

config/default.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ module.exports = {
150150
COMMUNITY_API: 'http://localhost:8000',
151151
COMMUNITY_APP_GITHUB_ISSUES: 'https://github.com/topcoder-platform/community-app/issues',
152152
EMAIL_VERIFY_URL: 'http://www.topcoder-dev.com/settings/account/changeEmail',
153+
THRIVE_POLL_FEED: 'https://www.topcoder.com/feed',
153154
},
154155

155156
/* Information about Topcoder user groups can be cached in various places.
@@ -259,10 +260,11 @@ module.exports = {
259260
title: 'Switch to BUSINESS',
260261
href: 'https://connect.topcoder-dev.com',
261262
},
262-
// Config for TC EDU
263+
// Config for TC EDU - THRIVE
263264
TC_EDU_BASE_PATH: '/thrive',
264265
TC_EDU_TRACKS_PATH: '/tracks',
265266
TC_EDU_ARTICLES_PATH: '/articles',
266267
TC_EDU_SEARCH_PATH: '/search',
267268
TC_EDU_SEARCH_BAR_MAX_RESULTS_EACH_GROUP: 3,
269+
TC_EDU_POLL_TIME: 3600, // 1h in seconds
268270
};

src/server/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@ import { toJson as xmlToJson } from 'utils/xml2json';
2626
import cdnRouter from './routes/cdn';
2727
import mailChimpRouter from './routes/mailchimp';
2828
import mockDocuSignFactory from './__mocks__/docu-sign-mock';
29+
import { pollArticlesForThrive } from 'server/services/contentful';
2930

3031
/* Dome API for topcoder communities */
3132
import tcCommunitiesDemoApi from './tc-communities';
3233

3334
import webpackConfigFactory from '../../webpack.config';
3435
/* eslint-enable */
3536

37+
// Init TC Blog -> THRIVE poll bridge
38+
pollArticlesForThrive();
39+
3640
global.atob = atob;
3741

3842
const CMS_BASE_URL = `https://app.contentful.com/spaces/${config.SECRET.CONTENTFUL.SPACE_ID}`;

src/server/services/contentful.js

+109
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import fetch from 'isomorphic-fetch';
1010
// import logger from 'utils/logger';
1111
// import moment from 'moment';
1212
import qs from 'qs';
13+
import { logger } from 'topcoder-react-lib';
1314

1415
const contentful = require('contentful-management');
16+
const xml2json = require('xml2json');
1517

1618
/* Holds Contentful CDN URL. */
1719
const CDN_URL = 'https://cdn.contentful.com/spaces';
@@ -191,6 +193,113 @@ export function articleVote(body) {
191193
.then(entry => entry.publish());
192194
}
193195

196+
/**
197+
* This function fetches TC RSS feed to create draft articles in THRIVE for the new posted blogs.
198+
* It calls itself by interval to poll for new blogs.
199+
* Runs on server side only.
200+
*/
201+
export async function pollArticlesForThrive() {
202+
// make this function execute only when in production
203+
if (process.env.BABEL_ENV !== 'production') return;
204+
logger.log('polling blog articles for THRIVE -> INIT');
205+
// fetch the RSS feed and parse it
206+
const feedXML = await fetch(config.URL.THRIVE_POLL_FEED);
207+
if (feedXML.ok) {
208+
let feed = await feedXML.text();
209+
feed = await Promise.resolve(xml2json.toJson(feed, { object: true }));
210+
if (feed) {
211+
// when feed loaded and parsed ok
212+
// connect to Thrive space
213+
const client = contentful.createClient({
214+
accessToken: config.SECRET.CONTENTFUL.MANAGEMENT_TOKEN,
215+
});
216+
client.getSpace(config.SECRET.CONTENTFUL.EDU.SPACE_ID)
217+
.then(space => space.getEnvironment('master'))
218+
// loop all feed items and check if those exists in space
219+
// if not existing then create
220+
.then(env => Promise.all(
221+
_.map(feed.rss.channel.item,
222+
blogPost => env.getEntries({
223+
content_type: 'article',
224+
'fields.title[match]': blogPost.title,
225+
})
226+
.then((queryData) => {
227+
if (queryData.total === 0) {
228+
// article not found in Contentful space
229+
// will create it with payload...
230+
const article = {
231+
fields: {
232+
title: { 'en-US': blogPost.title },
233+
type: { 'en-US': 'Article' },
234+
tags: { 'en-US': blogPost.category },
235+
creationDate: { 'en-US': new Date(blogPost.pubDate) },
236+
content: { 'en-US': blogPost.description },
237+
externalArticle: { 'en-US': true },
238+
contentUrl: { 'en-US': blogPost.link },
239+
},
240+
};
241+
// check if author exists
242+
// if yes link it if no create it?
243+
return env.getEntries({
244+
content_type: 'person',
245+
query: blogPost['dc:creator'],
246+
})
247+
.then((author) => {
248+
// found an author that matches link it
249+
if (author.total) {
250+
article.fields.contentAuthor = {
251+
'en-US': [{
252+
sys: {
253+
type: 'Link', linkType: 'Entry', id: author.items[0].sys.id,
254+
},
255+
}],
256+
};
257+
}
258+
// try get the page to extract its featured image
259+
return fetch(blogPost.link)
260+
.then(rsp => rsp.text())
261+
.then((HTMLsrc) => {
262+
const match = /<image [^>]*href="([^"]+)"/gm.exec(HTMLsrc);
263+
if (match && match[1]) {
264+
// create the asset in Contentful
265+
return env.createAsset({
266+
fields: {
267+
title: { 'en-US': blogPost.title },
268+
file: {
269+
'en-US': { fileName: blogPost.title, contentType: 'image', upload: match[1] },
270+
},
271+
},
272+
})
273+
.then(asset => asset.processForAllLocales())
274+
.then((asset) => {
275+
article.fields.featuredImage = {
276+
'en-US': {
277+
sys: {
278+
type: 'Link', linkType: 'Asset', id: asset.sys.id,
279+
},
280+
},
281+
};
282+
return env.createEntry('article', article);
283+
});
284+
}
285+
// could not find image
286+
// just create the article without it...
287+
return env.createEntry('article', article);
288+
});
289+
});
290+
}
291+
// Article exists in Contentful space
292+
// do nothing...
293+
return 1;
294+
})),
295+
))
296+
.then(() => logger.log('polling blog articles for THRIVE -> DONE'));
297+
}
298+
}
299+
// schedule a repeat each TC_EDU_POLL_TIME
300+
setTimeout(pollArticlesForThrive, config.TC_EDU_POLL_TIME * 1000).unref();
301+
}
302+
194303
// /* Contentful CDN service. */
195304
// export const cdnService = new ApiService(CDN_URL, CDN_KEY);
196305

0 commit comments

Comments
 (0)