diff --git a/client/components/modals/notification/NotificationEditModal.vue b/client/components/modals/notification/NotificationEditModal.vue new file mode 100644 index 00000000..f831c0aa --- /dev/null +++ b/client/components/modals/notification/NotificationEditModal.vue @@ -0,0 +1,253 @@ + + + diff --git a/client/pages/config/notifications.vue b/client/pages/config/notifications.vue index 6f944335..fe9b0294 100644 --- a/client/pages/config/notifications.vue +++ b/client/pages/config/notifications.vue @@ -10,7 +10,25 @@ Save + +
+ +
+

Notifications

+ Create add +
+ +
+

No notifications

+
+
+ + @@ -21,11 +39,18 @@ export default { loading: false, appriseApiUrl: null, notifications: [], - notificationSettings: null + notificationSettings: null, + notificationData: null, + showEditModal: false, + selectedNotification: null } }, computed: {}, methods: { + clickCreate() { + this.selectedNotification = null + this.showEditModal = true + }, submitForm() { if (this.notificationSettings && this.notificationSettings.appriseApiUrl == this.appriseApiUrl) { return @@ -52,18 +77,20 @@ export default { }, async init() { this.loading = true - const notificationSettings = await this.$axios.$get('/api/notifications').catch((error) => { + const notificationResponse = await this.$axios.$get('/api/notifications').catch((error) => { console.error('Failed to get notification settings', error) this.$toast.error('Failed to load notification settings') return null }) this.loading = false - if (!notificationSettings) { + if (!notificationResponse) { return } - this.notificationSettings = notificationSettings - this.appriseApiUrl = notificationSettings.appriseApiUrl - this.notifications = notificationSettings.notifications || [] + this.notificationSettings = notificationResponse.settings + this.notificationData = notificationResponse.data + console.log('Notification response', notificationResponse) + this.appriseApiUrl = this.notificationSettings.appriseApiUrl + this.notifications = this.notificationSettings.notifications || [] } }, mounted() { diff --git a/server/Server.js b/server/Server.js index 5500a14b..f494fc23 100644 --- a/server/Server.js +++ b/server/Server.js @@ -80,7 +80,7 @@ class Server { this.cronManager = new CronManager(this.db, this.scanner, this.podcastManager) // Routers - this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.rssFeedManager, this.cronManager, this.emitter.bind(this), this.clientEmitter.bind(this)) + this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.abMergeManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.audioMetadataManager, this.rssFeedManager, this.cronManager, this.notificationManager, this.emitter.bind(this), this.clientEmitter.bind(this)) this.hlsRouter = new HlsRouter(this.db, this.auth, this.playbackSessionManager, this.emitter.bind(this)) this.staticRouter = new StaticRouter(this.db) diff --git a/server/controllers/NotificationController.js b/server/controllers/NotificationController.js index 80754271..689680b5 100644 --- a/server/controllers/NotificationController.js +++ b/server/controllers/NotificationController.js @@ -4,7 +4,10 @@ class NotificationController { constructor() { } get(req, res) { - res.json(this.db.notificationSettings) + res.json({ + data: this.notificationManager.getData(), + settings: this.db.notificationSettings + }) } async update(req, res) { @@ -15,6 +18,28 @@ class NotificationController { res.sendStatus(200) } + async createEvent(req, res) { + const success = this.db.notificationSettings.addNewEvent(req.body) + + if (success) { + await this.db.updateEntity('settings', this.db.notificationSettings) + } + res.sendStatus(200) + } + + async updateEvent(req, res) { + const success = this.db.notificationSettings.updateEvent(req.body) + + if (success) { + await this.db.updateEntity('settings', this.db.notificationSettings) + } + res.sendStatus(200) + } + + getData(req, res) { + res.json(this.notificationManager.getData()) + } + middleware(req, res, next) { if (!req.user.isAdminOrUp) { return res.sendStatus(404) diff --git a/server/managers/NotificationManager.js b/server/managers/NotificationManager.js index be479046..da920268 100644 --- a/server/managers/NotificationManager.js +++ b/server/managers/NotificationManager.js @@ -1,5 +1,6 @@ const axios = require('axios') const Logger = require("../Logger") +const { notificationData } = require('../utils/notifications') class NotificationManager { constructor(db) { @@ -8,6 +9,10 @@ class NotificationManager { this.notificationFailedMap = {} } + getData() { + return notificationData + } + onPodcastEpisodeDownloaded(libraryItem, episode) { if (!this.db.notificationSettings.isUseable) return diff --git a/server/objects/Notification.js b/server/objects/Notification.js index 9e7bfab2..9c64bb28 100644 --- a/server/objects/Notification.js +++ b/server/objects/Notification.js @@ -1,3 +1,5 @@ +const { getId } = require('../utils/index') + class Notification { constructor(notification = null) { this.id = null @@ -42,6 +44,37 @@ class Notification { } } + setData(payload) { + this.id = getId('noti') + this.libraryId = payload.libraryId || null + this.eventName = payload.eventName + this.urls = payload.urls + this.titleTemplate = payload.titleTemplate + this.bodyTemplate = payload.bodyTemplate + this.enabled = !!payload.enabled + this.type = payload.type || null + this.createdAt = Date.now() + } + + update(payload) { + const keysToUpdate = ['libraryId', 'eventName', 'urls', 'titleTemplate', 'bodyTemplate', 'enabled', 'type'] + var hasUpdated = false + for (const key of keysToUpdate) { + if (payload[key]) { + if (key === 'urls') { + if (payload[key].join(',') !== this.urls.join(',')) { + this.urls = [...payload[key]] + hasUpdated = true + } + } else if (payload[key] !== this[key]) { + this[key] = payload[key] + hasUpdated = true + } + } + } + return hasUpdated + } + parseTitleTemplate(data) { // TODO: Implement template parsing return 'Test Title' diff --git a/server/objects/settings/NotificationSettings.js b/server/objects/settings/NotificationSettings.js index 901749ff..3a67b287 100644 --- a/server/objects/settings/NotificationSettings.js +++ b/server/objects/settings/NotificationSettings.js @@ -1,3 +1,5 @@ +const Notification = require('../Notification') + class NotificationSettings { constructor(settings = null) { this.id = 'notification-settings' @@ -41,5 +43,23 @@ class NotificationSettings { } return false } + + addNewEvent(payload) { + if (!payload) return false + // TODO: validate + + const notification = new Notification() + notification.setData(payload) + this.notifications.push(notification) + return true + } + + updateEvent(payload) { + if (!payload) return false + const notification = this.notifications.find(n => n.id === payload.id) + if (!notification) return false + + return notification.update(payload) + } } module.exports = NotificationSettings \ No newline at end of file diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 12912b0e..6eabbbf4 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -26,7 +26,7 @@ const Series = require('../objects/entities/Series') const FileSystemController = require('../controllers/FileSystemController') class ApiRouter { - constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, cronManager, emitter, clientEmitter) { + constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, cronManager, notificationManager, emitter, clientEmitter) { this.db = db this.auth = auth this.scanner = scanner @@ -40,6 +40,7 @@ class ApiRouter { this.audioMetadataManager = audioMetadataManager this.rssFeedManager = rssFeedManager this.cronManager = cronManager + this.notificationManager = notificationManager this.emitter = emitter this.clientEmitter = clientEmitter @@ -205,6 +206,9 @@ class ApiRouter { // this.router.get('/notifications', NotificationController.middleware.bind(this), NotificationController.get.bind(this)) this.router.patch('/notifications', NotificationController.middleware.bind(this), NotificationController.update.bind(this)) + this.router.post('/notifications/event', NotificationController.middleware.bind(this), NotificationController.createEvent.bind(this)) + this.router.patch('/notifications/event', NotificationController.middleware.bind(this), NotificationController.updateEvent.bind(this)) + this.router.get('/notificationdata', NotificationController.middleware.bind(this), NotificationController.getData.bind(this)) // // Misc Routes diff --git a/server/utils/notifications.js b/server/utils/notifications.js new file mode 100644 index 00000000..4972f875 --- /dev/null +++ b/server/utils/notifications.js @@ -0,0 +1,13 @@ +module.exports.notificationData = { + events: [ + { + name: 'onTest', + requiresLibrary: false, + description: 'Notification for testing', + defaults: { + title: 'Test Title', + body: 'Test Body' + } + } + ] +} \ No newline at end of file