From d1593aae5509cd7556022c492fa2da0408c7d6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Bateira?= Date: Fri, 16 Apr 2021 11:06:46 +0000 Subject: [PATCH 1/9] =?UTF-8?q?Update=20from=20Forestry.io=20Jos=C3=A9=20B?= =?UTF-8?q?ateira=20updated=20src/=5Fblog/086-ipfs-in-opera-for-android.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/_blog/086-ipfs-in-opera-for-android.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_blog/086-ipfs-in-opera-for-android.md b/src/_blog/086-ipfs-in-opera-for-android.md index 241ffdba..5f087fec 100644 --- a/src/_blog/086-ipfs-in-opera-for-android.md +++ b/src/_blog/086-ipfs-in-opera-for-android.md @@ -7,6 +7,7 @@ author: Dietrich Ayala header_image: "/086-ipfs-in-opera-for-android-header-image.png" tags: - browsers +- opera - mobile --- From ed3ef312599c195082031d1c1511e9dfb3cc801c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Bateira?= Date: Mon, 19 Apr 2021 10:27:53 +0000 Subject: [PATCH 2/9] Update from Forestry.io - Updated Forestry configuration --- .../front_matter/templates/blog-post.yml | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/.forestry/front_matter/templates/blog-post.yml b/.forestry/front_matter/templates/blog-post.yml index 0cd0a1de..a309ff12 100644 --- a/.forestry/front_matter/templates/blog-post.yml +++ b/.forestry/front_matter/templates/blog-post.yml @@ -27,23 +27,17 @@ fields: - type: datetime name: date label: Date - description: '"Published on" date. Remember this is only a list date for - display; posts are not automatically published!' + description: '"Published on" date.

(WIP: Auto publishing feature + is in the works)
To schedule this post for future publishing, simply + set the date to the future.

WARNING: Data + is saved in the ipfs/ipfs-blog + public github repo as soon as you hit the save button. So any sensitive information + will also be publicly available on github, but hidden from the website blog.ipfs.io.' config: required: true date_format: YYYY/MM/DD export_format: YYYY-MM-DD -- name: publishing_date - type: datetime - label: Publishing Date - config: - required: false - date_format: - time_format: - display_utc: true - description: When the post should be published.
Use this to schedule publishing - the post in the future.
If you don't want to schedule, just ignore this. - default: now + display_utc: false - type: text name: permalink label: Permalink From 7661cf788bce3bce6f43154c7dad085148af68b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Bateira?= Date: Mon, 19 Apr 2021 10:30:06 +0000 Subject: [PATCH 3/9] Update from Forestry.io - Updated Forestry configuration --- .forestry/front_matter/templates/newslinks.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forestry/front_matter/templates/newslinks.yml b/.forestry/front_matter/templates/newslinks.yml index 0a7a1e28..18a9d802 100644 --- a/.forestry/front_matter/templates/newslinks.yml +++ b/.forestry/front_matter/templates/newslinks.yml @@ -45,7 +45,8 @@ fields: date_format: time_format: display_utc: true - default: now + export_format: YYYY-MM-DDThh:mm:ssZ + default: '' - type: text name: path label: URL From af7aa34420ec5999190b2f3617e47a1ffb58401b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Bateira?= Date: Mon, 19 Apr 2021 10:31:07 +0000 Subject: [PATCH 4/9] Update from Forestry.io - Updated Forestry configuration --- .forestry/front_matter/templates/newslinks.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.forestry/front_matter/templates/newslinks.yml b/.forestry/front_matter/templates/newslinks.yml index 18a9d802..3ef646fd 100644 --- a/.forestry/front_matter/templates/newslinks.yml +++ b/.forestry/front_matter/templates/newslinks.yml @@ -38,8 +38,13 @@ fields: - name: publishing_date type: datetime label: Publishing Date - description: When the link should be published.
Use this to schedule publishing - the link in the future.
If you don't want to schedule, just ignore this. + description: '(WIP: Auto publishing feature is in the works)

When + the link should be published.
Use this to schedule publishing the link in + the future.
If you don''t want to schedule, just ignore this.

WARNING: + Data is saved in the ipfs/ipfs-blog public github repo as soon as + you hit the save button. So any sensitive information will also be publicly + available on github, but hidden from the website blog.ipfs.io.' config: required: false date_format: From 872ad1e63eb75cf26e2d73513d3d25be65c13627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Bateira?= Date: Mon, 19 Apr 2021 10:44:38 +0000 Subject: [PATCH 5/9] Update from Forestry.io - Updated Forestry configuration --- .forestry/front_matter/templates/newslinks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forestry/front_matter/templates/newslinks.yml b/.forestry/front_matter/templates/newslinks.yml index 3ef646fd..2b035487 100644 --- a/.forestry/front_matter/templates/newslinks.yml +++ b/.forestry/front_matter/templates/newslinks.yml @@ -35,9 +35,9 @@ fields: export_format: YYYY-MM-DD description: For events, use the date of the event itself.
For all other link types, use the date the original item was published. - - name: publishing_date + - name: publish_date type: datetime - label: Publishing Date + label: Publish Date description: '(WIP: Auto publishing feature is in the works)

When the link should be published.
Use this to schedule publishing the link in the future.
If you don''t want to schedule, just ignore this.

WARNING: From 1a9338d00b0ad9146de1ebdf3acf0e382832ddac Mon Sep 17 00:00:00 2001 From: Ze Bateira Date: Fri, 16 Apr 2021 18:16:40 +0100 Subject: [PATCH 6/9] feat: exclude scheduled posts and links feat: automatically deploy scheduled posts or links --- .github/workflows/scheduled-publishing.yml | 26 ++++++ package-lock.json | 2 + package.json | 2 + scripts/scheduled-publishing.js | 98 ++++++++++++++++++++++ src/.vuepress/plugins/pageData.js | 44 +++++++++- src/.vuepress/theme/layouts/Blog.vue | 10 +-- src/.vuepress/theme/layouts/BlogPost.vue | 13 ++- src/.vuepress/theme/util/blogUtils.js | 9 +- src/_blog/events.md | 2 - src/_blog/welcome-to-ipfs-weekly-131.md | 1 - 10 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/scheduled-publishing.yml create mode 100755 scripts/scheduled-publishing.js diff --git a/.github/workflows/scheduled-publishing.yml b/.github/workflows/scheduled-publishing.yml new file mode 100644 index 00000000..317fea66 --- /dev/null +++ b/.github/workflows/scheduled-publishing.yml @@ -0,0 +1,26 @@ +name: Check for scheduled posts to publish +on: + schedule: + - cron: '* 9,21 * * *' +jobs: + check-n-publish: + name: Check for scheduled posts and publish if any found + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Install dependencies + run: npm ci + - name: Check for scheduled posts + run: echo "::set-output name=should_publish::$(${{ github.workspace }}/scripts/scheduled-publishing.js)" + id: should_publish_step + - name: Trigger Fleek Build + if: ${{ steps.should_publish_step.outputs.should_publish == 'true' }} + id: deploy + uses: fleekhq/action-deploy@v1 + with: + apiKey: ${{ secrets.FLEEK_API_KEY }} + - name: Scheduled posts published + if: ${{ steps.should_publish_step.outputs.should_publish == 'true' }} + run: echo "Check https://blog.ipfs.io" + diff --git a/package-lock.json b/package-lock.json index f2ee17d3..1194306d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-promise": "^5.1.0", "eslint-plugin-vue": "^7.9.0", + "gray-matter": "^4.0.2", "husky": "^6.0.0", "lint-staged": "^10.5.4", "lodash": "^4.17.21", @@ -41,6 +42,7 @@ "markdown-it-task-lists": "^2.1.1", "markdown-it-video": "^0.6.3", "npm-run-all": "^4.1.5", + "p-map": "^4.0.0", "postcss": "^7.0.35", "prettier": "^2.2.1", "slug": "^4.0.3", diff --git a/package.json b/package.json index 38bedadc..33e1421c 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-promise": "^5.1.0", "eslint-plugin-vue": "^7.9.0", + "gray-matter": "^4.0.2", "husky": "^6.0.0", "lint-staged": "^10.5.4", "lodash": "^4.17.21", @@ -38,6 +39,7 @@ "markdown-it-task-lists": "^2.1.1", "markdown-it-video": "^0.6.3", "npm-run-all": "^4.1.5", + "p-map": "^4.0.0", "postcss": "^7.0.35", "prettier": "^2.2.1", "slug": "^4.0.3", diff --git a/scripts/scheduled-publishing.js b/scripts/scheduled-publishing.js new file mode 100755 index 00000000..3cf9f6b8 --- /dev/null +++ b/scripts/scheduled-publishing.js @@ -0,0 +1,98 @@ +#!/usr/bin/env node + +'use strict' + +/** + * Scheduled Publishing of posts and links. + * This script checks for any blog posts and links that are scheduled to + * be published, but are to be published today. If there is at least + * one found, a build is trigged in fleek, updating the website + * with the latest data. + */ + +const fs = require('fs') +const path = require('path') + +const pMap = require('p-map') +const matter = require('gray-matter') +const dayjs = require('dayjs') + +const isBetween = require('dayjs/plugin/isBetween') +dayjs.extend(isBetween) + +async function main() { + // read files contents concurrently, 10 at a time + const contentDir = path.resolve(__dirname, '../src/_blog') + const files = await pMap( + await fs.promises.readdir(contentDir), + (filename) => { + if (!filename.endsWith('.md')) { + return null + } + + return fs.promises.readFile(path.resolve(contentDir, filename), 'utf8') + }, + { concurrency: 10 } + ) + + const output = files + // exclude possible nulls + .filter((result) => !!result) + // process files into publishable items (posts or links) + .reduce((items, fileContent) => { + const metadata = matter(fileContent).data + + if (metadata.type && metadata.data) { + // links + items.push(...metadata.data) + } else { + items.push(metadata) + } + + return items + }, []) + // check if there is at least one publish date in the future + .some((item) => { + let publishDate + + // blog post + if (item.permalink) { + publishDate = item.date + } + + // links + if (item.url && item.publish_date) { + publishDate = item.publish_date + } + + if (!publishDate) { + return false + } + + // we trim to the hour to avoid counting the initial delays on triggering + // the job, which could cause the time calculations to exclude specific + // scheduled dates and times. + const now = dayjs(new Date()).startOf('hour') + const timeMatch = dayjs(new Date(publishDate)).isBetween( + now.subtract(12, 'hour'), + now + ) + + // using stderr since stdout is used for GH workflow output + if (timeMatch) { + console.error(`Found post/link to publish: "${item.title}"`) + } + + return timeMatch + }) + + if (!output) { + console.error('Nothing found to publish.') + } + + // output true or false: should trigger publish or not + // GH Workflow step reads from stdout + console.log(output) +} + +main() diff --git a/src/.vuepress/plugins/pageData.js b/src/.vuepress/plugins/pageData.js index e503fa2a..79d5e59f 100644 --- a/src/.vuepress/plugins/pageData.js +++ b/src/.vuepress/plugins/pageData.js @@ -1,4 +1,32 @@ const slug = require('slug') +const dayjs = require('dayjs') + +function shouldBeHidden(frontmatter) { + const isDateInFuture = (date) => dayjs(new Date(date)).isAfter(dayjs()) + let shouldHide = frontmatter.hidden || false + + // sitemap config + if (frontmatter.sitemap) { + shouldHide = shouldHide || frontmatter.sitemap.exclude + } + + // scheduled posts + // see auto-publishing of scheduled posts here: https://github.com/ipfs/ipfs-blog/issues/147 + if ( + !shouldHide && + frontmatter.permalink && // permalink is unique to posts + frontmatter.date + ) { + shouldHide = shouldHide || isDateInFuture(frontmatter.date) + } + + // scheduled links (path is unique to links) + if (!shouldHide && frontmatter.path && frontmatter.publish_date) { + shouldHide = shouldHide || isDateInFuture(frontmatter.publish_date) + } + + return shouldHide +} module.exports = (options, context) => ({ extendPageData($page) { @@ -18,8 +46,8 @@ module.exports = (options, context) => ({ frontmatter.authorKey = authorKey } - // exclude a page from the feed & robots if excluded from sitemap - if (frontmatter.sitemap && frontmatter.sitemap.exclude) { + // exclude hidden pages (sitemap config, future publishes, etc) + if (shouldBeHidden(frontmatter)) { frontmatter.feed = { enable: false, } @@ -30,6 +58,18 @@ module.exports = (options, context) => ({ } else { frontmatter.meta = [noIndex] } + + frontmatter.hidden = true + $page.hidden = true + } + + // set links has hidden (future publishes, etc) + if (frontmatter.data) { + frontmatter.data.forEach((item) => { + if (shouldBeHidden(item)) { + item.hidden = true + } + }) } }, }) diff --git a/src/.vuepress/theme/layouts/Blog.vue b/src/.vuepress/theme/layouts/Blog.vue index 64eec2f0..c564b925 100644 --- a/src/.vuepress/theme/layouts/Blog.vue +++ b/src/.vuepress/theme/layouts/Blog.vue @@ -128,14 +128,8 @@ export default { return false } - if ( - page.frontmatter && - (page.frontmatter.sitemap ? !page.frontmatter.sitemap.exclude : true) - ) { - result.push({ - ...page, - category: defaultCategory, - }) + if (page.frontmatter && !page.frontmatter.hidden) { + result.push({ ...page, category: defaultCategory }) } }) diff --git a/src/.vuepress/theme/layouts/BlogPost.vue b/src/.vuepress/theme/layouts/BlogPost.vue index 8c954a05..4adb53dd 100644 --- a/src/.vuepress/theme/layouts/BlogPost.vue +++ b/src/.vuepress/theme/layouts/BlogPost.vue @@ -1,5 +1,5 @@