diff --git a/CHANGELOG.md b/CHANGELOG.md index e8bfe76..cb78d18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.14.0 + +Adds the ability to replace a Push Notification you already sent with a new one. + ## 1.13.0 Adds custom icons and interruption levels for Push Notifications. Set `icon` to show a service logo or avatar on the notification, and `interruption_level` to deliver it as `passive`, `active`, or `time-sensitive`. diff --git a/README.md b/README.md index b35d0cd..f910539 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,29 @@ activitysmith.notifications.send( ) ``` +### Replace a Push Notification + +Every send returns a `notification_id`. Pass it to `replace` to update a Push Notification you already sent, for example when an incident you alerted on is resolved. The replacement takes the old notification's place on the Lock Screen and in history instead of stacking a second one. It arrives silently, without sound or waking the screen, and goes to the same recipients as the original. + +Omit `metadata` or `tags` to keep their stored values. + +```ruby +sent = activitysmith.notifications.send( + { + title: "🚨 checkout-api is down", + message: "500 errors on 62% of requests." + } +) + +activitysmith.notifications.replace( + sent.notification_id, + { + title: "✅ checkout-api recovered", + message: "Error rate is back to normal. Incident resolved." + } +) +``` + ## Live Activities Choose the Live Activity type that matches what you want to show: diff --git a/generated/activitysmith_openapi.rb b/generated/activitysmith_openapi.rb index 275ba82..a810273 100644 --- a/generated/activitysmith_openapi.rb +++ b/generated/activitysmith_openapi.rb @@ -59,6 +59,8 @@ require 'activitysmith_openapi/models/push_interruption_level' require 'activitysmith_openapi/models/push_notification_action' require 'activitysmith_openapi/models/push_notification_action_type' +require 'activitysmith_openapi/models/push_notification_replace_request' +require 'activitysmith_openapi/models/push_notification_replace_response' require 'activitysmith_openapi/models/push_notification_request' require 'activitysmith_openapi/models/push_notification_response' require 'activitysmith_openapi/models/push_notification_webhook_method' diff --git a/generated/activitysmith_openapi/api/push_notifications_api.rb b/generated/activitysmith_openapi/api/push_notifications_api.rb index 3b2dfe6..ba419eb 100644 --- a/generated/activitysmith_openapi/api/push_notifications_api.rb +++ b/generated/activitysmith_openapi/api/push_notifications_api.rb @@ -19,8 +19,86 @@ class PushNotificationsApi def initialize(api_client = ApiClient.default) @api_client = api_client end + # Replace a push notification + # Replaces a Push Notification you already sent, using the `notification_id` from the send response. The replacement takes the original's place on the Lock Screen and in Notification Center instead of appearing as a second notification. It is delivered silently, with no sound or screen wake, to the same recipients as the original. Notification history is updated in place. + # @param notification_id [String] The `notification_id` returned when the Push Notification was sent. + # @param push_notification_replace_request [PushNotificationReplaceRequest] + # @param [Hash] opts the optional parameters + # @return [PushNotificationReplaceResponse] + def replace_push_notification(notification_id, push_notification_replace_request, opts = {}) + data, _status_code, _headers = replace_push_notification_with_http_info(notification_id, push_notification_replace_request, opts) + data + end + + # Replace a push notification + # Replaces a Push Notification you already sent, using the `notification_id` from the send response. The replacement takes the original's place on the Lock Screen and in Notification Center instead of appearing as a second notification. It is delivered silently, with no sound or screen wake, to the same recipients as the original. Notification history is updated in place. + # @param notification_id [String] The `notification_id` returned when the Push Notification was sent. + # @param push_notification_replace_request [PushNotificationReplaceRequest] + # @param [Hash] opts the optional parameters + # @return [Array<(PushNotificationReplaceResponse, Integer, Hash)>] PushNotificationReplaceResponse data, response status code and response headers + def replace_push_notification_with_http_info(notification_id, push_notification_replace_request, opts = {}) + if @api_client.config.debugging + @api_client.config.logger.debug 'Calling API: PushNotificationsApi.replace_push_notification ...' + end + # verify the required parameter 'notification_id' is set + if @api_client.config.client_side_validation && notification_id.nil? + fail ArgumentError, "Missing the required parameter 'notification_id' when calling PushNotificationsApi.replace_push_notification" + end + if @api_client.config.client_side_validation && notification_id.to_s.length < 1 + fail ArgumentError, 'invalid value for "notification_id" when calling PushNotificationsApi.replace_push_notification, the character length must be great than or equal to 1.' + end + + # verify the required parameter 'push_notification_replace_request' is set + if @api_client.config.client_side_validation && push_notification_replace_request.nil? + fail ArgumentError, "Missing the required parameter 'push_notification_replace_request' when calling PushNotificationsApi.replace_push_notification" + end + # resource path + local_var_path = '/push-notification/{notification_id}'.sub('{' + 'notification_id' + '}', CGI.escape(notification_id.to_s)) + + # query parameters + query_params = opts[:query_params] || {} + + # header parameters + header_params = opts[:header_params] || {} + # HTTP header 'Accept' (if needed) + header_params['Accept'] = @api_client.select_header_accept(['application/json']) + # HTTP header 'Content-Type' + content_type = @api_client.select_header_content_type(['application/json']) + if !content_type.nil? + header_params['Content-Type'] = content_type + end + + # form parameters + form_params = opts[:form_params] || {} + + # http body (model) + post_body = opts[:debug_body] || @api_client.object_to_http_body(push_notification_replace_request) + + # return_type + return_type = opts[:debug_return_type] || 'PushNotificationReplaceResponse' + + # auth_names + auth_names = opts[:debug_auth_names] || ['apiKeyAuth'] + + new_options = opts.merge( + :operation => :"PushNotificationsApi.replace_push_notification", + :header_params => header_params, + :query_params => query_params, + :form_params => form_params, + :body => post_body, + :auth_names => auth_names, + :return_type => return_type + ) + + data, status_code, headers = @api_client.call_api(:PUT, local_var_path, new_options) + if @api_client.config.debugging + @api_client.config.logger.debug "API called: PushNotificationsApi#replace_push_notification\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + end + return data, status_code, headers + end + # Send a push notification - # Sends a push notification to devices matched by API key scope and optional target channels. Supports optional redirection URL, optional media preview or playback when the notification is expanded, and up to 4 interactive actions. `media` cannot be combined with `actions`. Optional `icon` shows a custom image, such as a service logo or avatar, next to a smaller app icon. Optional `interruption_level` sets how urgently iOS presents the notification. Optional tags to organize and filter notification history. + # Sends a push notification to devices matched by API key scope and optional target channels. Supports optional redirection URL, optional media preview or playback when the notification is expanded, and up to 4 interactive actions. `media` cannot be combined with `actions`. Optional `icon` shows a custom image, such as a logo or avatar, next to a smaller app icon. Optional `interruption_level` sets how urgently iOS presents the notification. Optional tags to organize and filter notification history. # @param push_notification_request [PushNotificationRequest] # @param [Hash] opts the optional parameters # @return [PushNotificationResponse] @@ -30,7 +108,7 @@ def send_push_notification(push_notification_request, opts = {}) end # Send a push notification - # Sends a push notification to devices matched by API key scope and optional target channels. Supports optional redirection URL, optional media preview or playback when the notification is expanded, and up to 4 interactive actions. `media` cannot be combined with `actions`. Optional `icon` shows a custom image, such as a service logo or avatar, next to a smaller app icon. Optional `interruption_level` sets how urgently iOS presents the notification. Optional tags to organize and filter notification history. + # Sends a push notification to devices matched by API key scope and optional target channels. Supports optional redirection URL, optional media preview or playback when the notification is expanded, and up to 4 interactive actions. `media` cannot be combined with `actions`. Optional `icon` shows a custom image, such as a logo or avatar, next to a smaller app icon. Optional `interruption_level` sets how urgently iOS presents the notification. Optional tags to organize and filter notification history. # @param push_notification_request [PushNotificationRequest] # @param [Hash] opts the optional parameters # @return [Array<(PushNotificationResponse, Integer, Hash)>] PushNotificationResponse data, response status code and response headers diff --git a/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb index 4482afc..02eb456 100644 --- a/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb +++ b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb @@ -35,6 +35,15 @@ class AppIconBadgeCountUpdateResponse attr_accessor :timestamp + # Number of device tokens targeted. + attr_accessor :devices_targeted + + # Number of device tokens deactivated because APNs reported them unregistered. + attr_accessor :devices_deactivated + + # Number of targeted device tokens APNs reported as unregistered. + attr_accessor :devices_unregistered + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -45,7 +54,10 @@ def self.attribute_map :'devices_notified' => :'devices_notified', :'users_notified' => :'users_notified', :'effective_channel_slugs' => :'effective_channel_slugs', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'devices_targeted' => :'devices_targeted', + :'devices_deactivated' => :'devices_deactivated', + :'devices_unregistered' => :'devices_unregistered' } end @@ -64,7 +76,10 @@ def self.openapi_types :'devices_notified' => :'Integer', :'users_notified' => :'Integer', :'effective_channel_slugs' => :'Array', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'devices_targeted' => :'Integer', + :'devices_deactivated' => :'Integer', + :'devices_unregistered' => :'Integer' } end @@ -134,6 +149,18 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'devices_targeted') + self.devices_targeted = attributes[:'devices_targeted'] + end + + if attributes.key?(:'devices_deactivated') + self.devices_deactivated = attributes[:'devices_deactivated'] + end + + if attributes.key?(:'devices_unregistered') + self.devices_unregistered = attributes[:'devices_unregistered'] + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -221,7 +248,10 @@ def ==(o) devices_notified == o.devices_notified && users_notified == o.users_notified && effective_channel_slugs == o.effective_channel_slugs && - timestamp == o.timestamp + timestamp == o.timestamp && + devices_targeted == o.devices_targeted && + devices_deactivated == o.devices_deactivated && + devices_unregistered == o.devices_unregistered end # @see the `==` method @@ -233,7 +263,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, badge, devices_updated, users_updated, devices_notified, users_notified, effective_channel_slugs, timestamp].hash + [success, badge, devices_updated, users_updated, devices_notified, users_notified, effective_channel_slugs, timestamp, devices_targeted, devices_deactivated, devices_unregistered].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/live_activity_end_response.rb b/generated/activitysmith_openapi/models/live_activity_end_response.rb index 13d41d3..ff831cf 100644 --- a/generated/activitysmith_openapi/models/live_activity_end_response.rb +++ b/generated/activitysmith_openapi/models/live_activity_end_response.rb @@ -26,6 +26,21 @@ class LiveActivityEndResponse attr_accessor :timestamp + # True when the Live Activity had already ended and the request had no effect. + attr_accessor :ignored + + attr_accessor :message + + attr_accessor :end_reason + + # True when the Live Activity was marked complete without a confirmed APNs end delivery. + attr_accessor :forced_completion + + attr_accessor :warning + + # Per-device delivery errors when some devices could not be reached. + attr_accessor :errors + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -33,7 +48,13 @@ def self.attribute_map :'activity_id' => :'activity_id', :'devices_queued' => :'devices_queued', :'devices_notified' => :'devices_notified', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'ignored' => :'ignored', + :'message' => :'message', + :'end_reason' => :'end_reason', + :'forced_completion' => :'forced_completion', + :'warning' => :'warning', + :'errors' => :'errors' } end @@ -49,13 +70,20 @@ def self.openapi_types :'activity_id' => :'String', :'devices_queued' => :'Integer', :'devices_notified' => :'Integer', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'ignored' => :'Boolean', + :'message' => :'String', + :'end_reason' => :'String', + :'forced_completion' => :'Boolean', + :'warning' => :'String', + :'errors' => :'Array' } end # List of attributes with nullable: true def self.openapi_nullable Set.new([ + :'end_reason', ]) end @@ -99,6 +127,32 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'ignored') + self.ignored = attributes[:'ignored'] + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end + + if attributes.key?(:'end_reason') + self.end_reason = attributes[:'end_reason'] + end + + if attributes.key?(:'forced_completion') + self.forced_completion = attributes[:'forced_completion'] + end + + if attributes.key?(:'warning') + self.warning = attributes[:'warning'] + end + + if attributes.key?(:'errors') + if (value = attributes[:'errors']).is_a?(Array) + self.errors = value + end + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -140,7 +194,13 @@ def ==(o) activity_id == o.activity_id && devices_queued == o.devices_queued && devices_notified == o.devices_notified && - timestamp == o.timestamp + timestamp == o.timestamp && + ignored == o.ignored && + message == o.message && + end_reason == o.end_reason && + forced_completion == o.forced_completion && + warning == o.warning && + errors == o.errors end # @see the `==` method @@ -152,7 +212,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, activity_id, devices_queued, devices_notified, timestamp].hash + [success, activity_id, devices_queued, devices_notified, timestamp, ignored, message, end_reason, forced_completion, warning, errors].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/live_activity_start_response.rb b/generated/activitysmith_openapi/models/live_activity_start_response.rb index d16624c..d299038 100644 --- a/generated/activitysmith_openapi/models/live_activity_start_response.rb +++ b/generated/activitysmith_openapi/models/live_activity_start_response.rb @@ -31,6 +31,14 @@ class LiveActivityStartResponse attr_accessor :timestamp + # Present when starting this Live Activity ended an older one to stay within the device limit. + attr_accessor :ended_activity_id + + attr_accessor :message + + # Per-device delivery errors when some devices could not be reached. + attr_accessor :errors + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -40,7 +48,10 @@ def self.attribute_map :'activity_id' => :'activity_id', :'effective_channel_slugs' => :'effective_channel_slugs', :'tags' => :'tags', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'ended_activity_id' => :'ended_activity_id', + :'message' => :'message', + :'errors' => :'errors' } end @@ -58,7 +69,10 @@ def self.openapi_types :'activity_id' => :'String', :'effective_channel_slugs' => :'Array', :'tags' => :'Array', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'ended_activity_id' => :'String', + :'message' => :'String', + :'errors' => :'Array' } end @@ -120,6 +134,20 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'ended_activity_id') + self.ended_activity_id = attributes[:'ended_activity_id'] + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end + + if attributes.key?(:'errors') + if (value = attributes[:'errors']).is_a?(Array) + self.errors = value + end + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -163,7 +191,10 @@ def ==(o) activity_id == o.activity_id && effective_channel_slugs == o.effective_channel_slugs && tags == o.tags && - timestamp == o.timestamp + timestamp == o.timestamp && + ended_activity_id == o.ended_activity_id && + message == o.message && + errors == o.errors end # @see the `==` method @@ -175,7 +206,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, devices_notified, users_notified, activity_id, effective_channel_slugs, tags, timestamp].hash + [success, devices_notified, users_notified, activity_id, effective_channel_slugs, tags, timestamp, ended_activity_id, message, errors].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/live_activity_stream_delete_response.rb b/generated/activitysmith_openapi/models/live_activity_stream_delete_response.rb index f21f246..04e6525 100644 --- a/generated/activitysmith_openapi/models/live_activity_stream_delete_response.rb +++ b/generated/activitysmith_openapi/models/live_activity_stream_delete_response.rb @@ -30,6 +30,18 @@ class LiveActivityStreamDeleteResponse attr_accessor :timestamp + # True when the stream was already ended and the request had no effect. + attr_accessor :ignored + + attr_accessor :message + + attr_accessor :forced_completion + + attr_accessor :warning + + # Per-device delivery errors when some devices could not be reached. + attr_accessor :errors + class EnumAttributeValidator attr_reader :datatype attr_reader :allowable_values @@ -61,7 +73,12 @@ def self.attribute_map :'activity_id' => :'activity_id', :'devices_queued' => :'devices_queued', :'devices_notified' => :'devices_notified', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'ignored' => :'ignored', + :'message' => :'message', + :'forced_completion' => :'forced_completion', + :'warning' => :'warning', + :'errors' => :'errors' } end @@ -79,7 +96,12 @@ def self.openapi_types :'activity_id' => :'String', :'devices_queued' => :'Integer', :'devices_notified' => :'Integer', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'ignored' => :'Boolean', + :'message' => :'String', + :'forced_completion' => :'Boolean', + :'warning' => :'String', + :'errors' => :'Array' } end @@ -140,6 +162,28 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'ignored') + self.ignored = attributes[:'ignored'] + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end + + if attributes.key?(:'forced_completion') + self.forced_completion = attributes[:'forced_completion'] + end + + if attributes.key?(:'warning') + self.warning = attributes[:'warning'] + end + + if attributes.key?(:'errors') + if (value = attributes[:'errors']).is_a?(Array) + self.errors = value + end + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -200,7 +244,12 @@ def ==(o) activity_id == o.activity_id && devices_queued == o.devices_queued && devices_notified == o.devices_notified && - timestamp == o.timestamp + timestamp == o.timestamp && + ignored == o.ignored && + message == o.message && + forced_completion == o.forced_completion && + warning == o.warning && + errors == o.errors end # @see the `==` method @@ -212,7 +261,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, operation, stream_key, activity_id, devices_queued, devices_notified, timestamp].hash + [success, operation, stream_key, activity_id, devices_queued, devices_notified, timestamp, ignored, message, forced_completion, warning, errors].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/live_activity_stream_put_response.rb b/generated/activitysmith_openapi/models/live_activity_stream_put_response.rb index a0a2cd4..73e5c60 100644 --- a/generated/activitysmith_openapi/models/live_activity_stream_put_response.rb +++ b/generated/activitysmith_openapi/models/live_activity_stream_put_response.rb @@ -37,8 +37,21 @@ class LiveActivityStreamPutResponse # Optional tags to organize and filter notification history. attr_accessor :tags + # Present on `updated` responses when the current Live Activity has received more than 12 updates and has averaged more than one update every 2 minutes since it started. The update is still sent, but iOS may throttle Live Activities that update this often. + attr_accessor :warning + attr_accessor :timestamp + # True when the request had no effect. + attr_accessor :ignored + + attr_accessor :remote_push_sent + + attr_accessor :message + + # Per-device delivery errors when some devices could not be reached. + attr_accessor :errors + class EnumAttributeValidator attr_reader :datatype attr_reader :allowable_values @@ -74,7 +87,12 @@ def self.attribute_map :'users_notified' => :'users_notified', :'effective_channel_slugs' => :'effective_channel_slugs', :'tags' => :'tags', - :'timestamp' => :'timestamp' + :'warning' => :'warning', + :'timestamp' => :'timestamp', + :'ignored' => :'ignored', + :'remote_push_sent' => :'remote_push_sent', + :'message' => :'message', + :'errors' => :'errors' } end @@ -96,7 +114,12 @@ def self.openapi_types :'users_notified' => :'Integer', :'effective_channel_slugs' => :'Array', :'tags' => :'Array', - :'timestamp' => :'Time' + :'warning' => :'String', + :'timestamp' => :'Time', + :'ignored' => :'Boolean', + :'remote_push_sent' => :'Boolean', + :'message' => :'String', + :'errors' => :'Array' } end @@ -172,11 +195,33 @@ def initialize(attributes = {}) end end + if attributes.key?(:'warning') + self.warning = attributes[:'warning'] + end + if attributes.key?(:'timestamp') self.timestamp = attributes[:'timestamp'] else self.timestamp = nil end + + if attributes.key?(:'ignored') + self.ignored = attributes[:'ignored'] + end + + if attributes.key?(:'remote_push_sent') + self.remote_push_sent = attributes[:'remote_push_sent'] + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end + + if attributes.key?(:'errors') + if (value = attributes[:'errors']).is_a?(Array) + self.errors = value + end + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -241,7 +286,12 @@ def ==(o) users_notified == o.users_notified && effective_channel_slugs == o.effective_channel_slugs && tags == o.tags && - timestamp == o.timestamp + warning == o.warning && + timestamp == o.timestamp && + ignored == o.ignored && + remote_push_sent == o.remote_push_sent && + message == o.message && + errors == o.errors end # @see the `==` method @@ -253,7 +303,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, operation, stream_key, activity_id, previous_activity_id, devices_notified, devices_queued, users_notified, effective_channel_slugs, tags, timestamp].hash + [success, operation, stream_key, activity_id, previous_activity_id, devices_notified, devices_queued, users_notified, effective_channel_slugs, tags, warning, timestamp, ignored, remote_push_sent, message, errors].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/live_activity_update_response.rb b/generated/activitysmith_openapi/models/live_activity_update_response.rb index a3d6303..387be84 100644 --- a/generated/activitysmith_openapi/models/live_activity_update_response.rb +++ b/generated/activitysmith_openapi/models/live_activity_update_response.rb @@ -26,6 +26,23 @@ class LiveActivityUpdateResponse attr_accessor :timestamp + attr_accessor :users_notified + + attr_accessor :effective_channel_slugs + + # Optional tags to organize and filter notification history. + attr_accessor :tags + + # Present when the update started a new Live Activity for a managed stream. + attr_accessor :operation + + attr_accessor :stream_key + + attr_accessor :previous_activity_id + + # Per-device delivery errors when some devices could not be reached. + attr_accessor :errors + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { @@ -33,7 +50,14 @@ def self.attribute_map :'activity_id' => :'activity_id', :'devices_queued' => :'devices_queued', :'devices_notified' => :'devices_notified', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'users_notified' => :'users_notified', + :'effective_channel_slugs' => :'effective_channel_slugs', + :'tags' => :'tags', + :'operation' => :'operation', + :'stream_key' => :'stream_key', + :'previous_activity_id' => :'previous_activity_id', + :'errors' => :'errors' } end @@ -49,7 +73,14 @@ def self.openapi_types :'activity_id' => :'String', :'devices_queued' => :'Integer', :'devices_notified' => :'Integer', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'users_notified' => :'Integer', + :'effective_channel_slugs' => :'Array', + :'tags' => :'Array', + :'operation' => :'String', + :'stream_key' => :'String', + :'previous_activity_id' => :'String', + :'errors' => :'Array' } end @@ -99,6 +130,40 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'users_notified') + self.users_notified = attributes[:'users_notified'] + end + + if attributes.key?(:'effective_channel_slugs') + if (value = attributes[:'effective_channel_slugs']).is_a?(Array) + self.effective_channel_slugs = value + end + end + + if attributes.key?(:'tags') + if (value = attributes[:'tags']).is_a?(Array) + self.tags = value + end + end + + if attributes.key?(:'operation') + self.operation = attributes[:'operation'] + end + + if attributes.key?(:'stream_key') + self.stream_key = attributes[:'stream_key'] + end + + if attributes.key?(:'previous_activity_id') + self.previous_activity_id = attributes[:'previous_activity_id'] + end + + if attributes.key?(:'errors') + if (value = attributes[:'errors']).is_a?(Array) + self.errors = value + end + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -140,7 +205,14 @@ def ==(o) activity_id == o.activity_id && devices_queued == o.devices_queued && devices_notified == o.devices_notified && - timestamp == o.timestamp + timestamp == o.timestamp && + users_notified == o.users_notified && + effective_channel_slugs == o.effective_channel_slugs && + tags == o.tags && + operation == o.operation && + stream_key == o.stream_key && + previous_activity_id == o.previous_activity_id && + errors == o.errors end # @see the `==` method @@ -152,7 +224,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, activity_id, devices_queued, devices_notified, timestamp].hash + [success, activity_id, devices_queued, devices_notified, timestamp, users_notified, effective_channel_slugs, tags, operation, stream_key, previous_activity_id, errors].hash end # Builds the object from hash diff --git a/generated/activitysmith_openapi/models/push_notification_replace_request.rb b/generated/activitysmith_openapi/models/push_notification_replace_request.rb new file mode 100644 index 0000000..cffc6bf --- /dev/null +++ b/generated/activitysmith_openapi/models/push_notification_replace_request.rb @@ -0,0 +1,434 @@ +=begin +#ActivitySmith API + +#Send push notifications and Live Activities to your own devices via a single API key. + +The version of the OpenAPI document: 1.0.0 + +Generated by: https://openapi-generator.tech +Generator version: 7.7.0 + +=end + +require 'date' +require 'time' + +module OpenapiClient + # Replacement content. title, subtitle, message, redirection, media, icon, actions, and payload fully replace the original values. Omit metadata or tags to keep the stored values; send {} or [] to clear them. + class PushNotificationReplaceRequest + # Additional information shown in notification and Live Activity details in ActivitySmith. Not displayed in the Push Notification or Live Activity on the device. Values must be strings, finite numbers, or booleans. At most 50 entries and 16 KB of serialized UTF-8 JSON. Omit on updates to preserve existing Metadata; send {} to clear it. + attr_accessor :metadata + + attr_accessor :title + + attr_accessor :message + + attr_accessor :subtitle + + # Optional HTTPS image URL without credentials for a custom notification icon. If the image cannot be loaded, the app icon is used. iOS may omit subtitle when displaying a custom icon. + attr_accessor :icon + + # Optional HTTPS URL for an image, audio file, or video that users can preview or play when they expand the notification. If `redirection` is omitted, tapping the notification opens this URL. Cannot be combined with `actions`. + attr_accessor :media + + # Optional HTTP, HTTPS, Shortcuts, or installed app URL opened when the user taps the notification body. Custom schemes such as spotify:// and spotify:track:123 require iOS 1.13.4 build 2 or later and an installed handler; no web fallback is provided. Internal and executable schemes are blocked. Overrides the default tap target from media. + attr_accessor :redirection + + # Optional interactive actions shown when users expand the notification. Cannot be combined with `media`. + attr_accessor :actions + + attr_accessor :payload + + attr_accessor :badge + + # Optional tags to organize and filter notification history. + attr_accessor :tags + + # Attribute mapping from ruby-style variable name to JSON key. + def self.attribute_map + { + :'metadata' => :'metadata', + :'title' => :'title', + :'message' => :'message', + :'subtitle' => :'subtitle', + :'icon' => :'icon', + :'media' => :'media', + :'redirection' => :'redirection', + :'actions' => :'actions', + :'payload' => :'payload', + :'badge' => :'badge', + :'tags' => :'tags' + } + end + + # Returns all the JSON keys this model knows about + def self.acceptable_attributes + attribute_map.values + end + + # Attribute type mapping. + def self.openapi_types + { + :'metadata' => :'Hash', + :'title' => :'String', + :'message' => :'String', + :'subtitle' => :'String', + :'icon' => :'String', + :'media' => :'String', + :'redirection' => :'String', + :'actions' => :'Array', + :'payload' => :'Object', + :'badge' => :'Integer', + :'tags' => :'Array' + } + end + + # List of attributes with nullable: true + def self.openapi_nullable + Set.new([ + ]) + end + + # Initializes the object + # @param [Hash] attributes Model attributes in the form of hash + def initialize(attributes = {}) + if (!attributes.is_a?(Hash)) + fail ArgumentError, "The input argument (attributes) must be a hash in `OpenapiClient::PushNotificationReplaceRequest` initialize method" + end + + # check to see if the attribute exists and convert string to symbol for hash key + attributes = attributes.each_with_object({}) { |(k, v), h| + if (!self.class.attribute_map.key?(k.to_sym)) + fail ArgumentError, "`#{k}` is not a valid attribute in `OpenapiClient::PushNotificationReplaceRequest`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect + end + h[k.to_sym] = v + } + + if attributes.key?(:'metadata') + if (value = attributes[:'metadata']).is_a?(Hash) + self.metadata = value + end + end + + if attributes.key?(:'title') + self.title = attributes[:'title'] + else + self.title = nil + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end + + if attributes.key?(:'subtitle') + self.subtitle = attributes[:'subtitle'] + end + + if attributes.key?(:'icon') + self.icon = attributes[:'icon'] + end + + if attributes.key?(:'media') + self.media = attributes[:'media'] + end + + if attributes.key?(:'redirection') + self.redirection = attributes[:'redirection'] + end + + if attributes.key?(:'actions') + if (value = attributes[:'actions']).is_a?(Array) + self.actions = value + end + end + + if attributes.key?(:'payload') + self.payload = attributes[:'payload'] + end + + if attributes.key?(:'badge') + self.badge = attributes[:'badge'] + end + + if attributes.key?(:'tags') + if (value = attributes[:'tags']).is_a?(Array) + self.tags = value + end + end + end + + # Show invalid properties with the reasons. Usually used together with valid? + # @return Array for valid properties with the reasons + def list_invalid_properties + warn '[DEPRECATED] the `list_invalid_properties` method is obsolete' + invalid_properties = Array.new + if !@metadata.nil? && @metadata.length > 50 + invalid_properties.push('invalid value for "metadata", number of items must be less than or equal to 50.') + end + + if @title.nil? + invalid_properties.push('invalid value for "title", title cannot be nil.') + end + + pattern = Regexp.new(/^https:\/\//) + if !@icon.nil? && @icon !~ pattern + invalid_properties.push("invalid value for \"icon\", must conform to the pattern #{pattern}.") + end + + pattern = Regexp.new(/^https:\/\//) + if !@media.nil? && @media !~ pattern + invalid_properties.push("invalid value for \"media\", must conform to the pattern #{pattern}.") + end + + if !@redirection.nil? && @redirection.to_s.length > 2048 + invalid_properties.push('invalid value for "redirection", the character length must be smaller than or equal to 2048.') + end + + pattern = Regexp.new(/^[A-Za-z][A-Za-z0-9+.-]*:/) + if !@redirection.nil? && @redirection !~ pattern + invalid_properties.push("invalid value for \"redirection\", must conform to the pattern #{pattern}.") + end + + if !@actions.nil? && @actions.length > 4 + invalid_properties.push('invalid value for "actions", number of items must be less than or equal to 4.') + end + + invalid_properties + end + + # Check to see if the all the properties in the model are valid + # @return true if the model is valid + def valid? + warn '[DEPRECATED] the `valid?` method is obsolete' + return false if !@metadata.nil? && @metadata.length > 50 + return false if @title.nil? + return false if !@icon.nil? && @icon !~ Regexp.new(/^https:\/\//) + return false if !@media.nil? && @media !~ Regexp.new(/^https:\/\//) + return false if !@redirection.nil? && @redirection.to_s.length > 2048 + return false if !@redirection.nil? && @redirection !~ Regexp.new(/^[A-Za-z][A-Za-z0-9+.-]*:/) + return false if !@actions.nil? && @actions.length > 4 + true + end + + # Custom attribute writer method with validation + # @param [Object] metadata Value to be assigned + def metadata=(metadata) + if metadata.nil? + fail ArgumentError, 'metadata cannot be nil' + end + + if metadata.length > 50 + fail ArgumentError, 'invalid value for "metadata", number of items must be less than or equal to 50.' + end + + @metadata = metadata + end + + # Custom attribute writer method with validation + # @param [Object] icon Value to be assigned + def icon=(icon) + if icon.nil? + fail ArgumentError, 'icon cannot be nil' + end + + pattern = Regexp.new(/^https:\/\//) + if icon !~ pattern + fail ArgumentError, "invalid value for \"icon\", must conform to the pattern #{pattern}." + end + + @icon = icon + end + + # Custom attribute writer method with validation + # @param [Object] media Value to be assigned + def media=(media) + if media.nil? + fail ArgumentError, 'media cannot be nil' + end + + pattern = Regexp.new(/^https:\/\//) + if media !~ pattern + fail ArgumentError, "invalid value for \"media\", must conform to the pattern #{pattern}." + end + + @media = media + end + + # Custom attribute writer method with validation + # @param [Object] redirection Value to be assigned + def redirection=(redirection) + if redirection.nil? + fail ArgumentError, 'redirection cannot be nil' + end + + if redirection.to_s.length > 2048 + fail ArgumentError, 'invalid value for "redirection", the character length must be smaller than or equal to 2048.' + end + + pattern = Regexp.new(/^[A-Za-z][A-Za-z0-9+.-]*:/) + if redirection !~ pattern + fail ArgumentError, "invalid value for \"redirection\", must conform to the pattern #{pattern}." + end + + @redirection = redirection + end + + # Custom attribute writer method with validation + # @param [Object] actions Value to be assigned + def actions=(actions) + if actions.nil? + fail ArgumentError, 'actions cannot be nil' + end + + if actions.length > 4 + fail ArgumentError, 'invalid value for "actions", number of items must be less than or equal to 4.' + end + + @actions = actions + end + + # Checks equality by comparing each attribute. + # @param [Object] Object to be compared + def ==(o) + return true if self.equal?(o) + self.class == o.class && + metadata == o.metadata && + title == o.title && + message == o.message && + subtitle == o.subtitle && + icon == o.icon && + media == o.media && + redirection == o.redirection && + actions == o.actions && + payload == o.payload && + badge == o.badge && + tags == o.tags + end + + # @see the `==` method + # @param [Object] Object to be compared + def eql?(o) + self == o + end + + # Calculates hash code according to all attributes. + # @return [Integer] Hash code + def hash + [metadata, title, message, subtitle, icon, media, redirection, actions, payload, badge, tags].hash + end + + # Builds the object from hash + # @param [Hash] attributes Model attributes in the form of hash + # @return [Object] Returns the model itself + def self.build_from_hash(attributes) + return nil unless attributes.is_a?(Hash) + attributes = attributes.transform_keys(&:to_sym) + transformed_hash = {} + openapi_types.each_pair do |key, type| + if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil? + transformed_hash["#{key}"] = nil + elsif type =~ /\AArray<(.*)>/i + # check to ensure the input is an array given that the attribute + # is documented as an array but the input is not + if attributes[attribute_map[key]].is_a?(Array) + transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) } + end + elsif !attributes[attribute_map[key]].nil? + transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]]) + end + end + new(transformed_hash) + end + + # Deserializes the data based on type + # @param string type Data type + # @param string value Value to be deserialized + # @return [Object] Deserialized data + def self._deserialize(type, value) + case type.to_sym + when :Time + Time.parse(value) + when :Date + Date.parse(value) + when :String + value.to_s + when :Integer + value.to_i + when :Float + value.to_f + when :Boolean + if value.to_s =~ /\A(true|t|yes|y|1)\z/i + true + else + false + end + when :Object + # generic object (usually a Hash), return directly + value + when /\AArray<(?.+)>\z/ + inner_type = Regexp.last_match[:inner_type] + value.map { |v| _deserialize(inner_type, v) } + when /\AHash<(?.+?), (?.+)>\z/ + k_type = Regexp.last_match[:k_type] + v_type = Regexp.last_match[:v_type] + {}.tap do |hash| + value.each do |k, v| + hash[_deserialize(k_type, k)] = _deserialize(v_type, v) + end + end + else # model + # models (e.g. Pet) or oneOf + klass = OpenapiClient.const_get(type) + klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) + end + end + + # Returns the string representation of the object + # @return [String] String presentation of the object + def to_s + to_hash.to_s + end + + # to_body is an alias to to_hash (backward compatibility) + # @return [Hash] Returns the object in the form of hash + def to_body + to_hash + end + + # Returns the object in the form of hash + # @return [Hash] Returns the object in the form of hash + def to_hash + hash = {} + self.class.attribute_map.each_pair do |attr, param| + value = self.send(attr) + if value.nil? + is_nullable = self.class.openapi_nullable.include?(attr) + next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) + end + + hash[param] = _to_hash(value) + end + hash + end + + # Outputs non-array value in the form of hash + # For object, use to_hash. Otherwise, just return the value + # @param [Object] value Any valid value + # @return [Hash] Returns the value in the form of hash + def _to_hash(value) + if value.is_a?(Array) + value.compact.map { |v| _to_hash(v) } + elsif value.is_a?(Hash) + {}.tap do |hash| + value.each { |k, v| hash[k] = _to_hash(v) } + end + elsif value.respond_to? :to_hash + value.to_hash + else + value + end + end + + end + +end diff --git a/generated/activitysmith_openapi/models/push_notification_replace_response.rb b/generated/activitysmith_openapi/models/push_notification_replace_response.rb new file mode 100644 index 0000000..df59763 --- /dev/null +++ b/generated/activitysmith_openapi/models/push_notification_replace_response.rb @@ -0,0 +1,298 @@ +=begin +#ActivitySmith API + +#Send push notifications and Live Activities to your own devices via a single API key. + +The version of the OpenAPI document: 1.0.0 + +Generated by: https://openapi-generator.tech +Generator version: 7.7.0 + +=end + +require 'date' +require 'time' + +module OpenapiClient + # Apple APNs acceptance result for the replacement. Acceptance does not confirm device delivery or presentation. + class PushNotificationReplaceResponse + # True when APNs accepts the replacement for at least one device. + attr_accessor :success + + # ID of the replaced Push Notification. It stays the same, so you can replace it again. + attr_accessor :notification_id + + # Number of device tokens for which APNs accepted the notification, without confirming on-device delivery. + attr_accessor :devices_notified + + attr_accessor :users_notified + + attr_accessor :effective_channel_slugs + + # Optional tags to organize and filter notification history. + attr_accessor :tags + + attr_accessor :timestamp + + # Attribute mapping from ruby-style variable name to JSON key. + def self.attribute_map + { + :'success' => :'success', + :'notification_id' => :'notification_id', + :'devices_notified' => :'devices_notified', + :'users_notified' => :'users_notified', + :'effective_channel_slugs' => :'effective_channel_slugs', + :'tags' => :'tags', + :'timestamp' => :'timestamp' + } + end + + # Returns all the JSON keys this model knows about + def self.acceptable_attributes + attribute_map.values + end + + # Attribute type mapping. + def self.openapi_types + { + :'success' => :'Boolean', + :'notification_id' => :'String', + :'devices_notified' => :'Integer', + :'users_notified' => :'Integer', + :'effective_channel_slugs' => :'Array', + :'tags' => :'Array', + :'timestamp' => :'Time' + } + end + + # List of attributes with nullable: true + def self.openapi_nullable + Set.new([ + ]) + end + + # Initializes the object + # @param [Hash] attributes Model attributes in the form of hash + def initialize(attributes = {}) + if (!attributes.is_a?(Hash)) + fail ArgumentError, "The input argument (attributes) must be a hash in `OpenapiClient::PushNotificationReplaceResponse` initialize method" + end + + # check to see if the attribute exists and convert string to symbol for hash key + attributes = attributes.each_with_object({}) { |(k, v), h| + if (!self.class.attribute_map.key?(k.to_sym)) + fail ArgumentError, "`#{k}` is not a valid attribute in `OpenapiClient::PushNotificationReplaceResponse`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect + end + h[k.to_sym] = v + } + + if attributes.key?(:'success') + self.success = attributes[:'success'] + else + self.success = nil + end + + if attributes.key?(:'notification_id') + self.notification_id = attributes[:'notification_id'] + else + self.notification_id = nil + end + + if attributes.key?(:'devices_notified') + self.devices_notified = attributes[:'devices_notified'] + end + + if attributes.key?(:'users_notified') + self.users_notified = attributes[:'users_notified'] + end + + if attributes.key?(:'effective_channel_slugs') + if (value = attributes[:'effective_channel_slugs']).is_a?(Array) + self.effective_channel_slugs = value + end + end + + if attributes.key?(:'tags') + if (value = attributes[:'tags']).is_a?(Array) + self.tags = value + end + end + + if attributes.key?(:'timestamp') + self.timestamp = attributes[:'timestamp'] + else + self.timestamp = nil + end + end + + # Show invalid properties with the reasons. Usually used together with valid? + # @return Array for valid properties with the reasons + def list_invalid_properties + warn '[DEPRECATED] the `list_invalid_properties` method is obsolete' + invalid_properties = Array.new + if @success.nil? + invalid_properties.push('invalid value for "success", success cannot be nil.') + end + + if @notification_id.nil? + invalid_properties.push('invalid value for "notification_id", notification_id cannot be nil.') + end + + if @timestamp.nil? + invalid_properties.push('invalid value for "timestamp", timestamp cannot be nil.') + end + + invalid_properties + end + + # Check to see if the all the properties in the model are valid + # @return true if the model is valid + def valid? + warn '[DEPRECATED] the `valid?` method is obsolete' + return false if @success.nil? + return false if @notification_id.nil? + return false if @timestamp.nil? + true + end + + # Checks equality by comparing each attribute. + # @param [Object] Object to be compared + def ==(o) + return true if self.equal?(o) + self.class == o.class && + success == o.success && + notification_id == o.notification_id && + devices_notified == o.devices_notified && + users_notified == o.users_notified && + effective_channel_slugs == o.effective_channel_slugs && + tags == o.tags && + timestamp == o.timestamp + end + + # @see the `==` method + # @param [Object] Object to be compared + def eql?(o) + self == o + end + + # Calculates hash code according to all attributes. + # @return [Integer] Hash code + def hash + [success, notification_id, devices_notified, users_notified, effective_channel_slugs, tags, timestamp].hash + end + + # Builds the object from hash + # @param [Hash] attributes Model attributes in the form of hash + # @return [Object] Returns the model itself + def self.build_from_hash(attributes) + return nil unless attributes.is_a?(Hash) + attributes = attributes.transform_keys(&:to_sym) + transformed_hash = {} + openapi_types.each_pair do |key, type| + if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil? + transformed_hash["#{key}"] = nil + elsif type =~ /\AArray<(.*)>/i + # check to ensure the input is an array given that the attribute + # is documented as an array but the input is not + if attributes[attribute_map[key]].is_a?(Array) + transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) } + end + elsif !attributes[attribute_map[key]].nil? + transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]]) + end + end + new(transformed_hash) + end + + # Deserializes the data based on type + # @param string type Data type + # @param string value Value to be deserialized + # @return [Object] Deserialized data + def self._deserialize(type, value) + case type.to_sym + when :Time + Time.parse(value) + when :Date + Date.parse(value) + when :String + value.to_s + when :Integer + value.to_i + when :Float + value.to_f + when :Boolean + if value.to_s =~ /\A(true|t|yes|y|1)\z/i + true + else + false + end + when :Object + # generic object (usually a Hash), return directly + value + when /\AArray<(?.+)>\z/ + inner_type = Regexp.last_match[:inner_type] + value.map { |v| _deserialize(inner_type, v) } + when /\AHash<(?.+?), (?.+)>\z/ + k_type = Regexp.last_match[:k_type] + v_type = Regexp.last_match[:v_type] + {}.tap do |hash| + value.each do |k, v| + hash[_deserialize(k_type, k)] = _deserialize(v_type, v) + end + end + else # model + # models (e.g. Pet) or oneOf + klass = OpenapiClient.const_get(type) + klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) + end + end + + # Returns the string representation of the object + # @return [String] String presentation of the object + def to_s + to_hash.to_s + end + + # to_body is an alias to to_hash (backward compatibility) + # @return [Hash] Returns the object in the form of hash + def to_body + to_hash + end + + # Returns the object in the form of hash + # @return [Hash] Returns the object in the form of hash + def to_hash + hash = {} + self.class.attribute_map.each_pair do |attr, param| + value = self.send(attr) + if value.nil? + is_nullable = self.class.openapi_nullable.include?(attr) + next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}")) + end + + hash[param] = _to_hash(value) + end + hash + end + + # Outputs non-array value in the form of hash + # For object, use to_hash. Otherwise, just return the value + # @param [Object] value Any valid value + # @return [Hash] Returns the value in the form of hash + def _to_hash(value) + if value.is_a?(Array) + value.compact.map { |v| _to_hash(v) } + elsif value.is_a?(Hash) + {}.tap do |hash| + value.each { |k, v| hash[k] = _to_hash(v) } + end + elsif value.respond_to? :to_hash + value.to_hash + else + value + end + end + + end + +end diff --git a/generated/activitysmith_openapi/models/push_notification_response.rb b/generated/activitysmith_openapi/models/push_notification_response.rb index 33b6331..bfe91b2 100644 --- a/generated/activitysmith_openapi/models/push_notification_response.rb +++ b/generated/activitysmith_openapi/models/push_notification_response.rb @@ -19,6 +19,9 @@ class PushNotificationResponse # True when APNs accepts the notification for at least one targeted device. attr_accessor :success + # ID of this Push Notification. Pass it to `PUT /push-notification/{notification_id}` to replace the notification later. + attr_accessor :notification_id + # Number of device tokens for which APNs accepted the notification, without confirming on-device delivery. attr_accessor :devices_notified @@ -31,15 +34,35 @@ class PushNotificationResponse attr_accessor :timestamp + # Number of device tokens targeted. + attr_accessor :devices_targeted + + # Number of device tokens deactivated because APNs reported them unregistered. + attr_accessor :devices_deactivated + + # Number of targeted device tokens APNs reported as unregistered. + attr_accessor :devices_unregistered + + # True when the request was an integration connection test and no paired devices were available. + attr_accessor :credential_test + + attr_accessor :message + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { :'success' => :'success', + :'notification_id' => :'notification_id', :'devices_notified' => :'devices_notified', :'users_notified' => :'users_notified', :'effective_channel_slugs' => :'effective_channel_slugs', :'tags' => :'tags', - :'timestamp' => :'timestamp' + :'timestamp' => :'timestamp', + :'devices_targeted' => :'devices_targeted', + :'devices_deactivated' => :'devices_deactivated', + :'devices_unregistered' => :'devices_unregistered', + :'credential_test' => :'credential_test', + :'message' => :'message' } end @@ -52,11 +75,17 @@ def self.acceptable_attributes def self.openapi_types { :'success' => :'Boolean', + :'notification_id' => :'String', :'devices_notified' => :'Integer', :'users_notified' => :'Integer', :'effective_channel_slugs' => :'Array', :'tags' => :'Array', - :'timestamp' => :'Time' + :'timestamp' => :'Time', + :'devices_targeted' => :'Integer', + :'devices_deactivated' => :'Integer', + :'devices_unregistered' => :'Integer', + :'credential_test' => :'Boolean', + :'message' => :'String' } end @@ -87,6 +116,10 @@ def initialize(attributes = {}) self.success = nil end + if attributes.key?(:'notification_id') + self.notification_id = attributes[:'notification_id'] + end + if attributes.key?(:'devices_notified') self.devices_notified = attributes[:'devices_notified'] end @@ -112,6 +145,26 @@ def initialize(attributes = {}) else self.timestamp = nil end + + if attributes.key?(:'devices_targeted') + self.devices_targeted = attributes[:'devices_targeted'] + end + + if attributes.key?(:'devices_deactivated') + self.devices_deactivated = attributes[:'devices_deactivated'] + end + + if attributes.key?(:'devices_unregistered') + self.devices_unregistered = attributes[:'devices_unregistered'] + end + + if attributes.key?(:'credential_test') + self.credential_test = attributes[:'credential_test'] + end + + if attributes.key?(:'message') + self.message = attributes[:'message'] + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -145,11 +198,17 @@ def ==(o) return true if self.equal?(o) self.class == o.class && success == o.success && + notification_id == o.notification_id && devices_notified == o.devices_notified && users_notified == o.users_notified && effective_channel_slugs == o.effective_channel_slugs && tags == o.tags && - timestamp == o.timestamp + timestamp == o.timestamp && + devices_targeted == o.devices_targeted && + devices_deactivated == o.devices_deactivated && + devices_unregistered == o.devices_unregistered && + credential_test == o.credential_test && + message == o.message end # @see the `==` method @@ -161,7 +220,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [success, devices_notified, users_notified, effective_channel_slugs, tags, timestamp].hash + [success, notification_id, devices_notified, users_notified, effective_channel_slugs, tags, timestamp, devices_targeted, devices_deactivated, devices_unregistered, credential_test, message].hash end # Builds the object from hash diff --git a/generated/openapi-source.json b/generated/openapi-source.json index a320213..28e1d47 100644 --- a/generated/openapi-source.json +++ b/generated/openapi-source.json @@ -1,6 +1,6 @@ { "repository": "ActivitySmithHQ/activitysmith-backend", - "commit": "ce15d69eeb25776a3ae395e77d8b907ff7ba0709", + "commit": "dd6757c5defa3d1e6524faef789b6829184fb852", "path": "openapi.json", - "sha256": "b113d50e06d6581707d9472dda6e371b996441f58dceba87a88f79cb96508a7d" + "sha256": "24dae2d064095351d5e5cf800228e64a2d23c40b1e31a9754503081ddf31c5d8" } diff --git a/lib/activitysmith/notifications.rb b/lib/activitysmith/notifications.rb index e0b20f6..63b2d8b 100644 --- a/lib/activitysmith/notifications.rb +++ b/lib/activitysmith/notifications.rb @@ -18,6 +18,18 @@ def send_push_notification(push_notification_request = nil, opts = {}, tags: nil send(push_notification_request, opts, tags: tags, **request_fields) end + # Silently replaces a sent Push Notification, using the notification_id returned by send. + def replace(notification_id, request = nil, opts = {}, tags: nil, **request_fields) + normalized = with_tags(combine_request(request, request_fields), tags) + assert_valid_media_actions!(normalized) + @api.replace_push_notification(notification_id, normalized, opts) + end + + # Generated-style alias. + def replace_push_notification(notification_id, push_notification_replace_request = nil, opts = {}, tags: nil, **request_fields) + replace(notification_id, push_notification_replace_request, opts, tags: tags, **request_fields) + end + def method_missing(name, *args, &block) return @api.public_send(name, *args, &block) if @api.respond_to?(name) diff --git a/lib/activitysmith/version.rb b/lib/activitysmith/version.rb index de82b1a..60e0a3a 100644 --- a/lib/activitysmith/version.rb +++ b/lib/activitysmith/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ActivitySmith - VERSION = "1.13.0" + VERSION = "1.14.0" end diff --git a/test/resources_test.rb b/test/resources_test.rb index 1d814f0..6f81d48 100644 --- a/test/resources_test.rb +++ b/test/resources_test.rb @@ -20,6 +20,11 @@ def send_push_notification(request, opts = {}) { ok: true } end + def replace_push_notification(notification_id, request, opts = {}) + @calls << [:replace_push_notification, notification_id, request, opts] + { ok: true } + end + def send_push_notification_with_http_info(request, opts = {}) @calls << [:send_push_notification_with_http_info, request, opts] [:ok, 200, {}] @@ -95,6 +100,35 @@ def test_notifications_short_and_legacy_methods ) end + def test_notifications_replace_and_alias + api = FakePushApi.new + resource = ActivitySmith::Notifications.new(api) + + assert_equal({ ok: true }, resource.replace("pn1", title: "Answered from desk", tags: [])) + assert_equal({ ok: true }, resource.replace_push_notification("pn1", { title: "Again" })) + + assert_equal( + [ + [:replace_push_notification, "pn1", { title: "Answered from desk", tags: [] }, {}], + [:replace_push_notification, "pn1", { title: "Again" }, {}] + ], + api.calls + ) + end + + def test_notifications_replace_rejects_media_and_actions + resource = ActivitySmith::Notifications.new(FakePushApi.new) + error = assert_raises(ArgumentError) do + resource.replace( + "pn1", + title: "Done", + media: "https://cdn.activitysmith.com/voice_over.mp3", + actions: [{ title: "Open", type: "open_url", url: "https://example.com" }] + ) + end + assert_equal "ActivitySmith: media cannot be combined with actions", error.message + end + def test_notifications_map_channels_to_target api = FakePushApi.new resource = ActivitySmith::Notifications.new(api) diff --git a/test/support/push_options_serialization.rb b/test/support/push_options_serialization.rb index 9d4bf44..d0b82be 100644 --- a/test/support/push_options_serialization.rb +++ b/test/support/push_options_serialization.rb @@ -36,6 +36,24 @@ def test_serialized_options_for_hash_keywords_model_and_legacy end end + def test_replace_serializes_put_and_parses_response + ActivitySmith::Client.new(api_key: 'mock-only') + [:replace, :replace_push_notification].each do |method| + captured = [] + api_client = OpenapiClient::ApiClient.new + api_client.define_singleton_method(:call_api) do |http_method, path, opts = {}| + request = build_request(http_method, path, opts) + captured << [http_method, path, JSON.parse(request.options[:body])] + body = '{"success":true,"notification_id":"pn1","devices_notified":1,"future_field":true,"timestamp":"2026-10-12T00:00:00Z"}' + [deserialize(Struct.new(:body, :headers).new(body, {'Content-Type' => 'application/json'}), opts[:return_type]), 200, {}] + end + notifications = ActivitySmith::Notifications.new(OpenapiClient::PushNotificationsApi.new(api_client)) + response = notifications.public_send(method, 'pn1', {title: 'Answered from desk', tags: [], metadata: {attempts: 0, resolved: false}}) + assert_equal [:PUT, '/push-notification/pn1', {'title' => 'Answered from desk', 'tags' => [], 'metadata' => {'attempts' => 0, 'resolved' => false}}], captured.last + assert_equal 'pn1', response.notification_id + end + end + def test_invalid_level_rejected api = Object.new assert_raises(ArgumentError) { ActivitySmith::Notifications.new(api).send(title: 'Test', interruption_level: 'timeSensitive') }