diff --git a/website/api/controllers/articles/view-basic-article.js b/website/api/controllers/articles/view-basic-article.js index bd2b67f6ba..6673616a44 100644 --- a/website/api/controllers/articles/view-basic-article.js +++ b/website/api/controllers/articles/view-basic-article.js @@ -45,6 +45,8 @@ module.exports = { } } + let articleCategorySlug = pageUrlSuffix.split('/')[0]; + // Setting the pages meta title and description from the articles meta tags, as well as an article image, if provided. // Note: Every article page should have a 'articleTitle' and a 'authorFullName' meta tag. // Note: Leaving title and description as `undefined` in our view means we'll default to the generic title and description set in layout.ejs. @@ -68,6 +70,7 @@ module.exports = { pageTitleForMeta, pageDescriptionForMeta, pageImageForMeta: thisPage.meta.articleImageUrl || undefined, + articleCategorySlug }; } diff --git a/website/api/controllers/download-rss-feed.js b/website/api/controllers/download-rss-feed.js new file mode 100644 index 0000000000..2dae5c7445 --- /dev/null +++ b/website/api/controllers/download-rss-feed.js @@ -0,0 +1,141 @@ +module.exports = { + + + friendlyName: 'Download rss feed', + + + description: 'Generate and return an RSS feed for a category of Fleet\'s articles', + + + inputs: { + + categoryName: { + type: 'string', + required: true, + isIn: [ + 'success-stories', + 'securing', + 'releases', + 'engineering', + 'guides', + 'announcements', + 'deploy', + 'podcasts', + 'report', + 'articles', + ], + } + + }, + + + exits: { + success: { outputFriendlyName: 'RSS feed XML', outputType: 'string' }, + badConfig: { responseType: 'badConfig' }, + }, + + + fn: async function ({categoryName}) { + + if (!_.isObject(sails.config.builtStaticContent)) { + throw {badConfig: 'builtStaticContent'}; + } else if (!_.isArray(sails.config.builtStaticContent.markdownPages)) { + throw {badConfig: 'builtStaticContent.markdownPages'}; + } + + // Start building the rss feed + let rssFeedXml = ''; + + // Build the description and title for this RSS feed. + let articleCategoryTitle = ''; + let categoryDescription = ''; + switch(categoryName) { + case 'success-stories': + articleCategoryTitle = 'Success stories | Fleet blog'; + categoryDescription = 'Read about how others are using Fleet and osquery.'; + break; + case 'securing': + articleCategoryTitle = 'Security | Fleet blog'; + categoryDescription = 'Learn more about how we secure Fleet.'; + break; + case 'releases': + articleCategoryTitle = 'Releases | Fleet blog'; + categoryDescription = 'Read about the latest release of Fleet.'; + break; + case 'engineering': + articleCategoryTitle = 'Engineering | Fleet blog'; + categoryDescription = 'Read about engineering at Fleet and beyond.'; + break; + case 'guides': + articleCategoryTitle = 'Guides | Fleet blog'; + categoryDescription = 'Learn more about how to use Fleet to accomplish your goals.'; + break; + case 'announcements': + articleCategoryTitle = 'Announcements | Fleet blog'; + categoryDescription = 'The latest news from Fleet.'; + break; + case 'deploy': + articleCategoryTitle = 'Deployment guides | Fleet blog'; + categoryDescription = 'Learn more about how to deploy Fleet.'; + break; + case 'podcasts': + articleCategoryTitle = 'Podcasts | Fleet blog'; + categoryDescription = 'Listen to the Future of Device Management podcast'; + break; + case 'report': + articleCategoryTitle = 'Reports | Fleet blog'; + categoryDescription = ''; + break; + case 'articles': + articleCategoryTitle = 'Fleet blog | Fleet for osquery'; + categoryDescription = 'Read all articles from Fleet\'s blog.'; + } + + let rssFeedTitle = `${_.escape(articleCategoryTitle)}`; + let rssFeedDescription = `${_.escape(categoryDescription)}`; + let rsslastBuildDate = `${_.escape(new Date(Date.now()))}`; + let rssFeedImage = `${_.escape('https://fleetdm.com'+categoryName)}${_.escape(articleCategoryTitle)}${_.escape('https://fleetdm.com/images/fleet-logo-square@2x.png')}`; + + rssFeedXml += `${rssFeedTitle}${rssFeedDescription}${rsslastBuildDate}${rssFeedImage}`; + + + // Determine the subset of articles that will be used to squirt out an XML string. + let articlesToAddToFeed = []; + if (categoryName === 'articles') { + // If the category is `articles` we'll build a rss feed that contains all articles + articlesToAddToFeed = sails.config.builtStaticContent.markdownPages.filter((page)=>{ + if(_.startsWith(page.htmlId, 'articles')) { + return page; + } + });//∞ + } else { + // If the user requested a specific category, we'll only build a feed with articles in that category + articlesToAddToFeed = sails.config.builtStaticContent.markdownPages.filter((page)=>{ + if(_.startsWith(page.url, '/'+categoryName)) { + return page; + } + });//∞ + } + + // Iterate through the filtered array of articles, adding elements for each article. + for (let pageInfo of articlesToAddToFeed) { + let rssItemTitle = `${_.escape(pageInfo.meta.articleTitle)}`; + let rssItemDescription = `${_.escape(pageInfo.meta.description)}`; + let rssItemLink = `${_.escape('https://fleetdm.com'+pageInfo.url)}`; + let rssItemPublishDate = `${_.escape(new Date(pageInfo.meta.publishedOn).toJSON())}`; + // Add the article to the feed. + rssFeedXml += `${rssItemTitle}${rssItemDescription}${rssItemLink}${rssItemPublishDate}`; + } + + rssFeedXml += ``; + + // Set the response type + this.res.type('text/xml'); + + // Return the generated RSS feed + return rssFeedXml; + + } + + +}; diff --git a/website/assets/styles/pages/articles/articles.less b/website/assets/styles/pages/articles/articles.less index 8fff99f91c..fb282d5428 100644 --- a/website/assets/styles/pages/articles/articles.less +++ b/website/assets/styles/pages/articles/articles.less @@ -33,6 +33,21 @@ padding-top: 80px; padding-bottom: 40px; } + [purpose='rss-button'] { + padding: 4px 8px; + display: inline; + max-width: min-content; + color: #192147; + font-size: 14px; + text-decoration: none; + span::before { + font-family: 'FontAwesome'; + content: '\f09e'; + color: #192147; + padding-right: 8px; + font-size: 16px; + } + } [purpose='articles'] { padding-bottom: 80px; diff --git a/website/assets/styles/pages/articles/basic-article.less b/website/assets/styles/pages/articles/basic-article.less index 679baca9b1..c7c617982a 100644 --- a/website/assets/styles/pages/articles/basic-article.less +++ b/website/assets/styles/pages/articles/basic-article.less @@ -24,6 +24,22 @@ } } + [purpose='rss-button'] { + padding: 4px 8px; + display: inline; + max-width: min-content; + color: #192147; + text-decoration: none; + font-size: 14px; + span::before { + vertical-align: baseline; + font-family: 'FontAwesome'; + content: '\f09e'; + color: #192147; + padding-right: 8px; + font-size: 16px; + } + } [purpose='article-details'] { font-size: 14px; line-height: 20px; diff --git a/website/config/policies.js b/website/config/policies.js index 09f4f4b1ee..87396255e7 100644 --- a/website/config/policies.js +++ b/website/config/policies.js @@ -50,4 +50,5 @@ module.exports.policies = { 'view-fleet-mdm': true, 'deliver-mdm-beta-signup': true, 'deliver-apple-csr': true, + 'download-rss-feed': true, }; diff --git a/website/config/routes.js b/website/config/routes.js index 8c40c6d397..d2ebaec4d3 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -355,6 +355,10 @@ module.exports.routes = { // XML file, which helps search engines know which pages are available on the website. 'GET /sitemap.xml': { action: 'download-sitemap' }, + // RSS feeds + // ============================================================================================================= + 'GET /rss/:categoryName': {action: 'download-rss-feed'}, + // Potential future pages // ============================================================================================================= // Things that are not webpages here (in the Sails app) yet, but could be in the future. For now they are just diff --git a/website/views/pages/articles/articles.ejs b/website/views/pages/articles/articles.ejs index 4adbf85061..4b7be05544 100644 --- a/website/views/pages/articles/articles.ejs +++ b/website/views/pages/articles/articles.ejs @@ -19,7 +19,10 @@

{{articleCategory}}

-

{{categoryDescription}}

+
+

{{categoryDescription}}

+ Subscribe +
diff --git a/website/views/pages/articles/basic-article.ejs b/website/views/pages/articles/basic-article.ejs index 4da8914fa1..a551df0a01 100644 --- a/website/views/pages/articles/basic-article.ejs +++ b/website/views/pages/articles/basic-article.ejs @@ -4,11 +4,14 @@

<%=thisPage.meta.articleTitle %>

{{articleSubtitle}}

-
- - | - The author's GitHub profile picture -

<%=thisPage.meta.authorFullName %>

+
+
+ + | + The author's GitHub profile picture +

<%=thisPage.meta.authorFullName %>

+
+ Subscribe
<%- partial(path.relative(path.dirname(__filename), path.resolve( sails.config.appPath, path.join(sails.config.builtStaticContent.compiledPagePartialsAppPath, thisPage.htmlId)))) %>