Add feed endpoints; fix cc license logo styles; add humans.txt

This commit is contained in:
Garrett Mills 2022-04-05 12:59:26 -05:00
parent e461635f3a
commit e643bf6df0
8 changed files with 128 additions and 15 deletions

View File

@ -8,7 +8,7 @@
"lib": "lib" "lib": "lib"
}, },
"dependencies": { "dependencies": {
"@extollo/lib": "^0.9.28", "@extollo/lib": "^0.9.31",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"feed": "^4.2.2", "feed": "^4.2.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",

View File

@ -2,7 +2,7 @@ lockfileVersion: 5.3
specifiers: specifiers:
'@extollo/cc': ^0.6.0 '@extollo/cc': ^0.6.0
'@extollo/lib': ^0.9.28 '@extollo/lib': ^0.9.31
copyfiles: ^2.4.1 copyfiles: ^2.4.1
feed: ^4.2.2 feed: ^4.2.2
rimraf: ^3.0.2 rimraf: ^3.0.2
@ -13,7 +13,7 @@ specifiers:
zod: ^3.11.6 zod: ^3.11.6
dependencies: dependencies:
'@extollo/lib': 0.9.28 '@extollo/lib': 0.9.31
copyfiles: 2.4.1 copyfiles: 2.4.1
feed: 4.2.2 feed: 4.2.2
rimraf: 3.0.2 rimraf: 3.0.2
@ -112,8 +112,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@extollo/lib/0.9.28: /@extollo/lib/0.9.31:
resolution: {integrity: sha512-lMI2FWOTKbRsqJrOAvZofzfz0DaNwWecYsDX98XkNbktaUjhaGc7xr1OVxscxUC/Edapyj/p02MLdsUoIsARxA==} resolution: {integrity: sha512-sYtqWTL+hmkPZ44fwWdRsHK1081m98547r9snFm8i+ou13Npw3i4RBf8k+uFRUCayMM4PKVWqgo0bZJLvO4W1g==}
dependencies: dependencies:
'@atao60/fse-cli': 0.1.7 '@atao60/fse-cli': 0.1.7
'@extollo/ui': 0.1.0_@types+node@14.18.12 '@extollo/ui': 0.1.0_@types+node@14.18.12

View File

@ -1,5 +1,6 @@
import {Controller, view, Injectable, Collection} from '@extollo/lib' import {Controller, view, Injectable, Collection, Inject, Routing, plaintext} from '@extollo/lib'
import {FeedPost} from '../../models/FeedPost.model' import {FeedPost} from '../../models/FeedPost.model'
import * as RSSFeed from 'feed'
/** /**
* Feed Controller * Feed Controller
@ -8,9 +9,72 @@ import {FeedPost} from '../../models/FeedPost.model'
*/ */
@Injectable() @Injectable()
export class Feed extends Controller { export class Feed extends Controller {
@Inject()
protected readonly routing!: Routing
public async feed(feedPosts: Collection<FeedPost>) { public async feed(feedPosts: Collection<FeedPost>) {
return view('feed', { return view('feed', {
feedPosts: feedPosts.toArray(), feedPosts: feedPosts.toArray(),
}) })
} }
public async rss(feedPosts: Collection<FeedPost>) {
const feed = this.getFeed(feedPosts)
return plaintext(feed.rss2()).contentType('application/rss+xml; charset=UTF-8')
}
public async atom(feedPosts: Collection<FeedPost>) {
const feed = this.getFeed(feedPosts)
return plaintext(feed.atom1()).contentType('application/atom+xml; charset=UTF-8')
}
public async json(feedPosts: Collection<FeedPost>) {
const feed = this.getFeed(feedPosts)
return plaintext(feed.json1()).contentType('application/feed+json; charset=UTF-8')
}
protected getFeed(feedPosts: Collection<FeedPost>): RSSFeed.Feed {
const feed = new RSSFeed.Feed({
title: 'Garrett Mills',
description: 'A sporadic collection of my thoughts, blog posts, and project updates',
id: `${this.routing.getAppUrl()}#about`,
link: this.routing.getNamedPath('feed').toRemote,
language: 'en',
image: this.routing.getAssetPath('favicon', 'apple-touch-icon.png').toRemote,
favicon: this.routing.getAssetPath('favicon', 'favicon.ico').toRemote,
copyright: `Copyright (c) ${(new Date).getFullYear()} Garrett Mills. See website for licensing details.`,
updated: feedPosts.whereMax('postedAt').first()?.postedAt,
generator: '',
feedLinks: {
json: this.routing.getNamedPath('feed.json').toRemote,
atom: this.routing.getNamedPath('feed.atom').toRemote,
rss: this.routing.getNamedPath('feed.rss').toRemote,
},
author: {
name: 'Garrett Mills',
email: 'shout@garrettmills.dev',
link: 'https://garrettmills.dev/#about',
},
})
feed.addCategory('Technology')
feed.addCategory('Software Development')
feedPosts.each(post => {
feed.addItem({
title: post.tag, // FIXME better title generation
date: post.postedAt,
id: `${this.routing.getNamedPath('feed')}#${post.feedPostId}`,
link: `${this.routing.getNamedPath('feed')}#${post.feedPostId}`,
content: post.body,
author: [{
name: 'Garrett Mills',
email: 'shout@garrettmills.dev',
link: 'https://garrettmills.dev/#about',
}],
})
})
return feed
}
} }

View File

@ -1,4 +1,4 @@
import {Controller, view, Injectable, SecurityContext, Inject, Collection, Config, Routing, file, Application} from '@extollo/lib' import {Controller, view, Injectable, SecurityContext, Inject, Collection, Config, Routing, file, Application, plaintext} from '@extollo/lib'
import {WorkItem} from '../../models/WorkItem.model' import {WorkItem} from '../../models/WorkItem.model'
import {FeedPost} from '../../models/FeedPost.model' import {FeedPost} from '../../models/FeedPost.model'
@ -82,4 +82,10 @@ export class Home extends Controller {
.appPath('resources', 'assets', 'favicon', 'favicon.ico') .appPath('resources', 'assets', 'favicon', 'favicon.ico')
) )
} }
humans() {
return Application.getApplication()
.appPath('resources', 'assets', 'humans.txt')
.read()
}
} }

View File

@ -14,6 +14,9 @@ Route
.calls<Home>(Home, home => home.welcome) .calls<Home>(Home, home => home.welcome)
.alias('home') .alias('home')
Route.get('/humans.txt')
.calls<Home>(Home, home => home.humans)
Route.get('/technical') Route.get('/technical')
.calls<Home>(Home, home => home.technical) .calls<Home>(Home, home => home.technical)
@ -25,11 +28,6 @@ Route
.calls<Home>(Home, home => home.optOut) .calls<Home>(Home, home => home.optOut)
.alias('opt-out') .alias('opt-out')
Route.get('/feed')
.parameterMiddleware(LoadFeedPosts, {all: true})
.calls<Feed>(Feed, feed => feed.feed)
.alias('feed')
Route.get('/snippet/:slug') Route.get('/snippet/:slug')
.parameterMiddleware(LoadSnippet) .parameterMiddleware(LoadSnippet)
.calls<Snippets>(Snippets, snippets => snippets.viewSnippet) .calls<Snippets>(Snippets, snippets => snippets.viewSnippet)
@ -39,6 +37,28 @@ Route
Route.get('/favicon.ico') Route.get('/favicon.ico')
.calls<Home>(Home, home => home.favicon) .calls<Home>(Home, home => home.favicon)
Route.group('feed', () => {
Route.get('/')
.parameterMiddleware(LoadFeedPosts, {all: true})
.calls<Feed>(Feed, feed => feed.feed)
.alias('feed')
Route.get('/rss.xml')
.parameterMiddleware(LoadFeedPosts, {all: true})
.calls<Feed>(Feed, feed => feed.rss)
.alias('feed.rss')
Route.get('/atom.xml')
.parameterMiddleware(LoadFeedPosts, {all: true})
.calls<Feed>(Feed, feed => feed.atom)
.alias('feed.atom')
Route.get('/json.json')
.parameterMiddleware(LoadFeedPosts, {all: true})
.calls<Feed>(Feed, feed => feed.json)
.alias('feed.json')
})
}) })
.pre(SessionAuthMiddleware) .pre(SessionAuthMiddleware)
.pre(PageView) .pre(PageView)

View File

@ -0,0 +1,16 @@
/* PEOPLE */
Garrett Mills - Developer/Speaker/Designer
E-Mail: shout@garrettmills.dev
Twitter: @glmdev
From: Lawrence, Kansas, USA (Rock Chalk!)
/* SITE */
Updated: 2022-04-05
Language: English
Doctype: HTML5
This site was built with Extollo, a free & libre application framework.
Learn more at: https://extollo.garrettmills.dev/
Copyright (C) 2022 Garrett Mills. All Rights Reserved.
/* OTHER */
Just a little something for the humans scraping the web... -GM

View File

@ -10,6 +10,12 @@ block content
.fira-p .fira-p
p This page contains a smattering of technical information that I think some people might find interesting, but not enough people for it to be included on the main page. p This page contains a smattering of technical information that I think some people might find interesting, but not enough people for it to be included on the main page.
h3 Source Code & Licensing
a(href='https://creativecommons.org/licenses/by-nc-sa/4.0/' target='_blank' style='margin-top: 15px')
img(src=asset('cc-by-nc-sa.png'))
p This website, its source code, and its contents are licensed under the terms of the Creative Commons BY-NC-SA 4.0 license. Learn more <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">here</a>.
p The source code for this site is available openly under the terms of the aforementioned license. You can view it <a href="https://code.garrettmills.dev/garrettmills/www" target="_blank">here</a>.
h3 Framework h3 Framework
p This site is built with Extollo, my free & libre application framework. You can learn more about Extollo <a href="https://extollo.garrettmills.dev" target="_blank">here</a>. p This site is built with Extollo, my free & libre application framework. You can learn more about Extollo <a href="https://extollo.garrettmills.dev" target="_blank">here</a>.

View File

@ -15,9 +15,10 @@ head
block style block style
link(rel='stylesheet' href=asset('main.css')) link(rel='stylesheet' href=asset('main.css'))
link(rel='author' href='humans.txt') link(rel='author' href='/humans.txt')
link(rel="alternate" href="/feed/atom.xml" title="Garrett Mills - Posts & Updates" type="application/atom+xml") link(rel="alternate" href="/feed/atom.xml" title="Garrett Mills - Posts & Updates" type="application/atom+xml")
link(rel="alternate" href="/feed/rss.xml" title="Garrett Mills - Posts & Updates" type="application/rss+xml") link(rel="alternate" href="/feed/rss.xml" title="Garrett Mills - Posts & Updates" type="application/rss+xml")
link(rel="alternate" href="/feed/json.json" title="Garrett Mills - Posts & Updates" type="application/feed+json")
link(rel='apple-touch-icon' sizes='180x180' href=asset('favicon/apple-touch-icon.png')) link(rel='apple-touch-icon' sizes='180x180' href=asset('favicon/apple-touch-icon.png'))
link(rel='manifest' href=asset('favicon/site.webmanifest')) link(rel='manifest' href=asset('favicon/site.webmanifest'))
@ -34,8 +35,8 @@ body
img(src=asset('ffox.png') width="75" style="margin-top: -1px") img(src=asset('ffox.png') width="75" style="margin-top: -1px")
.by-line garrettmills .by-line garrettmills
.copy#tagline(title="my, aren't you curious...") copyright &copy; #{(new Date()).getFullYear()} garrett mills .copy#tagline(title="my, aren't you curious...") copyright &copy; #{(new Date()).getFullYear()} garrett mills
.copyright .copyright(style='display: flex; justify-content: right')
a(href='https://creativecommons.org/licenses/by-nc-sa/4.0/' target='_blank') a(style='display: flex; padding-top: 10px' href='https://creativecommons.org/licenses/by-nc-sa/4.0/' target='_blank')
img(src=asset('cc-by-nc-sa-small.png') title='This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License') img(src=asset('cc-by-nc-sa-small.png') title='This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License')
if false if false
div.auth-container div.auth-container