diff --git a/README.md b/README.md index 14e91d5..d7625f5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ A table of maintainers for pages. - PagePattern: A regular expression that is matched against the full document path. Parent pages are separated through a "/". - Maintainer: The users that should receive all notifications for pages matching this pattern (separated by ,). You can - use `_lastauthor` to reference the last author of the page) + use `_lastauthor` to reference the last author of the page and `_creator` to reference the first author of the page. ### Panel "Exceptions" diff --git a/lib/api/Confluence.ts b/lib/api/Confluence.ts index 70cecec..4670db8 100644 --- a/lib/api/Confluence.ts +++ b/lib/api/Confluence.ts @@ -68,7 +68,7 @@ export class Confluence { */ public async getDocumentInfo(documentId: number): Promise { this._log.debug(`Getting document information of document ${documentId}`) - const documentUrl = `${this.confluenceUrl}/rest/api/content/${documentId}?expand=ancestors,version,metadata.labels` + const documentUrl = `${this.confluenceUrl}/rest/api/content/${documentId}?expand=ancestors,version,metadata.labels,history` const document = await got(documentUrl, { username: this.confluenceUser, password: this.confluencePassword, @@ -76,6 +76,7 @@ export class Confluence { }).json() const author = document.version.by.username ?? null + const creator = document.history['createdBy'].username ?? null if (!author) { this._log.error(`Can't get author from this document: @@ -125,6 +126,7 @@ export class Confluence { const documentInfo = new DocumentInfo( documentId, author, + creator, (lastVersionDate as Moment).toISOString(), lastVersionMessage, title, diff --git a/lib/api/DocumentInfo.ts b/lib/api/DocumentInfo.ts index 0460de8..ae6398b 100644 --- a/lib/api/DocumentInfo.ts +++ b/lib/api/DocumentInfo.ts @@ -50,6 +50,7 @@ export interface DocumentInfo { export class DocumentInfo implements DocumentInfo { public id: number public author: string + public creator: string public lastVersionDate: string public lastVersionMessage: string public title: string @@ -61,6 +62,7 @@ export class DocumentInfo implements DocumentInfo { constructor( id: number, author: string, + creator: string, lastVersionDate: string, lastVersionMessage: string, title: string, @@ -71,6 +73,7 @@ export class DocumentInfo implements DocumentInfo { ) { this.id = id this.author = author + this.creator = creator this.lastVersionDate = lastVersionDate this.lastVersionMessage = lastVersionMessage this.title = title @@ -88,6 +91,7 @@ export class DocumentInfo implements DocumentInfo { return new DocumentInfo( documentInfo.id, documentInfo.author, + documentInfo.creator, documentInfo.lastVersionDate, documentInfo.lastVersionMessage, documentInfo.title, @@ -101,18 +105,25 @@ export class DocumentInfo implements DocumentInfo { public getRecipients(maintainers: Maintainer[], domain?: string): string[] { const retval = [] let addLastAuthor = maintainers.length > 0 ? false : true + let addCreator = false for (const maintainer of maintainers) { if (this.matchesPath(maintainer.pagePattern)) { const maintainers = maintainer.maintainer.split(/,/) if (maintainers.indexOf('_lastauthor') > 0) { addLastAuthor = true } - retval.push(...maintainers.filter((entry) => entry != '_lastauthor')) + if (maintainers.indexOf('_creator') > 0) { + addCreator = true + } + retval.push(...maintainers.filter((entry) => ['_lastauthor', '_creator'].indexOf(entry) == -1)) } } if (addLastAuthor) { retval.push(this.author) } + if (addCreator) { + retval.push(this.creator) + } if (domain) { return retval.map((target) => `${target}@${domain}`) } diff --git a/resources/configurationDocument.html b/resources/configurationDocument.html index cf710bd..72df65f 100644 --- a/resources/configurationDocument.html +++ b/resources/configurationDocument.html @@ -48,7 +48,8 @@ Maintainer - This table holds a list of RegExp patterns for page paths and titles and the associated maintainers (separated by ,) for this pages, which will be notified instead of the last version's author. The last author can be added as well, if desired by using _lastauthor as the username. + This table holds a list of RegExp patterns for page paths and titles and the associated maintainers (separated by ,) for this pages, which will be notified instead of the last version's author. Use + _lastauthor to reference the last author of the page and _creator to reference the first author of the page. diff --git a/test/MockServer.ts b/test/MockServer.ts index cca9119..7ae816c 100644 --- a/test/MockServer.ts +++ b/test/MockServer.ts @@ -452,6 +452,166 @@ export class MockServer {
+ + Notification Template + + + Subject +

${MockServer.NOTIFICATION_SUBJECT}

+
+ + Body + ${MockServer.NOTIFICATION_BODY} + +
+
+ `, + }, + }, + }) + this._scope + .get('/rest/api/content/12348?expand=body.storage') + .basicAuth({ + user: 'nobody', + pass: 'nothing', + }) + .reply(200, { + body: { + storage: { + value: ` + + Configuration + + + + + + + + + + + + + + + + + + + + +
SpaceSAMPLE
Domainexample.com
NotificationFromNotification <noreply@example.com>
+
+
+ + SMTP + + + + + + + + + + + + + + + + +
Hostlocalhost
Port25
+
+
+ + Checks + + + + + + + + + + + + + + + + + + + + +
LabelsMaxAge
test1356
test21234
+
+
+ + Maintainer + + + + + + + + + + + + + + + + +
PagepatternMaintainer
main/Test/.*maintainer,_creator
+
+
+ + Exceptions + + + + + + + + + + + + + +
RegularExpression
main/Test/NOT
+
+
+ + Excluded labels + + This table holds a list of labels. A document which has one of these will be excluded from notifications. + + + + + + + + + + + + + + + + +
Label
NOT
NOT2
+
+
Notification Template @@ -507,7 +667,7 @@ export class MockServer { public addDocumentEndpoint(): void { this._scope - .get('/rest/api/content/123?expand=ancestors,version,metadata.labels') + .get('/rest/api/content/123?expand=ancestors,version,metadata.labels,history') .basicAuth({ user: 'nobody', pass: 'nothing', @@ -529,6 +689,11 @@ export class MockServer { when: '2020-01-01T00:00:00.000+02:00', message: 'Some change', }, + history: { + createdBy: { + username: 'creator', + }, + }, title: 'Test', metadata: { labels: { @@ -542,7 +707,7 @@ export class MockServer { }, }, }) - .get('/rest/api/content/234?expand=ancestors,version,metadata.labels') + .get('/rest/api/content/234?expand=ancestors,version,metadata.labels,history') .basicAuth({ user: 'nobody', pass: 'nothing', @@ -560,6 +725,11 @@ export class MockServer { title: 'Test', }, ], + history: { + createdBy: { + username: 'creator', + }, + }, version: { by: { username: 'author2', diff --git a/test/NotificationTest.ts b/test/NotificationTest.ts index 330286e..12a987c 100644 --- a/test/NotificationTest.ts +++ b/test/NotificationTest.ts @@ -35,6 +35,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author', + 'creator', moment().toISOString(), 'message', 'title', @@ -73,6 +74,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author2', + 'creator', moment().toISOString(), 'message', 'Test2', @@ -125,6 +127,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author', + 'creator', moment().toISOString(), 'message', 'title', @@ -141,6 +144,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author2', + 'creator', moment().toISOString(), 'message', 'NOT', @@ -158,6 +162,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author', + 'creator', moment().toISOString(), 'message', 'title1', @@ -169,6 +174,7 @@ describe('The Notification API', (): void => { const documentInfo2 = new DocumentInfo( 0, 'author', + 'creator', moment().toISOString(), 'message', 'title2', @@ -203,6 +209,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'maintainer', + 'creator', moment().toISOString(), 'message', 'Test2', @@ -238,6 +245,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author2', + 'creator', moment().toISOString(), 'message', 'Title', @@ -249,6 +257,7 @@ describe('The Notification API', (): void => { const documentInfoValid = new DocumentInfo( 0, 'author2', + 'creator', moment().toISOString(), 'message', 'Title', @@ -267,6 +276,7 @@ describe('The Notification API', (): void => { const documentInfo = new DocumentInfo( 0, 'author2', + 'creator', moment().toISOString(), 'message', 'Test2', @@ -279,4 +289,60 @@ describe('The Notification API', (): void => { await notification.notify([documentInfo]) chai.expect(JSON.stringify(documentInfo)).to.eq(documentInfoOrig) }) + + it('should use creator author if specified', async (): Promise => { + configuration = new Configuration('https://example.com', 'nobody', 'nothing', '12348') + await configuration.load() + const notification = new Notification(configuration, '', confluence, transportStub, false) + const documentInfo = new DocumentInfo( + 0, + 'author2', + 'creator', + moment().toISOString(), + 'message', + 'Test2', + ['main', 'Test'], + 'http://example.com', + 'test', + [] + ) + await notification.notify([documentInfo]) + chai.expect((transportStub as unknown as SinonStubbedInstance).sendMail.calledTwice).to.be.true + chai.expect( + (transportStub as unknown as SinonStubbedInstance).sendMail.calledWith({ + from: 'Notification ', + to: 'maintainer@example.com', + subject: Handlebars.compile(MockServer.NOTIFICATION_SUBJECT)({ + author: 'maintainer@example.com', + documentsCount: 1, + documents: [documentInfo], + multipleDocuments: false, + }), + html: Handlebars.compile(MockServer.NOTIFICATION_BODY)({ + author: 'maintainer@example.com', + documentsCount: 1, + documents: [documentInfo], + multipleDocuments: false, + }), + }) + ).to.be.true + chai.expect( + (transportStub as unknown as SinonStubbedInstance).sendMail.calledWith({ + from: 'Notification ', + to: 'creator@example.com', + subject: Handlebars.compile(MockServer.NOTIFICATION_SUBJECT)({ + author: 'creator@example.com', + documentsCount: 1, + documents: [documentInfo], + multipleDocuments: false, + }), + html: Handlebars.compile(MockServer.NOTIFICATION_BODY)({ + author: 'creator@example.com', + documentsCount: 1, + documents: [documentInfo], + multipleDocuments: false, + }), + }) + ).to.be.true + }) })