Skip to content

Commit 254179a

Browse files
committed
feat: Optimized smtp configuration
1 parent 5fc8975 commit 254179a

11 files changed

+41
-47
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ _confluence-outdated_ includes a command to create a template document:
2525

2626
Example:
2727

28-
confluence-outdated createconfigurationdocument --url https://example.com/confluence --user somebody --password secret --space CM --title "My configuration document" --parentId 12345
28+
confluence-outdated CreateConfigurationDocument --url https://example.com/confluence --user somebody --password secret --space CM --title "My configuration document" --parentId 12345
2929

3030
The command will output the page ID for the configuration document and a link to it.
3131

@@ -59,6 +59,15 @@ subject and the body of the notification mails.
5959
They will get [this object](https://github.com/dodevops/confluence-outdated/blob/master/lib/api/DocumentInfo.ts#L6) as
6060
a context for the template.
6161

62+
## Usage
63+
64+
After the configuration document is properly setup, run *confluence-outdated* on a regular basis:
65+
66+
confluence-outdated Check --url https://example.com/confluence --user somebody --password secret -i 123456 -s "smtp://localhost:25/?ignoreTLS=true"
67+
68+
This will fetch the confluence document with the id 123456 as the configuration and check all required documentation as
69+
configured. The SMTP url is based on the [nodemailer smtp transport](https://nodemailer.com/smtp/).
70+
6271
## Development
6372

6473
The tests subdirectory contain unit tests run by mocha for all parts of the api. If you want to help developing, please

lib/api/Configuration.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import got from 'got'
22
import { Check } from './Check'
33
import { Logger } from 'loglevel'
44
import { ConfigurationError } from '../error/ConfigurationError'
5-
import * as SMTPTransport from 'nodemailer/lib/smtp-transport'
65
import * as cheerio from 'cheerio'
76
import { Maintainer } from './Maintainer'
87
import log = require('loglevel')
@@ -55,11 +54,6 @@ export class Configuration {
5554
*/
5655
public notificationFrom: string
5756

58-
/**
59-
* Transport options for nodemailer for the notifications
60-
*/
61-
public transportOptions: SMTPTransport.Options
62-
6357
/**
6458
* A list of checks for outdated documents
6559
*/
@@ -102,15 +96,19 @@ export class Configuration {
10296
}
10397

10498
// eslint-disable-next-line @typescript-eslint/no-explicit-any
105-
private _getConfigurationFromPanel($: Root, panelName: string): Array<any> {
99+
private _getConfigurationFromPanel($: Root, panelName: string, lowerCase = true): Array<any> {
106100
const keys = $(`ac\\:parameter:contains("${panelName}") + ac\\:rich-text-body table tr th`)
107101
const values = $(`ac\\:parameter:contains("${panelName}") + ac\\:rich-text-body table tr td`)
108102
const rows = $(`ac\\:parameter:contains("${panelName}") + ac\\:rich-text-body table tr td`).parent()
109103
const returnObject = []
110104
for (let i = 0; i < rows.length; i++) {
111105
const rowObject = {}
112106
keys.each((index, key) => {
113-
rowObject[$(key).text().toLowerCase()] = $(values[index + i * 2]).text()
107+
let configurationKey = $(key).text()
108+
if (lowerCase) {
109+
configurationKey = configurationKey.toLowerCase()
110+
}
111+
rowObject[configurationKey] = $(values[index + i * 2]).text()
114112
})
115113
returnObject.push(rowObject)
116114
}
@@ -174,8 +172,6 @@ export class Configuration {
174172
}
175173
})
176174

177-
this.transportOptions = this._getConfigurationFromPanel($, 'SMTP')[0]
178-
179175
this.notificationSubjectTemplate = $(
180176
'ac\\:parameter:contains("Notification Template") + ac\\:rich-text-body ac\\:parameter:contains("Subject") + ac\\:rich-text-body'
181177
).text()

lib/api/Confluence.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class Confluence {
7575
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7676
}).json<any>()
7777

78-
const author = (document && document.version && document.version.by && document.version.by.username) || null
78+
const author = document.version.by.username ?? null
7979

8080
if (!author) {
8181
this._log.error(`Can't get author from this document:

lib/api/Notification.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ export class Notification {
1616
private _log: Logger
1717
private readonly _dryRun: boolean
1818

19-
constructor(configuration: Configuration, confluence: Confluence, transport: Mail = null, dryRun = false) {
19+
constructor(configuration: Configuration, smtpTransportUrl: string, confluence: Confluence, transport: Mail = null, dryRun = false) {
2020
this._configuration = configuration
2121
this._confluence = confluence
22-
this._transport = transport || createTransport(this._configuration.transportOptions)
22+
this._transport = transport || createTransport(smtpTransportUrl)
2323

2424
this._log = log.getLogger('Notification')
2525
this._dryRun = dryRun
@@ -40,9 +40,14 @@ export class Notification {
4040
}
4141
}
4242

43+
let to = documentInfo.author
44+
if (this._configuration.domain) {
45+
to = `${to}@${this._configuration.domain}`
46+
}
47+
4348
const mailOptions = {
4449
from: this._configuration.notificationFrom,
45-
to: `${documentInfo.author}@${this._configuration.domain}`,
50+
to: to,
4651
subject: subjectTemplate(documentInfo),
4752
html: bodyTemplate(documentInfo),
4853
}

lib/commands/Check.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ export class CheckOptions extends DefaultOptions {
2020
toggle: true,
2121
})
2222
dryRun: boolean
23+
24+
@option({
25+
name: 'smtpurl',
26+
flag: 's',
27+
description: 'SMTP URL (check out https://nodemailer.com/smtp/ for options)',
28+
required: true,
29+
})
30+
smtpTransportUrl: string
2331
}
2432

2533
@command({
@@ -42,7 +50,7 @@ export default class extends Command {
4250

4351
const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword)
4452

45-
const notification = new Notification(configuration, confluence, null, options.dryRun)
53+
const notification = new Notification(configuration, options.smtpTransportUrl, confluence, null, options.dryRun)
4654

4755
for (const check of configuration.checks) {
4856
log.debug(`Checking for documents older than ${check.maxAge} day(s) with label(s) ${check.labels.join(',')}`)

lib/commands/CreateConfigurationDocument.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class extends Command {
4040

4141
const confluence = new Confluence(options.confluenceUrl, options.confluenceUser, options.confluencePassword)
4242

43-
const pageId = confluence.createConfigurationDocument(options.space, options.title, options.parentId)
43+
const pageId = await confluence.createConfigurationDocument(options.space, options.title, options.parentId)
4444

4545
return `The configuration document was created with the ID
4646
${pageId}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"url": ""
1616
},
1717
"scripts": {
18-
"test": "grunt test"
18+
"test": "grunt test",
19+
"prepare": "grunt build"
1920
},
2021
"files": [
2122
"index.d.ts",

resources/configurationDocument.html

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,6 @@
2323
</table>
2424
</ac:rich-text-body>
2525
</ac:structured-macro>
26-
<ac:structured-macro ac:name="panel" ac:schema-version="1" ac:macro-id="ecfe796e-b701-4f30-a74a-b94dbb33daff">
27-
<ac:parameter ac:name="title">SMTP</ac:parameter>
28-
<ac:rich-text-body>
29-
<i>See <a href="https://nodemailer.com/smtp/">the nodemailer SMTP documentation</a> for all available options here.</i>
30-
<table class="wrapped">
31-
<colgroup>
32-
<col/>
33-
<col/>
34-
</colgroup>
35-
<tbody>
36-
<tr>
37-
<th>Host</th>
38-
<td>localhost</td>
39-
</tr>
40-
<tr>
41-
<th>Port</th>
42-
<td>25</td>
43-
</tr>
44-
</tbody>
45-
</table>
46-
</ac:rich-text-body>
47-
</ac:structured-macro>
4826
<ac:structured-macro ac:name="panel" ac:schema-version="1" ac:macro-id="f19cd8b2-57e0-4c68-a823-8a2daee08c12">
4927
<ac:parameter ac:name="title">Checks</ac:parameter>
5028
<ac:rich-text-body>

test/ConfigurationTest.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ describe('The Configuration API', (): void => {
2222
chai.expect(configuration.notificationBodyTemplate).to.eq(MockServer.NOTIFICATION_BODY)
2323
chai.expect(configuration.notificationSubjectTemplate).to.eq(MockServer.NOTIFICATION_SUBJECT)
2424

25-
chai.expect(configuration.transportOptions.host).to.eq('localhost')
26-
chai.expect(configuration.transportOptions.port).to.eq('25')
27-
2825
chai.expect(configuration.notificationFrom).to.eq('Notification <[email protected]>')
2926
})
3027
})

test/NotificationTest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('The Notification API', (): void => {
3131
})
3232

3333
it('should send notifications', async (): Promise<void> => {
34-
const notification = new Notification(configuration, confluence, transportStub)
34+
const notification = new Notification(configuration, '', confluence, transportStub)
3535
const documentInfo = new DocumentInfo(0, 'author', moment(), 'message', 'title', 'http://example.com')
3636
await notification.notify(documentInfo)
3737
chai.expect((transportStub as unknown as SinonStubbedInstance<Mail>).sendMail.calledOnce).to.be.true
@@ -45,7 +45,7 @@ describe('The Notification API', (): void => {
4545
).to.be.true
4646
})
4747
it('should use a maintainer when configured', async (): Promise<void> => {
48-
const notification = new Notification(configuration, confluence, transportStub)
48+
const notification = new Notification(configuration, '', confluence, transportStub)
4949
const documentInfo = new DocumentInfo(0, 'author2', moment(), 'message', 'Test2', 'http://example.com')
5050
await notification.notify(documentInfo)
5151
chai.expect((transportStub as unknown as SinonStubbedInstance<Mail>).sendMail.calledOnce).to.be.true
@@ -59,7 +59,7 @@ describe('The Notification API', (): void => {
5959
).to.be.true
6060
})
6161
it('should not send notifications on a dry run', async (): Promise<void> => {
62-
const notification = new Notification(configuration, confluence, transportStub, true)
62+
const notification = new Notification(configuration, '', confluence, transportStub, true)
6363
const documentInfo = new DocumentInfo(0, 'author', moment(), 'message', 'title', 'http://example.com')
6464
await notification.notify(documentInfo)
6565
chai.expect((transportStub as unknown as SinonStubbedInstance<Mail>).sendMail.notCalled).to.be.true

0 commit comments

Comments
 (0)