Skip to content

Commit

Permalink
feat: Introducing option to authenticate with (personal access) token…
Browse files Browse the repository at this point in the history
…, instead of username/password
  • Loading branch information
timdeluxe committed Jul 5, 2024
1 parent 1ca8fd3 commit 0f6910e
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 45 deletions.
16 changes: 12 additions & 4 deletions lib/DefaultOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,25 @@ export class DefaultOptions extends Options {
name: 'user',
flag: 'u',
description: 'Username for checking all confluence documents',
required: true,
required: false,
})
confluenceUser: string
confluenceUser: string = ''

@option({
name: 'password',
flag: 'p',
description: 'Password for the user',
required: true,
required: false,
})
confluencePassword: string = ''

@option({
name: 'token',
flag: 't',
description: 'Personal Access Token for the user. If set user and password will be ignored',
required: false,
})
confluencePassword: string
confluencePersonalAccessToken: string = ''

@option({
description: 'Log-Level to use (trace, debug, verbose, info, warn, error)',
Expand Down
27 changes: 21 additions & 6 deletions lib/api/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ export class Configuration {
*/
public confluencePassword: string

/**
* The personal access token of the Confluence user
*/
public confluencePersonalAccessToken: string

/**
* The document id of the configuration document
*/
Expand Down Expand Up @@ -94,10 +99,11 @@ export class Configuration {
*/
private _log: Logger

constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, configurationDocumentId: string) {
constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, confluencePersonalAccessToken: string, configurationDocumentId: string) {
this.confluenceUrl = confluenceUrl
this.confluenceUser = confluenceUser
this.confluencePassword = confluencePassword
this.confluencePersonalAccessToken = confluencePersonalAccessToken
this.configurationDocumentId = configurationDocumentId
this._loaded = false

Expand Down Expand Up @@ -134,11 +140,20 @@ export class Configuration {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let configurationDocument: any
try {
configurationDocument = await got(configurationUrl, {
username: this.confluenceUser,
password: this.confluencePassword,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
if (this.confluencePersonalAccessToken !== '') {
configurationDocument = await got(configurationUrl, {
headers: {
'Authorization': 'Bearer ' + this.confluencePersonalAccessToken
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
} else {
configurationDocument = await got(configurationUrl, {
username: this.confluenceUser,
password: this.confluencePassword,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
}
} catch (e) {
this._log.error(`Can't fetch configuration document: (${e.name}) ${e.message}`)
throw e
Expand Down
115 changes: 82 additions & 33 deletions lib/api/Confluence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ export class Confluence {
public confluenceUrl: string
public confluenceUser: string
public confluencePassword: string
public confluencePersonalAccessToken: string
private _log: Logger

constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string) {
constructor(confluenceUrl: string, confluenceUser: string, confluencePassword: string, confluencePersonalAccessToken: string,) {
this.confluenceUrl = confluenceUrl
this.confluenceUser = confluenceUser
this.confluencePassword = confluencePassword
this.confluencePersonalAccessToken = confluencePersonalAccessToken

this._log = log.getLogger('Confluence')
}
Expand All @@ -47,11 +49,20 @@ export class Confluence {
this._log.debug(`Searching for documents with ${cql}`)
do {
const configurationUrl = `${this.confluenceUrl}/rest/api/content/search?cql=${cql}&start=${start}&limit=${limit}`
results = await got(configurationUrl, {
username: this.confluenceUser,
password: this.confluencePassword,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
if (this.confluencePersonalAccessToken !== '') {
results = await got(configurationUrl, {
headers: {
'Authorization': 'Bearer ' + this.confluencePersonalAccessToken
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
} else {
results = await got(configurationUrl, {
username: this.confluenceUser,
password: this.confluencePassword,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
}
for (const result of results.results) {
documentInfos.push(await this.getDocumentInfo(result.id))
}
Expand All @@ -69,12 +80,20 @@ export class Confluence {
public async getDocumentInfo(documentId: number): Promise<DocumentInfo> {
this._log.debug(`Getting document information of document ${documentId}`)
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,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()

if (this.confluencePersonalAccessToken !== '') {
const document = await got(documentUrl, {
headers: {
'Authorization': 'Bearer ' + this.confluencePersonalAccessToken
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
} else {
const document = await got(documentUrl, {
username: this.confluenceUser,
password: this.confluencePassword,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).json<any>()
}
const author = document.version.by.username ?? null
const creator = document.history['createdBy'].username ?? null

Expand Down Expand Up @@ -142,31 +161,61 @@ export class Confluence {
public async createConfigurationDocument(space: string, title: string, parentId: string): Promise<string> {
const template = await fs.promises.readFile(path.join(__dirname, '..', '..', 'resources', 'configurationDocument.html'), 'utf-8')

const response = await got
.post(`${this.confluenceUrl}/rest/api/content`, {
json: {
type: 'page',
title: title,
space: {
key: space,
let response: any
if (this.confluencePersonalAccessToken !== '') {
response = await got
.post(`${this.confluenceUrl}/rest/api/content`, {
json: {
type: 'page',
title: title,
space: {
key: space,
},
ancestors: [
{
id: parentId,
},
],
body: {
storage: {
value: template,
representation: 'storage',
},
},
},
ancestors: [
{
id: parentId,
headers: {
'Authorization': 'Bearer ' + this.confluencePersonalAccessToken
}
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.json<any>()
} else {
response = await got
.post(`${this.confluenceUrl}/rest/api/content`, {
json: {
type: 'page',
title: title,
space: {
key: space,
},
],
body: {
storage: {
value: template,
representation: 'storage',
ancestors: [
{
id: parentId,
},
],
body: {
storage: {
value: template,
representation: 'storage',
},
},
},
},
username: this.confluenceUser,
password: this.confluencePassword,
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.json<any>()
username: this.confluenceUser,
password: this.confluencePassword,
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.json<any>()
}
return response.id
}
}
14 changes: 13 additions & 1 deletion lib/commands/Check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,29 @@ export default class extends Command {
public async execute(options: CheckOptions): Promise<void> {
const log = options.getLogger()

if(
options.confluencePersonalAccessToken === ''
&& (
options.confluenceUser === ''
|| options.confluencePassword === ''
)
) {
log.error('user and/or password parameter not set or empty! When not using the token parameter both of these have to be set!')
return
}

log.info('Checking for outdated documents')

const configuration = new Configuration(
options.confluenceUrl,
options.confluenceUser,
options.confluencePassword,
options.confluencePersonalAccessToken,
options.configurationDocumentId
)
await configuration.load()

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

const notification = new Notification(configuration, options.smtpTransportUrl, confluence, null, options.dryRun)

Expand Down
13 changes: 12 additions & 1 deletion lib/commands/CreateConfigurationDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,20 @@ export default class extends Command {
public async execute(options: CheckOptions): Promise<string> {
const log = options.getLogger()

if(
options.confluencePersonalAccessToken === ''
&& (
options.confluenceUser === ''
|| options.confluencePassword === ''
)
) {
log.error('user and/or password parameter not set or empty! When not using the token parameter both of these have to be set!')
return
}

log.info('Checking for outdated documents')

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

const pageId = await confluence.createConfigurationDocument(options.space, options.title, options.parentId)

Expand Down

0 comments on commit 0f6910e

Please sign in to comment.