openvibers/openvibe.deals Commits

API: a moderator-removed deal answers 410 like its page instead of serving its title, description and link; moderators still read it

OP OpenVibers committed 23 Sept 2026 · 22978517fe · 2 files, +15 −1


Changes

ddiff --git a/server/http/api.js b/server/http/api.js
iindex 47d486d..0f55b9d 100644
---- a/server/http/api.js
++++ b/server/http/api.js
@@@ -69,7 +69,15 @@ function createApi(ctx) {
return { sort: req.query.sort === 'new' ? 'new' : 'hot', page, total: listings.countActive(), offers: rows.map((o) => publication.offerDto(publication.offerView(o))) };
}));
-- router.get('/offers/:id', run((req) => offerOut(reads.mustFind(req.params.id))));
++ // A removed deal answers like its page (410, reason only); moderators still read the whole record.
++ router.get('/offers/:id', run((req) => {
++ const offer = reads.mustFind(req.params.id);
++ const root = reads.root(offer);
++ if (root.status === 'disabled' && !access.isModerator(req.viewer)) {
++ throw new ApiError(410, 'offer.disabled', 'This deal was removed by moderators', { id: root.id, slug: root.slug, status: 'disabled', reason: root.disabled_reason });
++ }
++ return offerOut(offer);
++ }));
router.get('/offers/:id/hotness', run((req) => {
const root = reads.root(reads.mustFind(req.params.id));
ddiff --git a/test/pages.test.js b/test/pages.test.js
iindex 12f75b3..4b2fcd0 100644
---- a/test/pages.test.js
++++ b/test/pages.test.js
@@@ -129,6 +129,12 @@ const { boot, check, done, robotsOf, jsonLd, HOUR } = require('./helpers/boot');
assert.strictEqual(thread.visibility, 'hidden', 'the disabled deal\'s discussion is hidden too');
assert.strictEqual((await t.get(`/d/${target.slug}`)).status, 410);
assert.strictEqual((await t.get(`/d/${target.slug}.json`)).status, 410);
++ for (const id of [target.id, target.slug]) {
++ const api = await t.get(`/api/v1/offers/${id}`);
++ assert.strictEqual(api.status, 410, 'the API does not serve a removed deal either');
++ assert.ok(!api.text.includes('Drone Pro'), 'no title, description or link of a removed deal');
++ }
++ assert.strictEqual((await t.get(`/api/v1/offers/${target.id}`, { as: t.mod })).status, 200, 'moderators still read it');
assert.ok(!(await t.get('/feed.xml')).text.includes(target.slug));
assert.ok(t.events('deals.index_document.deleted').some((e) => e.payload.id === target.id));
const en = await t.get(`/mod/offers/${target.slug}/enable`, { as: t.mod, form: {} });