Commentaires fédérés via Mastodon (bokante.o-k-i.net) — backend #5
@@ -1,6 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const {backupDatabase} = require('../src/utils/backup-database');
|
const {backupDatabase} = require('../src/utils/backup-database');
|
||||||
const {importBokanteComments} = require('../src/utils/import-bokante-comments');
|
const {importBokanteComments} = require('../src/utils/import-bokante-comments');
|
||||||
|
const {backfillBokanteMirror} = require('../src/utils/backfill-bokante-mirrors');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
myJob: {
|
myJob: {
|
||||||
@@ -37,4 +38,21 @@ module.exports = {
|
|||||||
tz: 'Indian/Reunion',
|
tz: 'Indian/Reunion',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
backfillBokanteMirror: {
|
||||||
|
task: async ({ strapi }) => {
|
||||||
|
if (!process.env.BOKANTE_ACCESS_TOKEN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {backfilled, slug} = await backfillBokanteMirror({strapi});
|
||||||
|
|
||||||
|
if (backfilled) {
|
||||||
|
strapi.log.info(`Backfill bokante : parole "${slug}" publiée.`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
rule: process.env.BOKANTE_BACKFILL_CRON || '0 * * * *',
|
||||||
|
tz: 'Indian/Reunion',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {describe, it, expect, vi, afterEach} from 'vitest';
|
||||||
|
import {backfillBokanteMirror} from '../backfill-bokante-mirrors.js';
|
||||||
|
|
||||||
|
const bokanteMastodon = require('../bokante-mastodon.js');
|
||||||
|
|
||||||
|
function buildStrapi({paroles = []} = {}) {
|
||||||
|
const updateMany = vi.fn();
|
||||||
|
|
||||||
|
return {
|
||||||
|
db: {
|
||||||
|
query: () => ({
|
||||||
|
findMany: vi.fn(async ({where, orderBy, limit}) => {
|
||||||
|
expect(where).toEqual({
|
||||||
|
publishedAt: {$notNull: true},
|
||||||
|
bokanteStatusId: {$null: true}
|
||||||
|
});
|
||||||
|
expect(orderBy).toEqual({publishedAt: 'asc'});
|
||||||
|
expect(limit).toBe(1);
|
||||||
|
return paroles.slice(0, limit);
|
||||||
|
}),
|
||||||
|
updateMany
|
||||||
|
})
|
||||||
|
},
|
||||||
|
log: {error: vi.fn(), info: vi.fn()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('backfillBokanteMirror', () => {
|
||||||
|
const originalCreateStatus = bokanteMastodon.createStatus;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
bokanteMastodon.createStatus = originalCreateStatus;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('publie le miroir pour la parole publiée la plus ancienne sans bokanteStatusId', async () => {
|
||||||
|
bokanteMastodon.createStatus = vi.fn(async () => ({id: '112233'}));
|
||||||
|
const parole = {documentId: 'doc-1', titre: 'Vieux titre', slug: 'vieux-titre'};
|
||||||
|
const strapi = buildStrapi({paroles: [parole]});
|
||||||
|
|
||||||
|
const result = await backfillBokanteMirror({strapi});
|
||||||
|
|
||||||
|
expect(bokanteMastodon.createStatus).toHaveBeenCalledTimes(1);
|
||||||
|
expect(bokanteMastodon.createStatus.mock.calls[0][0]).toContain('Vieux titre');
|
||||||
|
expect(bokanteMastodon.createStatus.mock.calls[0][0]).not.toContain('nouvelle parole');
|
||||||
|
expect(strapi.db.query().updateMany).toHaveBeenCalledWith({
|
||||||
|
where: {documentId: 'doc-1'},
|
||||||
|
data: {bokanteStatusId: '112233'}
|
||||||
|
});
|
||||||
|
expect(result).toEqual({backfilled: true, slug: 'vieux-titre'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ne fait rien si le catalogue est déjà rattrapé', async () => {
|
||||||
|
bokanteMastodon.createStatus = vi.fn();
|
||||||
|
const strapi = buildStrapi({paroles: []});
|
||||||
|
|
||||||
|
const result = await backfillBokanteMirror({strapi});
|
||||||
|
|
||||||
|
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
||||||
|
expect(result).toEqual({backfilled: false});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('n\'interrompt rien si bokante échoue, et ne marque pas la parole comme traitée', async () => {
|
||||||
|
bokanteMastodon.createStatus = vi.fn(async () => {
|
||||||
|
throw new Error('boom');
|
||||||
|
});
|
||||||
|
const parole = {documentId: 'doc-1', titre: 'Titre', slug: 'titre'};
|
||||||
|
const strapi = buildStrapi({paroles: [parole]});
|
||||||
|
|
||||||
|
const result = await backfillBokanteMirror({strapi});
|
||||||
|
|
||||||
|
expect(strapi.log.error).toHaveBeenCalledWith(expect.stringContaining('titre'));
|
||||||
|
expect(strapi.db.query().updateMany).not.toHaveBeenCalled();
|
||||||
|
expect(result).toEqual({backfilled: false});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const bokanteMastodon = require('./bokante-mastodon');
|
||||||
|
|
||||||
|
async function backfillBokanteMirror({strapi}) {
|
||||||
|
const [parole] = await strapi.db.query('api::parole.parole').findMany({
|
||||||
|
where: {
|
||||||
|
publishedAt: {$notNull: true},
|
||||||
|
bokanteStatusId: {$null: true}
|
||||||
|
},
|
||||||
|
orderBy: {publishedAt: 'asc'},
|
||||||
|
limit: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!parole) {
|
||||||
|
return {backfilled: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const status = await bokanteMastodon.createStatus(
|
||||||
|
`"${parole.titre}" — à (re)découvrir sur pawol.nu\n${process.env.WEBSITE_URL}/paroles/${parole.slug}`
|
||||||
|
);
|
||||||
|
|
||||||
|
await strapi.db.query('api::parole.parole').updateMany({
|
||||||
|
where: {documentId: parole.documentId},
|
||||||
|
data: {bokanteStatusId: status.id}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {backfilled: true, slug: parole.slug};
|
||||||
|
} catch (err) {
|
||||||
|
strapi.log.error(`Backfill bokante (${parole.slug}) : ${err.message}`);
|
||||||
|
return {backfilled: false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {backfillBokanteMirror};
|
||||||
Reference in New Issue
Block a user