diff --git a/docs/controllers/LibraryController.yaml b/docs/controllers/LibraryController.yaml index 80b99518..b985c05e 100644 --- a/docs/controllers/LibraryController.yaml +++ b/docs/controllers/LibraryController.yaml @@ -111,9 +111,12 @@ paths: content: application/json: schema: - type: array - items: - $ref: '../objects/Library.yaml#/components/schemas/library' + type: object + properties: + libraries: + type: array + items: + $ref: '../objects/Library.yaml#/components/schemas/library' post: operationId: createLibrary summary: Create a new library on server diff --git a/docs/controllers/NotificationController.yaml b/docs/controllers/NotificationController.yaml new file mode 100644 index 00000000..4d3fa09b --- /dev/null +++ b/docs/controllers/NotificationController.yaml @@ -0,0 +1,223 @@ +components: + responses: + notification200: + description: Notification endpoint success. + content: + text/html: + schema: + type: string + example: OK + notification404: + description: An admin user is required or notification with the given ID not found. + content: + text/html: + schema: + type: string + example: Series not found. +paths: + /api/notifications: + get: + operationId: getNotifications + description: Get all Apprise notification events and notification settings for server. + tags: + - Notification + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + events: + type: array + items: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationEvent' + settings: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationSettings' + '404': + $ref: '#/components/responses/notification404' + patch: + operationId: updateNotificationSettings + description: Update Notification settings. + tags: + - Notification + requestBody: + content: + application/json: + schema: + type: object + properties: + appriseApiUrl: + $ref: '../objects/Notification.yaml#/components/schemas/appriseApiUrl' + maxFailedAttempts: + $ref: '../objects/Notification.yaml#/components/schemas/maxFailedAttempts' + maxNotificationQueue: + $ref: '../objects/Notification.yaml#/components/schemas/maxNotificationQueue' + responses: + '200': + $ref: '#/components/responses/notification200' + '404': + $ref: '#/components/responses/notification404' + post: + operationId: createNotification + description: Update Notification settings. + tags: + - Notification + requestBody: + content: + application/json: + schema: + type: object + properties: + libraryId: + $ref: '../objects/Library.yaml#/components/schemas/libraryIdNullable' + eventName: + $ref: '../objects/Notification.yaml#/components/schemas/notificationEventName' + urls: + $ref: '../objects/Notification.yaml#/components/schemas/urls' + titleTemplate: + $ref: '../objects/Notification.yaml#/components/schemas/titleTemplate' + bodyTemplate: + $ref: '../objects/Notification.yaml#/components/schemas/bodyTemplate' + enabled: + $ref: '../objects/Notification.yaml#/components/schemas/enabled' + type: + $ref: '../objects/Notification.yaml#/components/schemas/notificationType' + required: + - eventName + - urls + - titleTemplate + - bodyTemplate + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + settings: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationSettings' + '404': + $ref: '#/components/responses/notification404' + /api/notificationdata: + get: + operationId: getNotificationEventData + description: Get all Apprise notification event data for the server. + tags: + - Notification + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + events: + type: array + items: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationEvent' + '404': + $ref: '#/components/responses/notification404' + /api/notifications/test: + get: + operationId: sendDefaultTestNotification + description: Send a test notification. + tags: + - Notification + parameters: + - in: query + name: fail + description: Whether to intentionally cause the notification to fail. `0` for false, `1` for true. + schema: + type: integer + responses: + '200': + $ref: '#/components/responses/notification200' + '404': + $ref: '#/components/responses/notification404' + /api/notifications/{id}: + parameters: + - name: id + in: path + description: The ID of the notification. + required: true + schema: + $ref: '../objects/Notification.yaml#/components/schemas/notificationId' + delete: + operationId: deleteNotification + description: Delete the notification by ID and return the notification settings. + tags: + - Notification + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + settings: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationSettings' + '404': + $ref: '#/components/responses/notification404' + patch: + operationId: updateNotification + description: Update individual Notification + tags: + - Notification + requestBody: + content: + application/json: + schema: + type: object + properties: + libraryId: + $ref: '../objects/Library.yaml#/components/schemas/libraryId' + eventName: + $ref: '../objects/Notification.yaml#/components/schemas/notificationEventName' + urls: + $ref: '../objects/Notification.yaml#/components/schemas/urls' + titleTemplate: + $ref: '../objects/Notification.yaml#/components/schemas/titleTemplate' + bodyTemplate: + $ref: '../objects/Notification.yaml#/components/schemas/bodyTemplate' + enabled: + $ref: '../objects/Notification.yaml#/components/schemas/enabled' + type: + $ref: '../objects/Notification.yaml#/components/schemas/notificationType' + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + settings: + $ref: '../objects/Notification.yaml#/components/schemas/NotificationSettings' + '404': + $ref: '#/components/responses/notification404' + /api/notifications/{id}/test: + parameters: + - name: id + in: path + description: The ID of the notification. + required: true + schema: + $ref: '../objects/Notification.yaml#/components/schemas/notificationId' + get: + operationId: sendTestNotification + description: Send a test to the given notification. + tags: + - Notification + responses: + '200': + $ref: '#/components/responses/notification200' + '404': + $ref: '#/components/responses/notification404' diff --git a/docs/objects/Library.yaml b/docs/objects/Library.yaml index c7a2a52e..bab503cc 100644 --- a/docs/objects/Library.yaml +++ b/docs/objects/Library.yaml @@ -10,6 +10,12 @@ components: description: The ID of the library. format: uuid example: 'e4bb1afb-4a4f-4dd6-8be0-e615d233185b' + libraryIdNullable: + type: string + description: The ID of the library. Applies to all libraries if `null`. + format: uuid + nullable: true + example: 'e4bb1afb-4a4f-4dd6-8be0-e615d233185b' libraryName: description: The name of the library. type: string diff --git a/docs/objects/LibraryItem.yaml b/docs/objects/LibraryItem.yaml index 0b85310d..107ba9f3 100644 --- a/docs/objects/LibraryItem.yaml +++ b/docs/objects/LibraryItem.yaml @@ -69,4 +69,7 @@ components: description: A single item on the server, like a book or podcast. Includes series sequence information. allOf: - $ref: '#/components/schemas/libraryItemBase' - - $ref: './entities/Series.yaml#/components/schemas/sequence' + - type: object + properties: + sequence: + $ref: './entities/Series.yaml#/components/schemas/sequence' diff --git a/docs/objects/Notification.yaml b/docs/objects/Notification.yaml new file mode 100644 index 00000000..bb9ce8bd --- /dev/null +++ b/docs/objects/Notification.yaml @@ -0,0 +1,142 @@ +components: + schemas: + notificationId: + type: string + description: The ID of the notification. + example: notification-settings + # This is using a value of `notification-settings`, not a UUID. Need to investigate + #format: uuid + #example: e4bb1afb-4a4f-4dd6-8be0-e615d233185b + appriseApiUrl: + type: string + nullable: true + description: The full URL where the Apprise API to use is located. + maxFailedAttempts: + type: integer + minimum: 0 + default: 5 + description: The maximum number of times a notification fails before being disabled. + maxNotificationQueue: + type: integer + description: The maximum number of notifications in the notification queue before events are ignored. + notificationEventName: + type: string + description: The name of the event the notification will fire on. + enum: ['onPodcastEpisodeDownloaded', 'onTest'] + urls: + type: array + items: + type: string + description: The Apprise URLs to use for the notification. + example: http://192.168.0.3:8000/notify/my-cool-notification + titleTemplate: + type: string + description: The template for the notification title. + example: 'New {{podcastTitle}} Episode!' + bodyTemplate: + type: string + description: The template for the notification body. + example: '{{episodeTitle}} has been added to {{libraryName}} library.' + enabled: + type: boolean + default: false + description: Whether the notification is enabled. + notificationType: + type: string + enum: ['info', 'success', 'warning', 'failure'] + nullable: true + default: 'info' + description: The notification's type. + Notification: + type: object + properties: + id: + $ref: '#/components/schemas/notificationId' + libraryId: + $ref: './Library.yaml#/components/schemas/libraryIdNullable' + eventName: + $ref: '#/components/schemas/notificationEventName' + urls: + $ref: '#/components/schemas/urls' + titleTemplate: + $ref: '#/components/schemas/titleTemplate' + bodyTemplate: + $ref: '#/components/schemas/bodyTemplate' + enabled: + $ref: '#/components/schemas/enabled' + type: + $ref: '#/components/schemas/notificationType' + lastFiredAt: + type: integer + nullable: true + description: The time (in ms since POSIX epoch) when the notification was last fired. Will be null if the notification has not fired. + lastAttemptFailed: + type: boolean + description: Whether the last notification attempt failed. + numConsecutiveFailedAttempts: + type: integer + description: The number of consecutive times the notification has failed. + default: 0 + numTimesFired: + type: integer + description: The number of times the notification has fired. + default: 0 + createdAt: + $ref: '../schemas.yaml#/components/schemas/createdAt' + NotificationEvent: + type: object + properties: + name: + type: string + description: The name of the notification event. The names and allowable values are defined at https://github.com/advplyr/audiobookshelf/blob/master/server/utils/notifications.js + requiresLibrary: + type: boolean + description: Whether the notification event depends on a library existing. + libraryMediaType: + type: string + description: The type of media of the library the notification depends on existing. Will not exist if requiresLibrary is false. + nullable: true + description: + type: string + description: The description of the notification event. + variables: + type: array + items: + type: string + description: The variables of the notification event that can be used in the notification templates. + defaults: + type: object + properties: + title: + type: string + description: The default title template for notifications using the notification event. + body: + type: string + description: The default body template for notifications using the notification event. + testData: + type: object + description: The keys of the testData object will match the list of variables. The values will be the data used when sending a test notification. + additionalProperties: + type: string + NotificationSettings: + type: object + properties: + id: + $ref: '#/components/schemas/notificationId' + appriseType: + type: string + description: The type of Apprise that will be used. At the moment, only api is available. + appriseApiUrl: + $ref: '#/components/schemas/appriseApiUrl' + notifications: + type: array + items: + $ref: '#/components/schemas/Notification' + description: The set notifications. + maxFailedAttempts: + $ref: '#/components/schemas/maxFailedAttempts' + maxNotificationQueue: + $ref: '#/components/schemas/maxNotificationQueue' + notificationDelay: + type: integer + description: The time (in ms) between notification pushes. diff --git a/docs/openapi.json b/docs/openapi.json index 082b5b4a..48274bb3 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -28,6 +28,10 @@ { "name": "Series", "description": "Series endpoints" + }, + { + "name": "Notification", + "description": "Notifications endpoints" } ], "paths": { @@ -426,9 +430,14 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/library" + "type": "object", + "properties": { + "libraries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/library" + } + } } } } @@ -1020,6 +1029,332 @@ } } }, + "/api/notifications": { + "get": { + "operationId": "getNotifications", + "description": "Get all Apprise notification events and notification settings for server.", + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationEvent" + } + } + } + }, + "settings": { + "$ref": "#/components/schemas/NotificationSettings" + } + } + } + } + } + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + }, + "patch": { + "operationId": "updateNotificationSettings", + "description": "Update Notification settings.", + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "appriseApiUrl": { + "$ref": "#/components/schemas/appriseApiUrl" + }, + "maxFailedAttempts": { + "$ref": "#/components/schemas/maxFailedAttempts" + }, + "maxNotificationQueue": { + "$ref": "#/components/schemas/maxNotificationQueue" + } + } + } + } + } + }, + "responses": { + "200": { + "$ref": "#/components/responses/notification200" + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + }, + "post": { + "operationId": "createNotification", + "description": "Update Notification settings.", + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "eventName", + "urls", + "titleTemplate", + "bodyTemplate" + ], + "properties": { + "libraryId": { + "$ref": "#/components/schemas/libraryIdNullable" + }, + "eventName": { + "$ref": "#/components/schemas/notificationEventName" + }, + "urls": { + "$ref": "#/components/schemas/urls" + }, + "titleTemplate": { + "$ref": "#/components/schemas/titleTemplate" + }, + "bodyTemplate": { + "$ref": "#/components/schemas/bodyTemplate" + }, + "enabled": { + "$ref": "#/components/schemas/enabled" + }, + "type": { + "$ref": "#/components/schemas/notificationType" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/components/schemas/NotificationSettings" + } + } + } + } + } + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + } + }, + "/api/notificationdata": { + "get": { + "operationId": "getNotificationEventData", + "description": "Get all Apprise notification event data for the server.", + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationEvent" + } + } + } + } + } + } + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + } + }, + "/api/notifications/test": { + "get": { + "operationId": "sendDefaultTestNotification", + "description": "Send a test notification.", + "tags": [ + "Notification" + ], + "parameters": [ + { + "in": "query", + "name": "fail", + "description": "Whether to intentionally cause the notification to fail. `0` for false, `1` for true.", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/notification200" + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + } + }, + "/api/notifications/{id}": { + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The ID of the notification.", + "required": true, + "schema": { + "$ref": "#/components/schemas/notificationId" + } + } + ], + "delete": { + "operationId": "deleteNotification", + "description": "Delete the notification by ID and return the notification settings.", + "tags": [ + "Notification" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/components/schemas/NotificationSettings" + } + } + } + } + } + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + }, + "patch": { + "operationId": "updateNotification", + "description": "Update individual Notification", + "tags": [ + "Notification" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "libraryId": { + "$ref": "#/components/schemas/libraryId" + }, + "eventName": { + "$ref": "#/components/schemas/notificationEventName" + }, + "urls": { + "$ref": "#/components/schemas/urls" + }, + "titleTemplate": { + "$ref": "#/components/schemas/titleTemplate" + }, + "bodyTemplate": { + "$ref": "#/components/schemas/bodyTemplate" + }, + "enabled": { + "$ref": "#/components/schemas/enabled" + }, + "type": { + "$ref": "#/components/schemas/notificationType" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/components/schemas/NotificationSettings" + } + } + } + } + } + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + } + }, + "/api/notifications/{id}/test": { + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The ID of the notification.", + "required": true, + "schema": { + "$ref": "#/components/schemas/notificationId" + } + } + ], + "get": { + "operationId": "sendTestNotification", + "description": "Send a test to the given notification.", + "tags": [ + "Notification" + ], + "responses": { + "200": { + "$ref": "#/components/responses/notification200" + }, + "404": { + "$ref": "#/components/responses/notification404" + } + } + } + }, "/api/series/{id}": { "parameters": [ { @@ -1860,7 +2195,12 @@ "$ref": "#/components/schemas/libraryItemBase" }, { - "$ref": "#/components/schemas/sequence" + "type": "object", + "properties": { + "sequence": { + "$ref": "#/components/schemas/sequence" + } + } } ] }, @@ -1974,6 +2314,208 @@ } } ] + }, + "NotificationEvent": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the notification event. The names and allowable values are defined at https://github.com/advplyr/audiobookshelf/blob/master/server/utils/notifications.js" + }, + "requiresLibrary": { + "type": "boolean", + "description": "Whether the notification event depends on a library existing." + }, + "libraryMediaType": { + "type": "string", + "description": "The type of media of the library the notification depends on existing. Will not exist if requiresLibrary is false.", + "nullable": true + }, + "description": { + "type": "string", + "description": "The description of the notification event." + }, + "variables": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The variables of the notification event that can be used in the notification templates." + }, + "defaults": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The default title template for notifications using the notification event." + }, + "body": { + "type": "string", + "description": "The default body template for notifications using the notification event." + } + } + }, + "testData": { + "type": "object", + "description": "The keys of the testData object will match the list of variables. The values will be the data used when sending a test notification.", + "additionalProperties": { + "type": "string" + } + } + } + }, + "notificationId": { + "type": "string", + "description": "The ID of the notification.", + "example": "notification-settings" + }, + "appriseApiUrl": { + "type": "string", + "nullable": true, + "description": "The full URL where the Apprise API to use is located." + }, + "libraryIdNullable": { + "type": "string", + "description": "The ID of the library. Applies to all libraries if `null`.", + "format": "uuid", + "nullable": true, + "example": "e4bb1afb-4a4f-4dd6-8be0-e615d233185b" + }, + "notificationEventName": { + "type": "string", + "description": "The name of the event the notification will fire on.", + "enum": [ + "onPodcastEpisodeDownloaded", + "onTest" + ] + }, + "urls": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The Apprise URLs to use for the notification.", + "example": "http://192.168.0.3:8000/notify/my-cool-notification" + }, + "titleTemplate": { + "type": "string", + "description": "The template for the notification title.", + "example": "New {{podcastTitle}} Episode!" + }, + "bodyTemplate": { + "type": "string", + "description": "The template for the notification body.", + "example": "{{episodeTitle}} has been added to {{libraryName}} library." + }, + "enabled": { + "type": "boolean", + "default": false, + "description": "Whether the notification is enabled." + }, + "notificationType": { + "type": "string", + "enum": [ + "info", + "success", + "warning", + "failure" + ], + "nullable": true, + "default": "info", + "description": "The notification's type." + }, + "Notification": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/notificationId" + }, + "libraryId": { + "$ref": "#/components/schemas/libraryIdNullable" + }, + "eventName": { + "$ref": "#/components/schemas/notificationEventName" + }, + "urls": { + "$ref": "#/components/schemas/urls" + }, + "titleTemplate": { + "$ref": "#/components/schemas/titleTemplate" + }, + "bodyTemplate": { + "$ref": "#/components/schemas/bodyTemplate" + }, + "enabled": { + "$ref": "#/components/schemas/enabled" + }, + "type": { + "$ref": "#/components/schemas/notificationType" + }, + "lastFiredAt": { + "type": "integer", + "nullable": true, + "description": "The time (in ms since POSIX epoch) when the notification was last fired. Will be null if the notification has not fired." + }, + "lastAttemptFailed": { + "type": "boolean", + "description": "Whether the last notification attempt failed." + }, + "numConsecutiveFailedAttempts": { + "type": "integer", + "description": "The number of consecutive times the notification has failed.", + "default": 0 + }, + "numTimesFired": { + "type": "integer", + "description": "The number of times the notification has fired.", + "default": 0 + }, + "createdAt": { + "$ref": "#/components/schemas/createdAt" + } + } + }, + "maxFailedAttempts": { + "type": "integer", + "minimum": 0, + "default": 5, + "description": "The maximum number of times a notification fails before being disabled." + }, + "maxNotificationQueue": { + "type": "integer", + "description": "The maximum number of notifications in the notification queue before events are ignored." + }, + "NotificationSettings": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/notificationId" + }, + "appriseType": { + "type": "string", + "description": "The type of Apprise that will be used. At the moment, only api is available." + }, + "appriseApiUrl": { + "$ref": "#/components/schemas/appriseApiUrl" + }, + "notifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Notification" + }, + "description": "The set notifications." + }, + "maxFailedAttempts": { + "$ref": "#/components/schemas/maxFailedAttempts" + }, + "maxNotificationQueue": { + "$ref": "#/components/schemas/maxNotificationQueue" + }, + "notificationDelay": { + "type": "integer", + "description": "The time (in ms) between notification pushes." + } + } } }, "responses": { @@ -2009,6 +2551,28 @@ } } }, + "notification404": { + "description": "An admin user is required or notification with the given ID not found.", + "content": { + "text/html": { + "schema": { + "type": "string", + "example": "Series not found." + } + } + } + }, + "notification200": { + "description": "Notification endpoint success.", + "content": { + "text/html": { + "schema": { + "type": "string", + "example": "OK" + } + } + } + }, "series404": { "description": "Series not found.", "content": { diff --git a/docs/root.yaml b/docs/root.yaml index 3c40f8dc..ee9d7b9c 100644 --- a/docs/root.yaml +++ b/docs/root.yaml @@ -35,6 +35,16 @@ paths: $ref: './controllers/LibraryController.yaml#/paths/~1api~1libraries~1{id}~1series' /api/libraries/{id}/series/{seriesId}: $ref: './controllers/LibraryController.yaml#/paths/~1api~1libraries~1{id}~1series~1{seriesId}' + /api/notifications: + $ref: './controllers/NotificationController.yaml#/paths/~1api~1notifications' + /api/notificationdata: + $ref: './controllers/NotificationController.yaml#/paths/~1api~1notificationdata' + /api/notifications/test: + $ref: './controllers/NotificationController.yaml#/paths/~1api~1notifications~1test' + /api/notifications/{id}: + $ref: './controllers/NotificationController.yaml#/paths/~1api~1notifications~1{id}' + /api/notifications/{id}/test: + $ref: './controllers/NotificationController.yaml#/paths/~1api~1notifications~1{id}~1test' /api/series/{id}: $ref: './controllers/SeriesController.yaml#/paths/~1api~1series~1{id}' tags: @@ -44,3 +54,5 @@ tags: description: Library endpoints - name: Series description: Series endpoints + - name: Notification + description: Notifications endpoints