@geekity/cms 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +445 -63
  2. package/admin/layouts/shell.njk +13 -6
  3. package/admin/pages/comments/all.njk +3 -0
  4. package/admin/pages/error.njk +11 -0
  5. package/admin/pages/settings/discussion.njk +53 -0
  6. package/admin/pages/settings/email.njk +20 -0
  7. package/admin/pages/tools/personal-data.njk +67 -0
  8. package/admin/pages/users/edit.njk +1 -1
  9. package/admin/static/admin.css +69 -15
  10. package/dist/admin/comments.d.ts +5 -0
  11. package/dist/admin/comments.d.ts.map +1 -1
  12. package/dist/admin/comments.js +13 -0
  13. package/dist/admin/comments.js.map +1 -1
  14. package/dist/admin/documents.d.ts.map +1 -1
  15. package/dist/admin/documents.js +58 -31
  16. package/dist/admin/documents.js.map +1 -1
  17. package/dist/admin/headers.d.ts +14 -5
  18. package/dist/admin/headers.d.ts.map +1 -1
  19. package/dist/admin/headers.js +18 -6
  20. package/dist/admin/headers.js.map +1 -1
  21. package/dist/admin/index.d.ts +1 -1
  22. package/dist/admin/index.d.ts.map +1 -1
  23. package/dist/admin/index.js +1 -1
  24. package/dist/admin/index.js.map +1 -1
  25. package/dist/admin/menu.d.ts.map +1 -1
  26. package/dist/admin/menu.js +5 -1
  27. package/dist/admin/menu.js.map +1 -1
  28. package/dist/admin/personal-data.d.ts +35 -0
  29. package/dist/admin/personal-data.d.ts.map +1 -0
  30. package/dist/admin/personal-data.js +90 -0
  31. package/dist/admin/personal-data.js.map +1 -0
  32. package/dist/admin/routes.d.ts.map +1 -1
  33. package/dist/admin/routes.js +23 -4
  34. package/dist/admin/routes.js.map +1 -1
  35. package/dist/admin/session.d.ts +42 -1
  36. package/dist/admin/session.d.ts.map +1 -1
  37. package/dist/admin/session.js +74 -4
  38. package/dist/admin/session.js.map +1 -1
  39. package/dist/admin/settings-discussion.d.ts.map +1 -1
  40. package/dist/admin/settings-discussion.js +9 -1
  41. package/dist/admin/settings-discussion.js.map +1 -1
  42. package/dist/admin/settings-email.d.ts.map +1 -1
  43. package/dist/admin/settings-email.js +10 -1
  44. package/dist/admin/settings-email.js.map +1 -1
  45. package/dist/admin/settings.d.ts +39 -0
  46. package/dist/admin/settings.d.ts.map +1 -1
  47. package/dist/admin/settings.js +144 -0
  48. package/dist/admin/settings.js.map +1 -1
  49. package/dist/admin/store.d.ts +30 -0
  50. package/dist/admin/store.d.ts.map +1 -1
  51. package/dist/admin/store.js +68 -5
  52. package/dist/admin/store.js.map +1 -1
  53. package/dist/admin/templates.d.ts +2 -0
  54. package/dist/admin/templates.d.ts.map +1 -1
  55. package/dist/admin/templates.js +2 -0
  56. package/dist/admin/templates.js.map +1 -1
  57. package/dist/avatars/avatars.d.ts +112 -0
  58. package/dist/avatars/avatars.d.ts.map +1 -0
  59. package/dist/avatars/avatars.js +259 -0
  60. package/dist/avatars/avatars.js.map +1 -0
  61. package/dist/avatars/index.d.ts +4 -0
  62. package/dist/avatars/index.d.ts.map +1 -0
  63. package/dist/avatars/index.js +3 -0
  64. package/dist/avatars/index.js.map +1 -0
  65. package/dist/avatars/routes.d.ts +11 -0
  66. package/dist/avatars/routes.d.ts.map +1 -0
  67. package/dist/avatars/routes.js +33 -0
  68. package/dist/avatars/routes.js.map +1 -0
  69. package/dist/cli.d.ts +1 -1
  70. package/dist/cli.d.ts.map +1 -1
  71. package/dist/cli.js +128 -3
  72. package/dist/cli.js.map +1 -1
  73. package/dist/comments/records.d.ts +15 -0
  74. package/dist/comments/records.d.ts.map +1 -1
  75. package/dist/comments/records.js +51 -1
  76. package/dist/comments/records.js.map +1 -1
  77. package/dist/comments/routes.d.ts.map +1 -1
  78. package/dist/comments/routes.js +7 -1
  79. package/dist/comments/routes.js.map +1 -1
  80. package/dist/config.d.ts +37 -0
  81. package/dist/config.d.ts.map +1 -1
  82. package/dist/config.js +58 -0
  83. package/dist/config.js.map +1 -1
  84. package/dist/contact/index.d.ts +1 -1
  85. package/dist/contact/index.d.ts.map +1 -1
  86. package/dist/contact/index.js +1 -1
  87. package/dist/contact/index.js.map +1 -1
  88. package/dist/contact/records.d.ts +8 -2
  89. package/dist/contact/records.d.ts.map +1 -1
  90. package/dist/contact/records.js +13 -6
  91. package/dist/contact/records.js.map +1 -1
  92. package/dist/content/document.d.ts +10 -2
  93. package/dist/content/document.d.ts.map +1 -1
  94. package/dist/content/document.js +1 -0
  95. package/dist/content/document.js.map +1 -1
  96. package/dist/content/parser.d.ts.map +1 -1
  97. package/dist/content/parser.js +13 -0
  98. package/dist/content/parser.js.map +1 -1
  99. package/dist/content/store.d.ts +13 -2
  100. package/dist/content/store.d.ts.map +1 -1
  101. package/dist/content/store.js +45 -1
  102. package/dist/content/store.js.map +1 -1
  103. package/dist/content/writer.d.ts.map +1 -1
  104. package/dist/content/writer.js +4 -0
  105. package/dist/content/writer.js.map +1 -1
  106. package/dist/env.d.ts +18 -0
  107. package/dist/env.d.ts.map +1 -1
  108. package/dist/federation/article.d.ts +9 -0
  109. package/dist/federation/article.d.ts.map +1 -1
  110. package/dist/federation/article.js +24 -2
  111. package/dist/federation/article.js.map +1 -1
  112. package/dist/federation/federation.d.ts.map +1 -1
  113. package/dist/federation/federation.js +24 -6
  114. package/dist/federation/federation.js.map +1 -1
  115. package/dist/federation/inbox.d.ts +17 -3
  116. package/dist/federation/inbox.d.ts.map +1 -1
  117. package/dist/federation/inbox.js +72 -6
  118. package/dist/federation/inbox.js.map +1 -1
  119. package/dist/federation/mount.d.ts.map +1 -1
  120. package/dist/federation/mount.js +8 -3
  121. package/dist/federation/mount.js.map +1 -1
  122. package/dist/federation/paths.d.ts +5 -0
  123. package/dist/federation/paths.d.ts.map +1 -1
  124. package/dist/federation/paths.js +5 -0
  125. package/dist/federation/paths.js.map +1 -1
  126. package/dist/federation/quotes.d.ts +58 -0
  127. package/dist/federation/quotes.d.ts.map +1 -0
  128. package/dist/federation/quotes.js +89 -0
  129. package/dist/federation/quotes.js.map +1 -0
  130. package/dist/federation/replies.d.ts +23 -0
  131. package/dist/federation/replies.d.ts.map +1 -1
  132. package/dist/federation/replies.js +47 -10
  133. package/dist/federation/replies.js.map +1 -1
  134. package/dist/federation/wordpress.d.ts.map +1 -1
  135. package/dist/federation/wordpress.js +5 -4
  136. package/dist/federation/wordpress.js.map +1 -1
  137. package/dist/index.d.ts +23 -2
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +64 -7
  140. package/dist/index.js.map +1 -1
  141. package/dist/maintenance.d.ts +47 -0
  142. package/dist/maintenance.d.ts.map +1 -0
  143. package/dist/maintenance.js +78 -0
  144. package/dist/maintenance.js.map +1 -0
  145. package/dist/notifications/index.d.ts +1 -1
  146. package/dist/notifications/index.d.ts.map +1 -1
  147. package/dist/notifications/index.js +1 -1
  148. package/dist/notifications/index.js.map +1 -1
  149. package/dist/notifications/optouts.d.ts +6 -0
  150. package/dist/notifications/optouts.d.ts.map +1 -1
  151. package/dist/notifications/optouts.js +17 -0
  152. package/dist/notifications/optouts.js.map +1 -1
  153. package/dist/privacy/erase.d.ts +45 -0
  154. package/dist/privacy/erase.d.ts.map +1 -0
  155. package/dist/privacy/erase.js +77 -0
  156. package/dist/privacy/erase.js.map +1 -0
  157. package/dist/privacy/policy.d.ts +32 -0
  158. package/dist/privacy/policy.d.ts.map +1 -0
  159. package/dist/privacy/policy.js +37 -0
  160. package/dist/privacy/policy.js.map +1 -0
  161. package/dist/privacy/retention.d.ts +79 -0
  162. package/dist/privacy/retention.d.ts.map +1 -0
  163. package/dist/privacy/retention.js +133 -0
  164. package/dist/privacy/retention.js.map +1 -0
  165. package/dist/web/conversation.d.ts +9 -1
  166. package/dist/web/conversation.d.ts.map +1 -1
  167. package/dist/web/conversation.js +69 -39
  168. package/dist/web/conversation.js.map +1 -1
  169. package/dist/web/documents.d.ts +9 -0
  170. package/dist/web/documents.d.ts.map +1 -1
  171. package/dist/web/documents.js +31 -0
  172. package/dist/web/documents.js.map +1 -1
  173. package/dist/web/errors.d.ts +19 -0
  174. package/dist/web/errors.d.ts.map +1 -0
  175. package/dist/web/errors.js +93 -0
  176. package/dist/web/errors.js.map +1 -0
  177. package/dist/web/health.d.ts +6 -0
  178. package/dist/web/health.d.ts.map +1 -1
  179. package/dist/web/health.js +5 -1
  180. package/dist/web/health.js.map +1 -1
  181. package/dist/web/index.d.ts +5 -0
  182. package/dist/web/index.d.ts.map +1 -1
  183. package/dist/web/index.js +4 -0
  184. package/dist/web/index.js.map +1 -1
  185. package/dist/web/maintenance.d.ts +18 -0
  186. package/dist/web/maintenance.d.ts.map +1 -0
  187. package/dist/web/maintenance.js +113 -0
  188. package/dist/web/maintenance.js.map +1 -0
  189. package/dist/web/redirects.d.ts +75 -0
  190. package/dist/web/redirects.d.ts.map +1 -0
  191. package/dist/web/redirects.js +200 -0
  192. package/dist/web/redirects.js.map +1 -0
  193. package/dist/web/render.d.ts +9 -0
  194. package/dist/web/render.d.ts.map +1 -1
  195. package/dist/web/render.js +19 -0
  196. package/dist/web/render.js.map +1 -1
  197. package/dist/web/routes.d.ts.map +1 -1
  198. package/dist/web/routes.js +57 -0
  199. package/dist/web/routes.js.map +1 -1
  200. package/dist/web/well-known.d.ts +21 -0
  201. package/dist/web/well-known.d.ts.map +1 -0
  202. package/dist/web/well-known.js +66 -0
  203. package/dist/web/well-known.js.map +1 -0
  204. package/dist/webmention/fetch-public.d.ts +34 -0
  205. package/dist/webmention/fetch-public.d.ts.map +1 -0
  206. package/dist/webmention/fetch-public.js +101 -0
  207. package/dist/webmention/fetch-public.js.map +1 -0
  208. package/dist/webmention/reply-context.d.ts.map +1 -1
  209. package/dist/webmention/reply-context.js +12 -89
  210. package/dist/webmention/reply-context.js.map +1 -1
  211. package/package.json +1 -1
  212. package/templates/site/content/_data/site.json +7 -1
  213. package/templates/site/content/pages/privacy.md +127 -0
  214. package/themes/default/README.md +58 -19
  215. package/themes/default/layouts/500.njk +8 -0
  216. package/themes/default/layouts/503.njk +8 -0
@@ -1,8 +1,7 @@
1
1
  import { discoverPostType } from '../content/post-type.js';
2
- import { WEBMENTION_USER_AGENT } from './discovery.js';
2
+ import { fetchPublic, webUrl } from './fetch-public.js';
3
3
  import { elementsIn, parseHtml, textOf } from './html.js';
4
4
  import { citedEntry } from './microformats.js';
5
- import { publicHost } from './public-address.js';
6
5
  /**
7
6
  * Reply context: what a reply shows of the post it answers (TASK-123).
8
7
  *
@@ -16,8 +15,6 @@ import { publicHost } from './public-address.js';
16
15
  export const REPLY_CONTEXT_TIMEOUT_MS = 10_000;
17
16
  /** The most of a target page that is read. A bigger page is not read at all. */
18
17
  export const REPLY_CONTEXT_MAX_BYTES = 1_000_000;
19
- /** How many redirects are followed, each one checked like the first. */
20
- const MAX_REDIRECTS = 5;
21
18
  /** How many words of a target's text a preview keeps. */
22
19
  const EXCERPT_WORDS = 40;
23
20
  /** And how many characters, for a text with few spaces in it. */
@@ -30,49 +27,17 @@ const EXCERPT_CHARACTERS = 300;
30
27
  * over the whole exchange, and no page over the byte limit. Nothing throws.
31
28
  */
32
29
  export async function fetchReplyContext(target, options) {
33
- const maxBytes = options.maxBytes ?? REPLY_CONTEXT_MAX_BYTES;
34
- const signal = AbortSignal.timeout(options.timeoutMs ?? REPLY_CONTEXT_TIMEOUT_MS);
35
- let at = target;
36
- try {
37
- for (let hop = 0;; hop += 1) {
38
- const url = webUrl(at);
39
- if (url === undefined)
40
- return refuse('not an http or https URL');
41
- if (!(await publicHost(url.hostname, options.lookup))) {
42
- return refuse('not a public address');
43
- }
44
- const response = await fetch(url, {
45
- headers: { accept: 'text/html, */*;q=0.8', 'user-agent': WEBMENTION_USER_AGENT },
46
- redirect: 'manual',
47
- signal,
48
- });
49
- const location = response.headers.get('location');
50
- if (response.status >= 300 && response.status < 400 && location !== null) {
51
- await response.body?.cancel();
52
- if (hop === MAX_REDIRECTS)
53
- return refuse('too many redirects');
54
- at = new URL(location, url).href;
55
- continue;
56
- }
57
- if (!response.ok) {
58
- await response.body?.cancel();
59
- return refuse(`answered ${String(response.status)}`);
60
- }
61
- const type = response.headers.get('content-type') ?? '';
62
- if (!/^\s*(text\/html|application\/xhtml\+xml)/i.test(type)) {
63
- await response.body?.cancel();
64
- return refuse('not an HTML page');
65
- }
66
- const body = await readWithin(response, maxBytes);
67
- if (body === undefined)
68
- return refuse(`larger than ${String(maxBytes)} bytes`);
69
- const context = readReplyContext(body, target, url.href);
70
- return context === undefined ? refuse('nothing to show') : { ok: true, context };
71
- }
72
- }
73
- catch (thrown) {
74
- return refuse(thrown instanceof Error ? thrown.message : String(thrown));
75
- }
30
+ const fetched = await fetchPublic(target, {
31
+ lookup: options.lookup,
32
+ timeoutMs: options.timeoutMs ?? REPLY_CONTEXT_TIMEOUT_MS,
33
+ maxBytes: options.maxBytes ?? REPLY_CONTEXT_MAX_BYTES,
34
+ accept: 'text/html, */*;q=0.8',
35
+ contentType: { pattern: /^\s*(text\/html|application\/xhtml\+xml)/i, name: 'an HTML page' },
36
+ });
37
+ if (!fetched.ok)
38
+ return fetched;
39
+ const context = readReplyContext(new TextDecoder().decode(fetched.body), target, fetched.url);
40
+ return context === undefined ? refuse('nothing to show') : { ok: true, context };
76
41
  }
77
42
  /**
78
43
  * What a target page says about itself, or `undefined` when it says nothing a
@@ -112,35 +77,6 @@ export function readReplyContext(html, target, base = target) {
112
77
  return undefined;
113
78
  return { url: target, ...(name === '' ? {} : { name }), ...(text === '' ? {} : { text }) };
114
79
  }
115
- /** A response body when it is no bigger than the limit, else `undefined`. */
116
- async function readWithin(response, maxBytes) {
117
- const declared = Number(response.headers.get('content-length') ?? '0');
118
- if (declared > maxBytes) {
119
- await response.body?.cancel();
120
- return undefined;
121
- }
122
- const body = response.body;
123
- if (body === null)
124
- return '';
125
- const reader = body.getReader();
126
- const decoder = new TextDecoder();
127
- const chunks = [];
128
- let read = 0;
129
- for (;;) {
130
- const chunk = await reader.read();
131
- if (chunk.done)
132
- break;
133
- const value = chunk.value;
134
- read += value.length;
135
- if (read > maxBytes) {
136
- await reader.cancel();
137
- return undefined;
138
- }
139
- chunks.push(decoder.decode(value, { stream: true }));
140
- }
141
- chunks.push(decoder.decode());
142
- return chunks.join('');
143
- }
144
80
  /** The page's `<title>`, or empty. */
145
81
  function titleOf(root) {
146
82
  for (const element of elementsIn(root)) {
@@ -170,19 +106,6 @@ function excerpt(text) {
170
106
  cut = cut.slice(0, EXCERPT_CHARACTERS).trimEnd();
171
107
  return cut === normalized ? normalized : `${cut} …`;
172
108
  }
173
- /** A URL, when it is an http or https one with a host. */
174
- function webUrl(value) {
175
- let url;
176
- try {
177
- url = new URL(value);
178
- }
179
- catch {
180
- return undefined;
181
- }
182
- if (url.protocol !== 'http:' && url.protocol !== 'https:')
183
- return undefined;
184
- return url.hostname === '' ? undefined : url;
185
- }
186
109
  function refuse(reason) {
187
110
  return { ok: false, reason };
188
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reply-context.js","sourceRoot":"","sources":["../../src/webmention/reply-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reply-context.js","sourceRoot":"","sources":["../../src/webmention/reply-context.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekity/cms",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "A file-first CMS: Markdown content, a SQLite index, a Hono server that is both the editor and the public site.",
6
6
  "license": "MIT",
@@ -9,8 +9,14 @@
9
9
  { "label": "About", "url": "/about/" },
10
10
  { "label": "Search", "url": "/search/" }
11
11
  ],
12
- "footer": [{ "label": "RSS", "url": "/feed/" }]
12
+ "footer": [
13
+ { "label": "RSS", "url": "/feed/" },
14
+ { "label": "Privacy", "url": "/privacy/" }
15
+ ]
13
16
  },
17
+ "commentEmailRetentionDays": 180,
18
+ "addressHashRetentionDays": 30,
19
+ "contactMessageRetentionDays": 365,
14
20
  "postsPerPage": 10,
15
21
  "feedSize": 20
16
22
  }
@@ -0,0 +1,127 @@
1
+ ---
2
+ title: Privacy
3
+ permalink: /privacy/
4
+ description: What this site stores about the people who read it, write to it and comment on it, and for how long.
5
+ ---
6
+
7
+ > **To the owner of this site.** `geekity init` wrote this page from what the
8
+ > Geekity CMS does out of the box. It is a starting point, not legal advice,
9
+ > and it knows nothing about your hosting, your analytics, your mail provider
10
+ > or anything you added. Review it, correct it, and delete this note before
11
+ > you rely on it. If you change a retention period on Settings > Discussion,
12
+ > change the number here too. If you delete this page, delete the
13
+ > `Privacy | /privacy/` line from the footer menu as well, so nothing links to
14
+ > it.
15
+
16
+ This page says what this site stores about you, where it keeps it, how long it
17
+ keeps it, and who else sees it.
18
+
19
+ ## Reading the site
20
+
21
+ This site sets no cookies on your browser while you read it, and it runs no
22
+ analytics or advertising scripts. Its fonts, styles and scripts come from this
23
+ site, not from another server.
24
+
25
+ Pictures of other people, such as the avatar of somebody who replied from
26
+ another site, are fetched and stored by this site and served from here. Your
27
+ browser does not fetch them from the other server, so that server does not
28
+ learn your IP address.
29
+
30
+ When you follow a link from this site to another one, your browser tells that
31
+ site only which site you came from, not which page.
32
+
33
+ To slow down abuse, the site counts requests from each IP address for a few
34
+ minutes. The counts are kept in memory only, and they are lost when the site
35
+ restarts. The web server writes a log line for each request. By default the
36
+ line does not contain your IP address. The owner can turn that on, and whoever
37
+ hosts the site can keep its own logs.
38
+
39
+ ## Comments
40
+
41
+ When you leave a comment, the site stores:
42
+
43
+ - Your name, your website and the words you type. These are shown on the page
44
+ beside your comment, for as long as the comment is up.
45
+ - Your email address, if you give one. It is optional, it is never shown, and
46
+ it is used to decide whether your comment needs a moderator and to email you
47
+ about replies if you ask for that. The site deletes it after 180 days.
48
+ - A salted hash of your IP address, which lets the site spot a run of spam from
49
+ one place. The IP address itself is never stored. The site deletes the hash
50
+ after 30 days.
51
+
52
+ If this site can send mail, a new comment waiting for a moderator is emailed
53
+ to the people who moderate it.
54
+
55
+ Comments are stored as files beside the posts, and the site may keep those
56
+ files in version control. A copy deleted from the site can stay in that
57
+ history until the owner rewrites it.
58
+
59
+ **Reply emails (optional).** If this site can send mail and you tick "email me
60
+ when somebody replies", the site emails you when a reply to your comment is
61
+ approved. Each message has an unsubscribe link. If you unsubscribe, the site
62
+ keeps your address on a list of addresses it must not email about replies.
63
+ The mail provider the owner chose sees each address a message goes to.
64
+
65
+ ## The contact form (optional)
66
+
67
+ If this site has a contact form and you send a message, the site stores your
68
+ name, your email address, the subject, the message and a salted hash of your
69
+ IP address, in a private file that is not published. If the site can send
70
+ mail, it also emails the message to the owner, through the mail provider the
71
+ owner chose. The site deletes the message after 365 days, and the hash after 30
72
+ days.
73
+
74
+ ## Spam checking with Akismet (optional)
75
+
76
+ Only if the owner turns it on, the site sends each new comment, webmention and
77
+ contact message to Akismet, a spam-checking service run by Automattic. Akismet
78
+ receives your IP address, your browser's user agent, the page you came from,
79
+ your name, email address and website, and what you wrote. Akismet's own privacy
80
+ policy covers what it does with them.
81
+
82
+ ## Replies from other sites
83
+
84
+ **Webmentions.** When another site links to a post here and sends a
85
+ webmention, this site fetches that page and stores its author's name, website
86
+ and avatar address and the words of the page, and may show them as a comment.
87
+ They are a copy of a page that is already public. When a post here links to
88
+ another site, this site sends that site a webmention, which tells it only the
89
+ address of the post.
90
+
91
+ **The fediverse.** Posts here are published over ActivityPub, so they are
92
+ copied to the servers of the people who follow this site, on Mastodon and
93
+ similar services. If you follow this site from one of those services, the site
94
+ stores your public profile: your handle, display name, avatar address and
95
+ profile address, until you unfollow. That list is kept in the site's files
96
+ beside the posts. When you reply to, like, boost or quote a
97
+ post, the site stores the activity and who sent it, and may show replies under
98
+ the post.
99
+
100
+ ## Accounts
101
+
102
+ The people who write this site have accounts. The site stores each account's
103
+ username, email address, a hash of its password and its public profile. A
104
+ signed-in account gets one cookie, `__Host-geekity_session` (called
105
+ `geekity_session` on a site without https), which holds a random session id and
106
+ nothing else. It is deleted when the person signs out or the session expires.
107
+
108
+ ## How long the site keeps things
109
+
110
+ | What | How long |
111
+ | ------------------------------------------------ | ------------------ |
112
+ | The email address on a comment | 180 days |
113
+ | The hash of the IP address on a comment or message | 30 days |
114
+ | A contact message | 365 days |
115
+ | Everything else above | Until it is deleted |
116
+
117
+ The site checks these periods when it starts and every six hours after that.
118
+
119
+ ## Asking for your data to be removed
120
+
121
+ Write to the owner of this site. The owner can find every comment and contact
122
+ message that carries your email address and erase them together, on
123
+ Tools > Personal data: your comments stay in their threads signed "Anonymous",
124
+ without your email, website or address hash, your messages are deleted, and
125
+ your address comes off the list of addresses not to email about replies.
126
+ Comments left without an email address, webmentions and fediverse replies are
127
+ removed one at a time.
@@ -17,6 +17,8 @@ themes/default/
17
17
  author.njk one person's archive, paginated
18
18
  search.njk the search form and what it found, paginated
19
19
  404.njk nothing at this URL
20
+ 500.njk the request failed on the server
21
+ 503.njk the site is in maintenance mode
20
22
  partials/
21
23
  post-list.njk the h-feed a listing is made of
22
24
  pagination.njk previous/next pager
@@ -373,6 +375,24 @@ alone.
373
375
 
374
376
  `layouts/404.njk` says `Content not found.` and links home and to the search.
375
377
 
378
+ `layouts/500.njk` is the page a request gets when the server fails while
379
+ answering it (TASK-129). It says `Something went wrong.` in an
380
+ `article.server-error` and links home. The context is the 404's: `title`,
381
+ `url` and `page.url`. The response is a 500 with `Cache-Control: no-store`, and
382
+ the error itself goes to the server's log, never into the page. If this template
383
+ fails too, the CMS answers with a plain HTML page of its own instead, so a theme
384
+ cannot turn one failure into a crash. A request for the `.md` or `.json`
385
+ representation gets a 500 in that format and never reaches this template.
386
+
387
+ `layouts/503.njk` is the page a request gets while the site is in maintenance
388
+ mode (TASK-130). It says `Down for maintenance.` in an `article.maintenance`.
389
+ The context is the 404's, plus `until` (an ISO 8601 time) and `untilText` (the
390
+ same time as an HTTP date) when the operator named when the site should be
391
+ back. The response is a 503 with `Retry-After` and `Cache-Control: no-store`.
392
+ The theme's files under `/theme/` are still served, so the page can use the
393
+ stylesheet. If this template fails, the CMS answers with a plain HTML page of
394
+ its own.
395
+
376
396
  ### Search
377
397
 
378
398
  `layouts/search.njk` is the page at `/search/` (TASK-22). It prints
@@ -1031,8 +1051,9 @@ Category archives get their own three the same way.
1031
1051
  ## The conversation
1032
1052
 
1033
1053
  `conversation` is what has been said about a post: the fediverse replies, likes
1034
- and boosts its inbox was sent, the comments people left on the page itself, and
1035
- the webmentions other pages sent it.
1054
+ and boosts its inbox was sent, the fediverse posts that quoted it with its
1055
+ author's approval, the comments people left on the page itself, and the
1056
+ webmentions other pages sent it.
1036
1057
  It is on the context of a rendered post **only when there is something in it**,
1037
1058
  so a post nobody has answered renders no empty section and a layout can simply
1038
1059
  ask:
@@ -1072,29 +1093,29 @@ the thread, because it is not an answer.
1072
1093
  | `replies` | The replies to the post, oldest first, each carrying its own `replies`. See below. |
1073
1094
  | `likes` | The likes, oldest first, in the same shape. |
1074
1095
  | `boosts` | The boosts, oldest first, in the same shape. A webmention `repost` is one of them. |
1075
- | `mentions` | The pages that linked here without answering, oldest first, in the same shape. |
1096
+ | `mentions` | The pages and fediverse quotes about this post, oldest first, in the same shape. |
1076
1097
  | `counts.replies` | How many replies, counted through the whole thread rather than the top of it. |
1077
1098
  | `counts.likes`, `counts.boosts`, `counts.mentions` | How many of each. |
1078
1099
  | `counts.total` | All four added up. Zero never reaches a template: there would be no `conversation` at all. |
1079
1100
 
1080
1101
  Each entry — a reply, a like or a boost — is:
1081
1102
 
1082
- | Key | What it holds |
1083
- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1084
- | `id` | What it is called: a reply's own note id, which is what an answer to it names. |
1085
- | `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here. |
1086
- | `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. The last two only ever come from a webmention. |
1087
- | `author.name` | The best name available: their display name, else their handle, else their id. For a webmention, the source's `h-card` name, else its host. |
1088
- | `author.handle` | `@user@host`, or `null`. Taken from the follower profile the site holds, else guessed from the actor URL. `null` for a native comment. |
1089
- | `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link. |
1090
- | `author.avatar` | Their avatar, or `null`. The site knows one for an actor that follows it and for a webmention whose `h-card` carried a `u-photo`. |
1091
- | `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment. |
1092
- | `url` | Where it can be read: the remote note's `url` for a fediverse reply, the source page for a webmention, and `{permalink}#comment-{id}` — this page's own anchor — for a native comment. |
1093
- | `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost. |
1094
- | `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter. |
1095
- | `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction. |
1096
- | `status` | `"published"`. On the record for the sources that moderate. |
1097
- | `replies` | The replies to this one, oldest first, nested as deep as the site has seen. |
1103
+ | Key | What it holds |
1104
+ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1105
+ | `id` | What it is called: a reply's own note id, which is what an answer to it names. |
1106
+ | `source` | `"activitypub"` for a fediverse reply, `"comment"` for one left on the page, `"webmention"` for another page linking here. |
1107
+ | `kind` | `"reply"`, `"like"`, `"boost"`, `"repost"` or `"mention"`. A `repost` comes from a webmention; a `mention` is a webmention or an approved fediverse quote. |
1108
+ | `author.name` | The best name available: their display name, else their handle, else their id. For a webmention, the source's `h-card` name, else its host. |
1109
+ | `author.handle` | `@user@host`, or `null`. Taken from the follower profile the site holds, else guessed from the actor URL. `null` for a native comment. |
1110
+ | `author.url` | Their profile page, the website a commenter typed, or a webmention author's `u-url`. May be `null`, so guard the link. |
1111
+ | `author.avatar` | Their avatar, or `null`. The site knows one for an actor that follows it and for a webmention whose `h-card` carried a `u-photo`. Always a same-origin `/_geekity/avatars/…` path, never the remote URL: see [Avatars](#avatars). |
1112
+ | `author.actorId` | Their id, which is what identifies them however they are named. `null` for a native comment. |
1113
+ | `url` | Where it can be read: the remote note's `url` for a fediverse reply or quote, the source page for a webmention, and `{permalink}#comment-{id}` — this page's own anchor — for a native comment. |
1114
+ | `content` | What it says, **already sanitised**, so print it with `\| safe`. Empty for a like or a boost. |
1115
+ | `published` | A `Date`: when it was published, or when it arrived if it did not say. Use the `date` filter. |
1116
+ | `inReplyTo` | What it answers — the post's ActivityPub id, or another reply's — and `null` for a reaction. |
1117
+ | `status` | `"published"`. On the record for the sources that moderate. |
1118
+ | `replies` | The replies to this one, oldest first, nested as deep as the site has seen. |
1098
1119
 
1099
1120
  Three rules decide what is in the thread, and they are the CMS's rather than a
1100
1121
  theme's: a reply whose author deleted it is gone, and its own answers move up to
@@ -1151,6 +1172,24 @@ and then loops over exactly the keys above. The slug is what names the post's
1151
1172
  comment file under `content/_data/comments/`; the format is documented in
1152
1173
  backlog doc-6.
1153
1174
 
1175
+ ### Avatars
1176
+
1177
+ A reader's browser never fetches a face from the server it lives on. The
1178
+ `author.avatar` a theme is handed is a path on this site, under
1179
+ `/_geekity/avatars/`, and the CMS fetches the picture, crops it to an
1180
+ 80-pixel square WebP (twice the 40 pixels this theme shows a commenter at)
1181
+ and keeps it under `data/avatars/`. Print it as it is; it needs no filter.
1182
+
1183
+ The route serves only the pictures the site shows: a follower who has
1184
+ liked, boosted, quoted or answered a post, and the author of an approved
1185
+ comment or webmention. Any other URL is a 404, and nothing is fetched for it.
1186
+ Pictures are fetched in the background when the site starts and every six
1187
+ hours after, refreshed once they are a week old, and forgotten once nothing
1188
+ shows them. A picture that cannot be fetched, is over 2 MB, or is not a JPEG,
1189
+ PNG, GIF, WebP or AVIF is served as a grey placeholder, and tried again an
1190
+ hour later. `data/avatars/` is a cache: delete it and every picture is fetched
1191
+ again.
1192
+
1154
1193
  ## The comment form
1155
1194
 
1156
1195
  `commentForm` is on the context of a rendered post **only when that post is
@@ -0,0 +1,8 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ <article class="server-error">
5
+ <h1 class="page-title">Something went wrong.</h1>
6
+ <p>This page could not be shown because of a problem on the server. Try again in a moment, or go <a href="{{ "/" | url }}">home</a>.</p>
7
+ </article>
8
+ {% endblock %}
@@ -0,0 +1,8 @@
1
+ {% extends "layouts/base.njk" %}
2
+
3
+ {% block content %}
4
+ <article class="maintenance">
5
+ <h1 class="page-title">Down for maintenance.</h1>
6
+ <p>This site is down for maintenance and will be back shortly.{% if until %} It should be back by <time datetime="{{ until }}">{{ untilText }}</time>.{% endif %} Please try again then.</p>
7
+ </article>
8
+ {% endblock %}