fix: déplacer le miroir bokante de beforeUpdate vers afterCreate
Avec draftAndPublish sur Strapi 5, publier une entrée crée une nouvelle ligne (document-service publishEntry -> createEntry) au lieu de mettre à jour la ligne existante : beforeUpdate ne se déclenche donc jamais sur une vraie action Publier, seulement sur l'édition d'une entrée déjà publiée. Le miroir bokante est maintenant posté dans afterCreate, sur la condition result.publishedAt, avec synchronisation brouillon/publié pour rester idempotent à travers les cycles dépublier/republier.
This commit is contained in:
@@ -118,14 +118,14 @@ describe('beforeUpdate — notifications Telegram/Revolt', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('beforeUpdate — publication miroir bokante', () => {
|
||||
describe('afterCreate — publication miroir bokante', () => {
|
||||
const originalEnv = {...process.env};
|
||||
const bokanteMastodon = require('../../../../../utils/bokante-mastodon');
|
||||
const originalCreateStatus = bokanteMastodon.createStatus;
|
||||
|
||||
function buildStrapi(previous) {
|
||||
function buildStrapi() {
|
||||
const dbQuery = {
|
||||
findOne: vi.fn(async () => previous),
|
||||
findOne: vi.fn(async () => null),
|
||||
updateMany: vi.fn()
|
||||
};
|
||||
|
||||
@@ -136,11 +136,16 @@ describe('beforeUpdate — publication miroir bokante', () => {
|
||||
};
|
||||
}
|
||||
|
||||
function buildEvent(overrides = {}) {
|
||||
function buildEvent(resultOverrides = {}) {
|
||||
return {
|
||||
state: {},
|
||||
params: {
|
||||
data: {documentId: 'doc-1', publishedAt: '2026-07-04T00:00:00.000Z', ...overrides}
|
||||
params: {data: {titre: 'Mon titre'}},
|
||||
result: {
|
||||
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;
|
||||
});
|
||||
|
||||
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';
|
||||
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(previous);
|
||||
const strapiMock = buildStrapi();
|
||||
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||
|
||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
||||
const event = buildEvent();
|
||||
|
||||
await beforeUpdate(event);
|
||||
await afterCreate(buildEvent());
|
||||
|
||||
expect(bokanteMastodon.createStatus).toHaveBeenCalledTimes(1);
|
||||
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 () => {
|
||||
process.env.BOKANTE_ACCESS_TOKEN = 'fake-token';
|
||||
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(previous);
|
||||
const strapiMock = buildStrapi();
|
||||
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||
|
||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
||||
|
||||
await beforeUpdate(buildEvent());
|
||||
await afterCreate(buildEvent({bokanteStatusId: '112233'}));
|
||||
|
||||
expect(bokanteMastodon.createStatus).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -186,32 +201,27 @@ describe('beforeUpdate — publication miroir bokante', () => {
|
||||
delete process.env.BOKANTE_ACCESS_TOKEN;
|
||||
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(previous);
|
||||
const strapiMock = buildStrapi();
|
||||
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||
|
||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
||||
|
||||
await beforeUpdate(buildEvent());
|
||||
await afterCreate(buildEvent());
|
||||
|
||||
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';
|
||||
bokanteMastodon.createStatus = vi.fn(async () => {
|
||||
throw new Error('boom');
|
||||
});
|
||||
|
||||
const previous = {publishedAt: null, slug: 'mon-titre', titre: 'Mon titre', user: null, userAdmin: null, artistes: [], bokanteStatusId: null};
|
||||
const strapiMock = buildStrapi(previous);
|
||||
const strapiMock = buildStrapi();
|
||||
const {afterCreate} = await loadLifecycles(strapiMock);
|
||||
|
||||
const {beforeUpdate} = await loadLifecycles(strapiMock);
|
||||
const event = buildEvent();
|
||||
|
||||
await expect(beforeUpdate(event)).resolves.not.toThrow();
|
||||
await expect(afterCreate(buildEvent())).resolves.not.toThrow();
|
||||
|
||||
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 currentPublished_at = data.publishedAt;
|
||||
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> ❤️
|
||||
\n${process.env.WEBSITE_URL}/paroles/${previousData.slug}`;
|
||||
if (previousData.user) {
|
||||
@@ -284,6 +273,27 @@ module.exports = {
|
||||
},
|
||||
afterCreate: async event => {
|
||||
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 userAdmin = await jwennUserAdminEpiId(data?.createdBy);
|
||||
const superAdmin = await jwennSuperAdminEpiId(data?.createdBy);
|
||||
|
||||
Reference in New Issue
Block a user