mirror of
https://github.com/svemagie/indiekit-endpoint-blogroll.git
synced 2026-04-02 15:34:59 +02:00
fix: resolve [Object Object] bug and add sort/source API params
Rename duplicate "sync" locale key to "syncResult" to fix the sources list page showing [Object Object] instead of the Sync button label. Add sort=recent and source= query params to the blogs API for the sidebar widget tabs feature. Tag FeedLand blogs with source: "feedland" and expose source field for all blogs in API responses. Bump version to 1.0.22.
This commit is contained in:
@@ -18,16 +18,18 @@ import { handleMicrosubWebhook, isMicrosubAvailable } from "../sync/microsub.js"
|
||||
async function listBlogs(request, response) {
|
||||
const { application } = request.app.locals;
|
||||
|
||||
const { category, limit = 100, offset = 0 } = request.query;
|
||||
const { category, source, sort, limit = 100, offset = 0 } = request.query;
|
||||
|
||||
try {
|
||||
const blogs = await getBlogs(application, {
|
||||
category,
|
||||
source,
|
||||
sort,
|
||||
limit: Number(limit),
|
||||
offset: Number(offset),
|
||||
});
|
||||
|
||||
const total = await countBlogs(application, { category });
|
||||
const total = await countBlogs(application, { category, source });
|
||||
|
||||
response.json({
|
||||
items: blogs.map(sanitizeBlog),
|
||||
@@ -232,11 +234,11 @@ function sanitizeBlog(blog) {
|
||||
itemCount: blog.itemCount,
|
||||
pinned: blog.pinned,
|
||||
lastFetchAt: blog.lastFetchAt,
|
||||
source: blog.source || null,
|
||||
};
|
||||
|
||||
// Include Microsub metadata if applicable
|
||||
if (blog.source === "microsub") {
|
||||
sanitized.source = "microsub";
|
||||
sanitized.microsubChannel = blog.microsubChannelName;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,13 +77,13 @@ async function sync(request, response) {
|
||||
|
||||
if (result.skipped) {
|
||||
request.session.messages = [
|
||||
{ type: "warning", content: request.__("blogroll.sync.already_running") },
|
||||
{ type: "warning", content: request.__("blogroll.syncResult.already_running") },
|
||||
];
|
||||
} else if (result.success) {
|
||||
request.session.messages = [
|
||||
{
|
||||
type: "success",
|
||||
content: request.__("blogroll.sync.success", {
|
||||
content: request.__("blogroll.syncResult.success", {
|
||||
blogs: result.blogs.success,
|
||||
items: result.items.added,
|
||||
}),
|
||||
@@ -91,13 +91,13 @@ async function sync(request, response) {
|
||||
];
|
||||
} else {
|
||||
request.session.messages = [
|
||||
{ type: "error", content: request.__("blogroll.sync.error", { error: result.error }) },
|
||||
{ type: "error", content: request.__("blogroll.syncResult.error", { error: result.error }) },
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Blogroll] Manual sync error:", error);
|
||||
request.session.messages = [
|
||||
{ type: "error", content: request.__("blogroll.sync.error", { error: error.message }) },
|
||||
{ type: "error", content: request.__("blogroll.syncResult.error", { error: error.message }) },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ async function clearResync(request, response) {
|
||||
request.session.messages = [
|
||||
{
|
||||
type: "success",
|
||||
content: request.__("blogroll.sync.cleared_success", {
|
||||
content: request.__("blogroll.syncResult.cleared_success", {
|
||||
blogs: result.blogs.success,
|
||||
items: result.items.added,
|
||||
}),
|
||||
@@ -126,13 +126,13 @@ async function clearResync(request, response) {
|
||||
];
|
||||
} else {
|
||||
request.session.messages = [
|
||||
{ type: "error", content: request.__("blogroll.sync.error", { error: result.error }) },
|
||||
{ type: "error", content: request.__("blogroll.syncResult.error", { error: result.error }) },
|
||||
];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Blogroll] Clear resync error:", error);
|
||||
request.session.messages = [
|
||||
{ type: "error", content: request.__("blogroll.sync.error", { error: error.message }) },
|
||||
{ type: "error", content: request.__("blogroll.syncResult.error", { error: error.message }) },
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,18 @@ export async function getBlogs(application, options = {}) {
|
||||
if (!includeHidden) query.hidden = { $ne: true };
|
||||
if (category) query.category = category;
|
||||
if (sourceId) query.sourceId = new ObjectId(sourceId);
|
||||
if (options.source) query.source = options.source;
|
||||
|
||||
// Default sort: pinned first, then alphabetical
|
||||
// "recent" sort: pinned first, then by last fetch time (newest first)
|
||||
const sortOrder =
|
||||
options.sort === "recent"
|
||||
? { pinned: -1, lastFetchAt: -1, title: 1 }
|
||||
: { pinned: -1, title: 1 };
|
||||
|
||||
return collection
|
||||
.find(query)
|
||||
.sort({ pinned: -1, title: 1 })
|
||||
.sort(sortOrder)
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.toArray();
|
||||
@@ -46,11 +54,12 @@ export async function getBlogs(application, options = {}) {
|
||||
*/
|
||||
export async function countBlogs(application, options = {}) {
|
||||
const collection = getCollection(application);
|
||||
const { category, includeHidden = false } = options;
|
||||
const { category, source, includeHidden = false } = options;
|
||||
|
||||
const query = { status: { $ne: "deleted" } };
|
||||
if (!includeHidden) query.hidden = { $ne: true };
|
||||
if (category) query.category = category;
|
||||
if (source) query.source = source;
|
||||
|
||||
return collection.countDocuments(query);
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ export async function syncFeedlandSource(application, source) {
|
||||
const result = await upsertBlog(application, {
|
||||
...blog,
|
||||
category,
|
||||
source: "feedland",
|
||||
sourceId: source._id,
|
||||
});
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Dadurch werden alle zwischengespeicherten Einträge gelöscht und alles neu abgerufen. Fortfahren?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "This will delete all cached items and re-fetch everything. Continue?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Esto eliminará todas las entradas almacenadas en caché y volverá a descargar todo. ¿Continuar?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Esto eliminará todas las entradas almacenadas en caché y volverá a obtenerlo todo. ¿Continuar?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Cela supprimera toutes les entrées mises en cache et récupérera tout à nouveau. Continuer ?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "इससे सभी कैश किए गए आइटम हटा दिए जाएंगे और सब कुछ फिर से प्राप्त किया जाएगा। जारी रखें?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Ini akan menghapus semua item yang di-cache dan mengambil semuanya lagi. Lanjutkan?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Questo cancellerà tutti gli elementi memorizzati e recupererà tutto nuovamente. Continuare?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Dit verwijdert alle gecachte items en haalt alles opnieuw op. Doorgaan?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Spowoduje to usunięcie wszystkich elementów w pamięci podręcznej i ponowne pobranie wszystkiego. Kontynuować?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Isso excluirá todos os itens em cache e buscará tudo novamente. Continuar?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Isto eliminará todos os itens em cache e voltará a obter tudo. Continuar?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Ово ће обрисати све кеширане ставке и поново преузети све. Наставити?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "Detta kommer att ta bort alla cachade poster och hämta allt igen. Fortsätta?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"clearConfirm": "这将删除所有缓存的条目并重新获取所有内容。继续吗?"
|
||||
},
|
||||
|
||||
"sync": {
|
||||
"syncResult": {
|
||||
"success": "Synced {{blogs}} blogs, added {{items}} items.",
|
||||
"error": "Sync failed: {{error}}",
|
||||
"already_running": "A sync is already in progress.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@rmdes/indiekit-endpoint-blogroll",
|
||||
"version": "1.0.21",
|
||||
"version": "1.0.22",
|
||||
"description": "Blogroll endpoint for Indiekit. Aggregates blog feeds from OPML, JSON feeds, or manual entry.",
|
||||
"keywords": [
|
||||
"indiekit",
|
||||
|
||||
Reference in New Issue
Block a user