Commentaires fédérés via Mastodon (bokante.o-k-i.net) — backend #5
@@ -118,14 +118,14 @@ describe('beforeUpdate — notifications Telegram/Revolt', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('beforeUpdate — publication miroir bokante', () => {
|
describe('afterCreate — publication miroir bokante', () => {
|
||||||
const originalEnv = {...process.env};
|
const originalEnv = {...process.env};
|
||||||
const bokanteMastodon = require('../../../../../utils/bokante-mastodon');
|
const bokanteMastodon = require('../../../../../utils/bokante-mastodon');
|
||||||
const originalCreateStatus = bokanteMastodon.createStatus;
|
const originalCreateStatus = bokanteMastodon.createStatus;
|
||||||
|
|
||||||
function buildStrapi(previous) {
|
function buildStrapi() {
|
||||||
const dbQuery = {
|
const dbQuery = {
|
||||||
findOne: vi.fn(async () => previous),
|
findOne: vi.fn(async () => null),
|
||||||
updateMany: vi.fn()
|
updateMany: vi.fn()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,11 +136,16 @@ describe('beforeUpdate — publication miroir bokante', () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEvent(overrides = {}) {
|
function buildEvent(resultOverrides = {}) {
|
||||||
return {
|
return {
|
||||||
state: {},
|
params: {data: {titre: 'Mon titre'}},
|
||||||
params: {
|
result: {
|
||||||
data: {documentId: 'doc-1', publishedAt: '2026-07-04T00:00:00.000Z', ...overrides}
|
documentId: 'doc-1',
|
||||||
|
titre: 'Mon titre',
|
||||||
|
slug: 'mon-titre',
|
||||||
|
publishedAt: '2026-07-04T00:00:00.000Z',
|
||||||
|
bokanteStatusId: null,
|
||||||
|
...resultOverrides
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -151,33 +156,43 @@ describe('beforeUpdate — publication miroir bokante', () => {
|
|||||||
delete global.strapi;
|
delete global.strapi;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('publie un statut miroir et stocke bokanteStatusId sur data', async () => {
|
it('publie un statut miroir et synchronise bokanteStatusId sur le documentId', async () => {
|
||||||
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
||||||
bokanteMastodon.createStatus = vi.fn(async () => ({id: '112233'}));
|
bokanteMastodon.createStatus = vi.fn(async () => ({id: '112233'}));
|
||||||
|
|
||||||
const previous = {publishedAt: null, slug: 'mon-titre', titre: 'Mon titre', user: null, userAdmin: null, artistes: [], bokanteStatusId: null};
|
const strapiMock = buildStrapi();
|
||||||
const strapiMock = buildStrapi(previous);
|
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||||
|
|
||||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
await afterCreate(buildEvent());
|
||||||
const event = buildEvent();
|
|
||||||
|
|
||||||
await beforeUpdate(event);
|
|
||||||
|
|
||||||
expect(bokanteMastodon.createStatus).toHaveBeenCalledTimes(1);
|
expect(bokanteMastodon.createStatus).toHaveBeenCalledTimes(1);
|
||||||
expect(bokanteMastodon.createStatus.mock.calls[0][0]).toContain('Mon titre');
|
expect(bokanteMastodon.createStatus.mock.calls[0][0]).toContain('Mon titre');
|
||||||
expect(event.params.data.bokanteStatusId).toBe('112233');
|
expect(strapiMock.db.query('api::parole.parole').updateMany).toHaveBeenCalledWith({
|
||||||
|
where: {documentId: 'doc-1'},
|
||||||
|
data: {bokanteStatusId: '112233'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ne publie rien si la ligne créée n\'est pas publiée (simple brouillon)', async () => {
|
||||||
|
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
||||||
|
bokanteMastodon.createStatus = vi.fn(async () => ({id: '999'}));
|
||||||
|
|
||||||
|
const strapiMock = buildStrapi();
|
||||||
|
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||||
|
|
||||||
|
await afterCreate(buildEvent({publishedAt: null}));
|
||||||
|
|
||||||
|
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ne republie pas si bokanteStatusId existe déjà', async () => {
|
it('ne republie pas si bokanteStatusId existe déjà', async () => {
|
||||||
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
||||||
bokanteMastodon.createStatus = vi.fn(async () => ({id: '999'}));
|
bokanteMastodon.createStatus = vi.fn(async () => ({id: '999'}));
|
||||||
|
|
||||||
const previous = {publishedAt: null, slug: 'mon-titre', titre: 'Mon titre', user: null, userAdmin: null, artistes: [], bokanteStatusId: '112233'};
|
const strapiMock = buildStrapi();
|
||||||
const strapiMock = buildStrapi(previous);
|
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||||
|
|
||||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
await afterCreate(buildEvent({bokanteStatusId: '112233'}));
|
||||||
|
|
||||||
await beforeUpdate(buildEvent());
|
|
||||||
|
|
||||||
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -186,32 +201,27 @@ describe('beforeUpdate — publication miroir bokante', () => {
|
|||||||
delete process.env.BOKANTE_ACCESS_TOKEN;
|
delete process.env.BOKANTE_ACCESS_TOKEN;
|
||||||
bokanteMastodon.createStatus = vi.fn(async () => ({id: '999'}));
|
bokanteMastodon.createStatus = vi.fn(async () => ({id: '999'}));
|
||||||
|
|
||||||
const previous = {publishedAt: null, slug: 'mon-titre', titre: 'Mon titre', user: null, userAdmin: null, artistes: [], bokanteStatusId: null};
|
const strapiMock = buildStrapi();
|
||||||
const strapiMock = buildStrapi(previous);
|
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||||
|
|
||||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
await afterCreate(buildEvent());
|
||||||
|
|
||||||
await beforeUpdate(buildEvent());
|
|
||||||
|
|
||||||
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('n\'interrompt pas la publication quand bokante échoue', async () => {
|
it('n\'interrompt pas la création quand bokante échoue', async () => {
|
||||||
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
||||||
bokanteMastodon.createStatus = vi.fn(async () => {
|
bokanteMastodon.createStatus = vi.fn(async () => {
|
||||||
throw new Error('boom');
|
throw new Error('boom');
|
||||||
});
|
});
|
||||||
|
|
||||||
const previous = {publishedAt: null, slug: 'mon-titre', titre: 'Mon titre', user: null, userAdmin: null, artistes: [], bokanteStatusId: null};
|
const strapiMock = buildStrapi();
|
||||||
const strapiMock = buildStrapi(previous);
|
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||||
|
|
||||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
await expect(afterCreate(buildEvent())).resolves.not.toThrow();
|
||||||
const event = buildEvent();
|
|
||||||
|
|
||||||
await expect(beforeUpdate(event)).resolves.not.toThrow();
|
|
||||||
|
|
||||||
expect(strapiMock.log.error).toHaveBeenCalledWith(expect.stringContaining('bokante'));
|
expect(strapiMock.log.error).toHaveBeenCalledWith(expect.stringContaining('bokante'));
|
||||||
expect(event.params.data.bokanteStatusId).toBeUndefined();
|
expect(strapiMock.db.query('api::parole.parole').updateMany).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -192,17 +192,6 @@ module.exports = {
|
|||||||
const previousPublishedAt = previousData.publishedAt;
|
const previousPublishedAt = previousData.publishedAt;
|
||||||
const currentPublished_at = data.publishedAt;
|
const currentPublished_at = data.publishedAt;
|
||||||
if (currentPublished_at != previousPublishedAt) {
|
if (currentPublished_at != previousPublishedAt) {
|
||||||
if (!previousData.bokanteStatusId && process.env.BOKANTE_ACCESS_TOKEN) {
|
|
||||||
try {
|
|
||||||
const status = await bokanteMastodon.createStatus(
|
|
||||||
`"${previousData.titre}" — nouvelle parole sur pawol.nu\n${process.env.WEBSITE_URL}/paroles/${previousData.slug}`
|
|
||||||
);
|
|
||||||
data.bokanteStatusId = status.id;
|
|
||||||
} catch (err) {
|
|
||||||
strapi.log.error(`Publication bokante : ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = `<b>Nouvelle publication</b> ❤️
|
const message = `<b>Nouvelle publication</b> ❤️
|
||||||
\n${process.env.WEBSITE_URL}/paroles/${previousData.slug}`;
|
\n${process.env.WEBSITE_URL}/paroles/${previousData.slug}`;
|
||||||
if (previousData.user) {
|
if (previousData.user) {
|
||||||
@@ -284,6 +273,27 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
afterCreate: async event => {
|
afterCreate: async event => {
|
||||||
const {data} = event.params;
|
const {data} = event.params;
|
||||||
|
|
||||||
|
// Avec draftAndPublish, "publier" crée une nouvelle ligne (la version publiée)
|
||||||
|
// au lieu de mettre à jour la ligne existante : c'est ici, et non dans
|
||||||
|
// beforeUpdate, qu'un événement de publication est détectable.
|
||||||
|
if (event.result?.publishedAt && !event.result?.bokanteStatusId && process.env.BOKANTE_ACCESS_TOKEN) {
|
||||||
|
try {
|
||||||
|
const status = await bokanteMastodon.createStatus(
|
||||||
|
`"${event.result.titre}" — nouvelle parole sur pawol.nu\n${process.env.WEBSITE_URL}/paroles/${event.result.slug}`
|
||||||
|
);
|
||||||
|
// Synchronise brouillon et version publiée pour éviter une republication
|
||||||
|
// en double au prochain cycle dépublier/republier (qui recrée la ligne
|
||||||
|
// publiée à partir du brouillon).
|
||||||
|
await strapi.db.query('api::parole.parole').updateMany({
|
||||||
|
where: {documentId: event.result.documentId},
|
||||||
|
data: {bokanteStatusId: status.id}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
strapi.log.error(`Publication bokante : ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const user = await jwennUserEpiId(data?.user?.id);
|
const user = await jwennUserEpiId(data?.user?.id);
|
||||||
const userAdmin = await jwennUserAdminEpiId(data?.createdBy);
|
const userAdmin = await jwennUserAdminEpiId(data?.createdBy);
|
||||||
const superAdmin = await jwennSuperAdminEpiId(data?.createdBy);
|
const superAdmin = await jwennSuperAdminEpiId(data?.createdBy);
|
||||||
|
|||||||
Reference in New Issue
Block a user