@rmdes/indiekit-endpoint-webmention-io 1.0.1 → 1.0.2
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.
|
@@ -5,6 +5,26 @@
|
|
|
5
5
|
import { getBlocklist, unblockDomain } from "../storage/blocklist.js";
|
|
6
6
|
import { unhideByDomain } from "../storage/webmentions.js";
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Format a date for display. Returns a human-readable string or null.
|
|
10
|
+
* NEVER pass raw Date objects to Nunjucks templates — the | date filter
|
|
11
|
+
* crashes on both Date objects and undefined/null.
|
|
12
|
+
* @param {*} value
|
|
13
|
+
* @returns {string|null}
|
|
14
|
+
*/
|
|
15
|
+
function formatDate(value) {
|
|
16
|
+
if (!value) return null;
|
|
17
|
+
const d = value instanceof Date ? value : new Date(value);
|
|
18
|
+
if (Number.isNaN(d.getTime())) return null;
|
|
19
|
+
return d.toLocaleDateString("en-GB", {
|
|
20
|
+
year: "numeric",
|
|
21
|
+
month: "short",
|
|
22
|
+
day: "numeric",
|
|
23
|
+
hour: "2-digit",
|
|
24
|
+
minute: "2-digit",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
8
28
|
export const blocklistController = {
|
|
9
29
|
/**
|
|
10
30
|
* GET /blocklist - Blocklist management page
|
|
@@ -21,9 +41,7 @@ export const blocklistController = {
|
|
|
21
41
|
const raw = await getBlocklist(collection);
|
|
22
42
|
entries = raw.map((entry) => ({
|
|
23
43
|
...entry,
|
|
24
|
-
blockedAt: entry.blockedAt
|
|
25
|
-
? entry.blockedAt.toISOString()
|
|
26
|
-
: entry.blockedAt,
|
|
44
|
+
blockedAt: formatDate(entry.blockedAt),
|
|
27
45
|
}));
|
|
28
46
|
}
|
|
29
47
|
|
|
@@ -16,14 +16,37 @@ import { getSyncState } from "../sync.js";
|
|
|
16
16
|
import { getMentionType, getMentionTitle, getAuthorName } from "../utils.js";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Format a date for direct display in templates (NOT through macros).
|
|
20
|
+
* Returns a human-readable string or null.
|
|
20
21
|
* @param {*} value
|
|
21
|
-
* @returns {string|
|
|
22
|
+
* @returns {string|null}
|
|
22
23
|
*/
|
|
23
|
-
function
|
|
24
|
-
if (!value) return
|
|
24
|
+
function formatDate(value) {
|
|
25
|
+
if (!value) return null;
|
|
26
|
+
const d = value instanceof Date ? value : new Date(value);
|
|
27
|
+
if (Number.isNaN(d.getTime())) return null;
|
|
28
|
+
return d.toLocaleDateString("en-GB", {
|
|
29
|
+
year: "numeric",
|
|
30
|
+
month: "short",
|
|
31
|
+
day: "numeric",
|
|
32
|
+
hour: "2-digit",
|
|
33
|
+
minute: "2-digit",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Convert any date value to an ISO 8601 string safe for the Nunjucks | date
|
|
39
|
+
* filter (which calls date-fns parseISO — crashes on Date objects, null, and
|
|
40
|
+
* undefined). Use this for values that pass through mention()/card() macros.
|
|
41
|
+
* @param {*} value
|
|
42
|
+
* @returns {string|null}
|
|
43
|
+
*/
|
|
44
|
+
function toISO(value) {
|
|
45
|
+
if (!value) return null;
|
|
25
46
|
if (value instanceof Date) return value.toISOString();
|
|
26
|
-
|
|
47
|
+
const d = new Date(value);
|
|
48
|
+
if (Number.isNaN(d.getTime())) return null;
|
|
49
|
+
return d.toISOString();
|
|
27
50
|
}
|
|
28
51
|
|
|
29
52
|
export const dashboardController = {
|
|
@@ -42,7 +65,7 @@ export const dashboardController = {
|
|
|
42
65
|
counts: { total: 0, hidden: 0, visible: 0 },
|
|
43
66
|
syncState: {
|
|
44
67
|
...getSyncState(),
|
|
45
|
-
lastSync:
|
|
68
|
+
lastSync: formatDate(getSyncState().lastSync),
|
|
46
69
|
},
|
|
47
70
|
cursor: {},
|
|
48
71
|
filter: "all",
|
|
@@ -96,7 +119,7 @@ export const dashboardController = {
|
|
|
96
119
|
locale: application.locale,
|
|
97
120
|
title: getMentionTitle({ name: item.name, "wm-property": item.wmProperty }),
|
|
98
121
|
description: html ? { html } : undefined,
|
|
99
|
-
published:
|
|
122
|
+
published: toISO(item.published || item.wmReceived),
|
|
100
123
|
url: item.sourceUrl,
|
|
101
124
|
user: {
|
|
102
125
|
avatar: { src: item.authorPhoto },
|
|
@@ -127,7 +150,7 @@ export const dashboardController = {
|
|
|
127
150
|
counts,
|
|
128
151
|
syncState: {
|
|
129
152
|
...getSyncState(),
|
|
130
|
-
lastSync:
|
|
153
|
+
lastSync: formatDate(getSyncState().lastSync),
|
|
131
154
|
},
|
|
132
155
|
cursor,
|
|
133
156
|
filter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rmdes/indiekit-endpoint-webmention-io",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Webmention moderation endpoint for Indiekit. Syncs webmentions from webmention.io into MongoDB with delete, block, and privacy removal capabilities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"indiekit",
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
</span>
|
|
174
174
|
</td>
|
|
175
175
|
<td>{{ entry.mentionsHidden or 0 }}</td>
|
|
176
|
-
<td>{{ entry.blockedAt
|
|
176
|
+
<td>{{ entry.blockedAt }}</td>
|
|
177
177
|
<td>
|
|
178
178
|
<form method="post" action="{{ wmEndpoint }}/blocklist/{{ entry.domain | urlencode }}/delete" style="display:inline">
|
|
179
179
|
<button type="submit" class="button button--small button--secondary"
|
package/views/webmentions.njk
CHANGED
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
<div class="wm-actions-bar">
|
|
140
140
|
<span class="wm-sync-info">
|
|
141
141
|
{% if syncState.lastSync %}
|
|
142
|
-
{{ __("webmention-io.sync.lastSync") }}: {{ syncState.lastSync
|
|
142
|
+
{{ __("webmention-io.sync.lastSync") }}: {{ syncState.lastSync }}
|
|
143
143
|
{% else %}
|
|
144
144
|
{{ __("webmention-io.sync.never") }}
|
|
145
145
|
{% endif %}
|