Skip to content

Commit

Permalink
Merge pull request #740 from dhis2/master
Browse files Browse the repository at this point in the history
chore: merge master into next
  • Loading branch information
Birkbjo authored Jan 3, 2024
2 parents 13ab555 + c6bfa3e commit 414603c
Show file tree
Hide file tree
Showing 16 changed files with 670 additions and 393 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# [2.33.0](https://github.com/dhis2/app-hub/compare/v2.32.2...v2.33.0) (2023-08-01)


### Bug Fixes

* add docs for slack arguments ([de11f5b](https://github.com/dhis2/app-hub/commit/de11f5bb899f6ecf616c9b81076961c95b7e62f5))
* debug log ([5188baf](https://github.com/dhis2/app-hub/commit/5188baf7dfb569e989e590b5d46b633fc02243aa))
* **slackmessager:** update review now link ([4b9875d](https://github.com/dhis2/app-hub/commit/4b9875dba49b60370ff86023244121da8da9e121))
* slackwebhookmessager rename ([d86ba80](https://github.com/dhis2/app-hub/commit/d86ba80fc6fbc4d6e317b4ca4371c52056a45f1b))


### Features

* **notifications:** add slack webhook for new apps ([2f222ee](https://github.com/dhis2/app-hub/commit/2f222ee7a89c3259889d956444cbd2ba91aaa8f6))

## [2.32.2](https://github.com/dhis2/app-hub/compare/v2.32.1...v2.32.2) (2023-05-16)


Expand Down
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "client",
"version": "2.32.2",
"version": "2.33.0",
"description": "The App Hub Client",
"repository": "https://github.com/dhis2/app-hub",
"author": "Birk Johansson <[email protected]>",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@
"cypress-cucumber-preprocessor": {
"nonGlobalStepDefinitions": true
},
"version": "2.32.2"
"version": "2.33.0"
}
3 changes: 2 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "server",
"version": "2.32.2",
"version": "2.33.0",
"description": "The App Hub Server",
"main": "src/main.js",
"repository": "https://github.com/dhis2/app-hub",
Expand Down Expand Up @@ -29,6 +29,7 @@
"@hapi/inert": "^7.1.0",
"@hapi/vision": "^7.0.1",
"@hapipal/schmervice": "^2.1.0",
"@slack/webhook": "^6.1.0",
"adm-zip": "^0.5.5",
"auth0": "^2.36.1",
"aws-sdk": "^2.981.0",
Expand Down
11 changes: 10 additions & 1 deletion server/src/routes/v1/apps/formatting/convertAppsToApiV1Format.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ const convertDbAppViewRowToAppApiV1Object = (app) => ({
reviews: [],
})

const getMediaUrl = ({ serverUrl, organisationSlug, appId, mediaId }) =>
`${serverUrl}/v1/apps/media/${organisationSlug}/${appId}/${mediaId}`

const convertAppToV1Media = (app, serverUrl) => {
return {
imageUrl: `${serverUrl}/v1/apps/media/${app.organisation_slug}/${app.app_id}/${app.media_id}`,
imageUrl: getMediaUrl({
serverUrl,
organisationSlug: app.organisation_slug,
appId: app.app_id,
mediaId: app.media_id,
}),
caption: '',
created: +new Date(app.media_created_at),
description: '',
Expand Down Expand Up @@ -122,4 +130,5 @@ const convertAll = (apps, request) => {
module.exports = {
convertAppsToApiV1Format: convertAll,
convertAppToV1AppVersion,
getMediaUrl,
}
13 changes: 9 additions & 4 deletions server/src/routes/v1/apps/formatting/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const {
convertAppToV1AppVersion,
convertAppsToApiV1Format,
getMediaUrl,
} = require('./convertAppsToApiV1Format')

module.exports = {
convertAppToV1AppVersion: require('./convertAppsToApiV1Format')
.convertAppToV1AppVersion,
convertAppsToApiV1Format: require('./convertAppsToApiV1Format')
.convertAppsToApiV1Format,
convertAppToV1AppVersion,
convertAppsToApiV1Format,
getMediaUrl,
}
36 changes: 31 additions & 5 deletions server/src/routes/v1/apps/handlers/createApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ const {
} = require('../../../../security')
const App = require('../../../../services/app')
const Organisation = require('../../../../services/organisation')
const { saveFile } = require('../../../../utils')
const { saveFile, getServerUrl } = require('../../../../utils')
const { validateImageMetadata } = require('../../../../utils/validateMime')
const { getMediaUrl } = require('../../apps/formatting')
const { server } = require('@hapi/hapi')

module.exports = {
method: 'POST',
Expand Down Expand Up @@ -39,6 +41,7 @@ module.exports = {
if (!canCreateApp(request, h)) {
throw Boom.unauthorized()
}
const { notificationService } = request.services(true)

const { db } = h.context
const { id: currentUserId } = await getCurrentUserFromRequest(
Expand Down Expand Up @@ -77,11 +80,12 @@ module.exports = {
)
}

const app = await db.transaction(async trx => {
const { appType } = appJsonPayload
const { appType } = appJsonPayload
const { name, description, sourceUrl } = appJsonPayload
let logoMediaId
const app = await db.transaction(async (trx) => {
const { file } = payload

const { name, description, sourceUrl } = appJsonPayload
const {
version,
demoUrl,
Expand Down Expand Up @@ -142,7 +146,7 @@ module.exports = {
const logoMetadata = logo.hapi
validateImageMetadata(request.server.mime, logoMetadata)

const { id: logoId } = await App.createMediaForApp(
const { id: logoId, media_id } = await App.createMediaForApp(
app.id,
{
userId: currentUserId,
Expand All @@ -154,6 +158,7 @@ module.exports = {
},
trx
)
logoMediaId = logoId

const appUpload = saveFile(
`${app.id}/${appVersion.id}`,
Expand All @@ -166,6 +171,27 @@ module.exports = {
return app
})

const imageUrl = getMediaUrl({
serverUrl: getServerUrl(request),
organisationSlug: organisation.slug,
appId: app.id,
mediaId: logoMediaId,
})
notificationService
.sendNewAppNotifications({
appName: name,
organisationName: organisation.name,
imageUrl,
sourceUrl,
link: `${getServerUrl(request, { base: true })}/user/app/${
app.id
}`,
})
.catch((e) => {
//.catch() so we don't have to await
request.logger.error('Failed to send notification %o', e)
})

return h.response(app).created(`/v2/apps/${app.id}`)
},
}
2 changes: 1 addition & 1 deletion server/src/routes/v1/apps/handlers/getSingleApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ module.exports = {
db
)
isDeveloper =
appsUserCanEdit.map(app => app.app_id).indexOf(appId) !== -1
appsUserCanEdit.map((app) => app.app_id).indexOf(appId) !== -1
} catch (err) {
//no user on request
debug('No user in request')
Expand Down
3 changes: 3 additions & 0 deletions server/src/server/env-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const config = {
dsn: process.env.SENTRY_DSN,
environment: process.env.SENTRY_ENVIRONMENT || process.env.NODE_ENV,
},
slack: {
webhookUrl: process.env.SLACK_WEBHOOK_URL,
},
auth: {
noAuthUserIdMapping: process.env.NO_AUTH_MAPPED_USER_ID,
config: {
Expand Down
4 changes: 4 additions & 0 deletions server/src/server/init-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const staticFrontendRoutes = require('../plugins/staticFrontendRoutes')
const { getUserDecoration } = require('../security')
const { createAppVersionService } = require('../services/appVersion')
const { createEmailService } = require('../services/EmailService')
const {
createNotificationService,
} = require('../services/NotificationService/NotificationService.js')

exports.init = async (knex, config) => {
debug('Starting server...')
Expand Down Expand Up @@ -109,6 +112,7 @@ exports.init = async (knex, config) => {

await server.registerService(createEmailService)
await server.registerService(createAppVersionService)
await server.registerService(createNotificationService)

await server.register({
plugin: staticFrontendRoutes,
Expand Down
25 changes: 25 additions & 0 deletions server/src/services/NotificationService/NotificationMessager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const messagerTypes = {
WEBHOOK: 'webhook',
email: 'email',
}

class NotificationMessager {
constructor(name, { type } = {}) {
if (this.constructor === NotificationMessager) {
throw new TypeError(
'Class "NotificationMessager" cannot be instantiated directly.'
)
}
this.name = name
this.type = type
}

send() {
throw new Error('Method "sendNotification" must be implemented.')
}
}

module.exports = {
messagerTypes,
NotificationMessager,
}
72 changes: 72 additions & 0 deletions server/src/services/NotificationService/NotificationService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const Schmervice = require('@hapipal/schmervice')
const { SlackWebhookMessager } = require('./SlackWebhookMessager.js')

class NotificationService extends Schmervice.Service {
constructor(server, schmerviceOptions, { messagers }) {
super(server, schmerviceOptions)

if (!messagers || messagers.length < 1) {
server.logger.warn(
'No messagers provided to NotificationService, notifications will not be sent.'
)
} else {
const messagersName = messagers.map((m) => m.name).join(', ')
server.logger.info(
`Init NotificationService with messagers: ${messagersName}`
)
}

this.messagers = messagers
}

async sendNewAppNotifications({
appName,
imageUrl,
link,
organisationName,
sourceUrl,
}) {
const newAppMessagers = this.messagers.filter(
(m) => !!m.sendNewAppNotification
)
if (newAppMessagers.length < 1) {
return Promise.resolve(null)
}

const promises = newAppMessagers.map((messager) => {
this.server.logger.info(
`Sending new app notification, using messager: ${messager.name}`
)
return messager.sendNewAppNotification({
appName,
imageUrl,
link,
organisationName,
sourceUrl,
})
})
return Promise.all(promises)
}
}

const createNotificationService = (server, schmerviceOptions) => {
const service = new NotificationService(server, schmerviceOptions, {
messagers: createMessagers(server),
})
return Schmervice.withName('notificationService', service)
}

const createMessagers = (server) => {
const messagers = []
const { config } = server.realm.settings.bind
if (config.slack?.webhookUrl) {
const slackMessager = new SlackWebhookMessager(
'slack',
config.slack.webhookUrl
)
messagers.push(slackMessager)
}
return messagers
}

module.exports = { NotificationService, createNotificationService }
Loading

0 comments on commit 414603c

Please sign in to comment.