feat: guard bookmark hook when microsub is available, update category on tag change

- index: skip direct bookmark import when microsub plugin is present;
  microsub handles the flow and notifies blogroll via notifyBlogroll()
  to avoid duplicate entries
- bookmark-import: when blog already exists and category differs, update it
  instead of skipping (handles tag changes on existing bookmark posts)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
svemagie
2026-03-12 09:33:42 +01:00
parent 66bc404f03
commit 381b0397a5
2 changed files with 25 additions and 2 deletions

View File

@@ -17,6 +17,11 @@ const publicRouter = express.Router();
// Global hook router: intercepts POST requests site-wide to detect micropub // Global hook router: intercepts POST requests site-wide to detect micropub
// bookmark creations and auto-import the bookmarked site into the blogroll. // bookmark creations and auto-import the bookmarked site into the blogroll.
// Mounted at "/" via contentNegotiationRoutes (runs before auth middleware). // Mounted at "/" via contentNegotiationRoutes (runs before auth middleware).
//
// NOTE: When the Microsub plugin is installed it acts as the single source of
// truth for bookmarks — it creates the feed subscription AND notifies the
// blogroll via notifyBlogroll(). This hook therefore skips processing if
// Microsub is available, acting only as a standalone fallback.
const bookmarkHookRouter = express.Router(); const bookmarkHookRouter = express.Router();
bookmarkHookRouter.use((request, response, next) => { bookmarkHookRouter.use((request, response, next) => {
response.on("finish", () => { response.on("finish", () => {
@@ -40,6 +45,14 @@ bookmarkHookRouter.use((request, response, next) => {
request.body?.properties?.["bookmark-of"]?.[0]; request.body?.properties?.["bookmark-of"]?.[0];
if (!bookmarkOf) return; if (!bookmarkOf) return;
const { application } = request.app.locals;
// Microsub plugin is installed → it will handle this bookmark and notify
// the blogroll. Skip direct import to avoid duplicate entries.
if (application.collections?.has("microsub_channels")) {
return;
}
// Extract category from any micropub body format: // Extract category from any micropub body format:
// form-encoded: category=tech or category[]=tech&category[]=web // form-encoded: category=tech or category[]=tech&category[]=web
// JF2 JSON: { "category": ["tech", "web"] } // JF2 JSON: { "category": ["tech", "web"] }
@@ -51,7 +64,6 @@ bookmarkHookRouter.use((request, response, next) => {
? rawCategory[0] || "bookmarks" ? rawCategory[0] || "bookmarks"
: rawCategory || "bookmarks"; : rawCategory || "bookmarks";
const { application } = request.app.locals;
importBookmarkUrl(application, bookmarkOf, category).catch((err) => importBookmarkUrl(application, bookmarkOf, category).catch((err) =>
console.warn("[Blogroll] bookmark-import failed:", err.message) console.warn("[Blogroll] bookmark-import failed:", err.message)
); );

View File

@@ -43,8 +43,19 @@ export async function importBookmarkUrl(application, bookmarkUrl, category = "bo
}); });
if (existing) { if (existing) {
// If the category differs, update it (tag changed on the bookmark post)
if (existing.category !== category) {
await db.collection("blogrollBlogs").updateOne(
{ _id: existing._id },
{ $set: { category, updatedAt: new Date().toISOString() } },
);
console.log(
`[Blogroll] bookmark-import: updated category for "${existing.title}" → "${category}"`,
);
return { updated: true, siteUrl };
}
console.log( console.log(
`[Blogroll] bookmark-import: ${siteUrl} already in blogroll ("${existing.title}")` `[Blogroll] bookmark-import: ${siteUrl} already in blogroll ("${existing.title}")`,
); );
return { alreadyExists: true, siteUrl }; return { alreadyExists: true, siteUrl };
} }