diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9485214 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +## 1.9.0 + +### New Features + +- **New Feature: App Icon Badge Count** - Show MRR, user counts, stock prices, and more on your ActivitySmith app icon. diff --git a/README.md b/README.md index 7ca7ae7..ad2cf0e 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ See [API reference](https://activitysmith.com/docs/api-reference/introduction). - [Live Activity Action](#live-activity-action) - [Icons and Badges](#icons-and-badges) - [Live Activity Colors](#live-activity-colors) -- [Channels](#channels) - [Widgets](#widgets) +- [App Icon Badge Count](#app-icon-badge-count) +- [Channels](#channels) ## Installation @@ -535,20 +536,6 @@ Choose from these colors for the Live Activity accent, including progress bars a `lime`, `green`, `cyan`, `blue`, `purple`, `magenta`, `red`, `orange`, `yellow`, `gray` -## Channels - -Channels are used to target specific team members or devices. Can be used for both push notifications and live activities. - -```ruby -activitysmith.notifications.send( - { - title: "New subscription 💸", - message: "Customer upgraded to Pro plan", - channels: ["sales", "customer-success"] # Optional - } -) -``` - ## Widgets

@@ -571,6 +558,64 @@ String metric values work too. activitysmith.metrics.update("prod.status", "healthy") ``` +## App Icon Badge Count + +

+ ActivitySmith app icon with an App Icon Badge Count +

+ +Show the number you care about on your ActivitySmith app icon. Track MRR, a customer count, a stock price, or any other value you want to keep in view. + +Set or update the badge value. + +```ruby +activitysmith.badge_count(8333) +``` + +To clear the badge, set its value to 0. + +```ruby +activitysmith.badge_count(0) +``` + +## Channels + +Use `channels` to target specific team members or devices + +### Push Notifications + +```ruby +activitysmith.notifications.send( + { + title: "New subscription 💸", + message: "Customer upgraded to Pro plan", + channels: ["sales", "customer-success"] + } +) +``` + +### Live Activities + +```ruby +activitysmith.live_activities.start( + { + content_state: { + title: "Nightly Database Backup", + subtitle: "verify restore", + type: "progress", + percentage: 62 + }, + channels: ["sales", "customer-success"] + } +) +``` + +### App Icon Badge Count + +```ruby +activitysmith.badge_count(3, channels: ["sales", "customer-success"]) +``` + ## Error Handling ```ruby diff --git a/generated/activitysmith_openapi.rb b/generated/activitysmith_openapi.rb index 7d5aee2..9928336 100644 --- a/generated/activitysmith_openapi.rb +++ b/generated/activitysmith_openapi.rb @@ -20,6 +20,8 @@ require 'activitysmith_openapi/models/activity_metric' require 'activitysmith_openapi/models/activity_metric_value' require 'activitysmith_openapi/models/alert_payload' +require 'activitysmith_openapi/models/app_icon_badge_count_update_request' +require 'activitysmith_openapi/models/app_icon_badge_count_update_response' require 'activitysmith_openapi/models/bad_request_error' require 'activitysmith_openapi/models/channel_target' require 'activitysmith_openapi/models/content_state_end' @@ -59,6 +61,7 @@ require 'activitysmith_openapi/models/stream_content_state' # APIs +require 'activitysmith_openapi/api/app_icon_badges_api' require 'activitysmith_openapi/api/live_activities_api' require 'activitysmith_openapi/api/metrics_api' require 'activitysmith_openapi/api/push_notifications_api' diff --git a/generated/activitysmith_openapi/api/app_icon_badges_api.rb b/generated/activitysmith_openapi/api/app_icon_badges_api.rb new file mode 100644 index 0000000..0ee813e --- /dev/null +++ b/generated/activitysmith_openapi/api/app_icon_badges_api.rb @@ -0,0 +1,90 @@ +=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 'cgi' + +module OpenapiClient + class AppIconBadgesApi + attr_accessor :api_client + + def initialize(api_client = ApiClient.default) + @api_client = api_client + end + # Update App Icon Badge Count + # Updates the App Icon Badge Count on devices matched by API key scope and optional target channels. Send `badge: 0` to clear the count. Badge updates are independent of push notifications and do not create a push notification history item. + # @param app_icon_badge_count_update_request [AppIconBadgeCountUpdateRequest] + # @param [Hash] opts the optional parameters + # @return [AppIconBadgeCountUpdateResponse] + def update_app_icon_badge_count(app_icon_badge_count_update_request, opts = {}) + data, _status_code, _headers = update_app_icon_badge_count_with_http_info(app_icon_badge_count_update_request, opts) + data + end + + # Update App Icon Badge Count + # Updates the App Icon Badge Count on devices matched by API key scope and optional target channels. Send `badge: 0` to clear the count. Badge updates are independent of push notifications and do not create a push notification history item. + # @param app_icon_badge_count_update_request [AppIconBadgeCountUpdateRequest] + # @param [Hash] opts the optional parameters + # @return [Array<(AppIconBadgeCountUpdateResponse, Integer, Hash)>] AppIconBadgeCountUpdateResponse data, response status code and response headers + def update_app_icon_badge_count_with_http_info(app_icon_badge_count_update_request, opts = {}) + if @api_client.config.debugging + @api_client.config.logger.debug 'Calling API: AppIconBadgesApi.update_app_icon_badge_count ...' + end + # verify the required parameter 'app_icon_badge_count_update_request' is set + if @api_client.config.client_side_validation && app_icon_badge_count_update_request.nil? + fail ArgumentError, "Missing the required parameter 'app_icon_badge_count_update_request' when calling AppIconBadgesApi.update_app_icon_badge_count" + end + # resource path + local_var_path = '/badge' + + # 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(app_icon_badge_count_update_request) + + # return_type + return_type = opts[:debug_return_type] || 'AppIconBadgeCountUpdateResponse' + + # auth_names + auth_names = opts[:debug_auth_names] || ['apiKeyAuth'] + + new_options = opts.merge( + :operation => :"AppIconBadgesApi.update_app_icon_badge_count", + :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(:POST, local_var_path, new_options) + if @api_client.config.debugging + @api_client.config.logger.debug "API called: AppIconBadgesApi#update_app_icon_badge_count\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" + end + return data, status_code, headers + end + end +end diff --git a/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb b/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb new file mode 100644 index 0000000..090f14d --- /dev/null +++ b/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb @@ -0,0 +1,260 @@ +=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 + # App Icon Badge Count update. Send badge 0 to clear the count. + class AppIconBadgeCountUpdateRequest + # The count to show on the ActivitySmith app icon. Send 0 to clear it. + attr_accessor :badge + + attr_accessor :target + + # Attribute mapping from ruby-style variable name to JSON key. + def self.attribute_map + { + :'badge' => :'badge', + :'target' => :'target' + } + 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 + { + :'badge' => :'Integer', + :'target' => :'ChannelTarget' + } + 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::AppIconBadgeCountUpdateRequest` 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::AppIconBadgeCountUpdateRequest`. 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?(:'badge') + self.badge = attributes[:'badge'] + else + self.badge = nil + end + + if attributes.key?(:'target') + self.target = attributes[:'target'] + 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 @badge.nil? + invalid_properties.push('invalid value for "badge", badge cannot be nil.') + end + + if @badge > 2147483647 + invalid_properties.push('invalid value for "badge", must be smaller than or equal to 2147483647.') + end + + if @badge < 0 + invalid_properties.push('invalid value for "badge", must be greater than or equal to 0.') + 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 @badge.nil? + return false if @badge > 2147483647 + return false if @badge < 0 + true + end + + # Custom attribute writer method with validation + # @param [Object] badge Value to be assigned + def badge=(badge) + if badge.nil? + fail ArgumentError, 'badge cannot be nil' + end + + if badge > 2147483647 + fail ArgumentError, 'invalid value for "badge", must be smaller than or equal to 2147483647.' + end + + if badge < 0 + fail ArgumentError, 'invalid value for "badge", must be greater than or equal to 0.' + end + + @badge = badge + 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 && + badge == o.badge && + target == o.target + 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 + [badge, target].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/app_icon_badge_count_update_response.rb b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb new file mode 100644 index 0000000..9faa31c --- /dev/null +++ b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb @@ -0,0 +1,331 @@ +=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 + class AppIconBadgeCountUpdateResponse + attr_accessor :success + + attr_accessor :badge + + attr_accessor :devices_notified + + attr_accessor :users_notified + + attr_accessor :effective_channel_slugs + + attr_accessor :timestamp + + # Attribute mapping from ruby-style variable name to JSON key. + def self.attribute_map + { + :'success' => :'success', + :'badge' => :'badge', + :'devices_notified' => :'devices_notified', + :'users_notified' => :'users_notified', + :'effective_channel_slugs' => :'effective_channel_slugs', + :'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', + :'badge' => :'Integer', + :'devices_notified' => :'Integer', + :'users_notified' => :'Integer', + :'effective_channel_slugs' => :'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::AppIconBadgeCountUpdateResponse` 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::AppIconBadgeCountUpdateResponse`. 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?(:'badge') + self.badge = attributes[:'badge'] + else + self.badge = nil + end + + if attributes.key?(:'devices_notified') + self.devices_notified = attributes[:'devices_notified'] + else + self.devices_notified = nil + end + + if attributes.key?(:'users_notified') + self.users_notified = attributes[:'users_notified'] + else + self.users_notified = nil + end + + if attributes.key?(:'effective_channel_slugs') + if (value = attributes[:'effective_channel_slugs']).is_a?(Array) + self.effective_channel_slugs = value + end + else + self.effective_channel_slugs = nil + 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 @badge.nil? + invalid_properties.push('invalid value for "badge", badge cannot be nil.') + end + + if @badge > 2147483647 + invalid_properties.push('invalid value for "badge", must be smaller than or equal to 2147483647.') + end + + if @badge < 0 + invalid_properties.push('invalid value for "badge", must be greater than or equal to 0.') + end + + if @devices_notified.nil? + invalid_properties.push('invalid value for "devices_notified", devices_notified cannot be nil.') + end + + if @users_notified.nil? + invalid_properties.push('invalid value for "users_notified", users_notified cannot be nil.') + end + + if @effective_channel_slugs.nil? + invalid_properties.push('invalid value for "effective_channel_slugs", effective_channel_slugs 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 @badge.nil? + return false if @badge > 2147483647 + return false if @badge < 0 + return false if @devices_notified.nil? + return false if @users_notified.nil? + return false if @effective_channel_slugs.nil? + return false if @timestamp.nil? + true + end + + # Custom attribute writer method with validation + # @param [Object] badge Value to be assigned + def badge=(badge) + if badge.nil? + fail ArgumentError, 'badge cannot be nil' + end + + if badge > 2147483647 + fail ArgumentError, 'invalid value for "badge", must be smaller than or equal to 2147483647.' + end + + if badge < 0 + fail ArgumentError, 'invalid value for "badge", must be greater than or equal to 0.' + end + + @badge = badge + 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 && + badge == o.badge && + devices_notified == o.devices_notified && + users_notified == o.users_notified && + effective_channel_slugs == o.effective_channel_slugs && + 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, badge, devices_notified, users_notified, effective_channel_slugs, 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/live_activity_action.rb b/generated/activitysmith_openapi/models/live_activity_action.rb index 389bd32..c4f1e42 100644 --- a/generated/activitysmith_openapi/models/live_activity_action.rb +++ b/generated/activitysmith_openapi/models/live_activity_action.rb @@ -53,7 +53,7 @@ def self.openapi_types :'type' => :'LiveActivityActionType', :'url' => :'String', :'method' => :'LiveActivityWebhookMethod', - :'body' => :'Hash' + :'body' => :'Object' } end @@ -103,9 +103,7 @@ def initialize(attributes = {}) end if attributes.key?(:'body') - if (value = attributes[:'body']).is_a?(Hash) - self.body = value - end + self.body = attributes[:'body'] end end diff --git a/generated/activitysmith_openapi/models/push_notification_action.rb b/generated/activitysmith_openapi/models/push_notification_action.rb index 84ded6a..f64fe47 100644 --- a/generated/activitysmith_openapi/models/push_notification_action.rb +++ b/generated/activitysmith_openapi/models/push_notification_action.rb @@ -52,7 +52,7 @@ def self.openapi_types :'type' => :'PushNotificationActionType', :'url' => :'String', :'method' => :'PushNotificationWebhookMethod', - :'body' => :'Hash' + :'body' => :'Object' } end @@ -102,9 +102,7 @@ def initialize(attributes = {}) end if attributes.key?(:'body') - if (value = attributes[:'body']).is_a?(Hash) - self.body = value - end + self.body = attributes[:'body'] end end diff --git a/generated/activitysmith_openapi/models/push_notification_request.rb b/generated/activitysmith_openapi/models/push_notification_request.rb index 7dd3a89..effcb1b 100644 --- a/generated/activitysmith_openapi/models/push_notification_request.rb +++ b/generated/activitysmith_openapi/models/push_notification_request.rb @@ -68,7 +68,7 @@ def self.openapi_types :'media' => :'String', :'redirection' => :'String', :'actions' => :'Array', - :'payload' => :'Hash', + :'payload' => :'Object', :'badge' => :'Integer', :'sound' => :'String', :'target' => :'ChannelTarget' @@ -125,9 +125,7 @@ def initialize(attributes = {}) end if attributes.key?(:'payload') - if (value = attributes[:'payload']).is_a?(Hash) - self.payload = value - end + self.payload = attributes[:'payload'] end if attributes.key?(:'badge') diff --git a/lib/activitysmith/client.rb b/lib/activitysmith/client.rb index 0ab93bf..707b40e 100644 --- a/lib/activitysmith/client.rb +++ b/lib/activitysmith/client.rb @@ -19,6 +19,14 @@ def initialize(api_key:) @notifications = Notifications.new(OpenapiClient::PushNotificationsApi.new(api_client)) @live_activities = LiveActivities.new(OpenapiClient::LiveActivitiesApi.new(api_client)) @metrics = Metrics.new(OpenapiClient::MetricsApi.new(api_client)) + @app_icon_badges = OpenapiClient::AppIconBadgesApi.new(api_client) + end + + def badge_count(value, channels: nil) + request = { badge: value } + normalized_channels = normalize_channels(channels) + request[:target] = { channels: normalized_channels } unless normalized_channels.empty? + @app_icon_badges.update_app_icon_badge_count(request) end private @@ -44,7 +52,8 @@ def generated_client_present? "OpenapiClient::ApiClient", "OpenapiClient::PushNotificationsApi", "OpenapiClient::LiveActivitiesApi", - "OpenapiClient::MetricsApi" + "OpenapiClient::MetricsApi", + "OpenapiClient::AppIconBadgesApi" ].reject { |name| constant_defined?(name) } missing.empty? @@ -56,5 +65,10 @@ def constant_defined?(name) rescue NameError false end + + def normalize_channels(channels) + values = channels.is_a?(String) ? channels.split(",") : Array(channels) + values.map { |channel| channel.to_s.strip }.reject(&:empty?) + end end end diff --git a/lib/activitysmith/version.rb b/lib/activitysmith/version.rb index 4d79d17..6795883 100644 --- a/lib/activitysmith/version.rb +++ b/lib/activitysmith/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ActivitySmith - VERSION = "1.8.0" + VERSION = "1.9.0" end diff --git a/test/client_test.rb b/test/client_test.rb index d5847cc..155ddd0 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -44,6 +44,20 @@ def initialize(api_client) @api_client = api_client end end + + class AppIconBadgesApi + attr_reader :api_client, :calls + + def initialize(api_client) + @api_client = api_client + @calls = [] + end + + def update_app_icon_badge_count(request, opts = {}) + @calls << [request, opts] + request + end + end end class ClientTest < Minitest::Test @@ -68,6 +82,7 @@ def test_constructs_when_generated_client_is_present assert_respond_to client.live_activities, :end_stream refute_nil client.metrics assert_respond_to client.metrics, :update + assert_respond_to client, :badge_count metrics_api = client.metrics.instance_variable_get(:@api) assert_equal "ruby-v#{ActivitySmith::VERSION}", metrics_api.api_client.default_headers["X-ActivitySmith-SDK"] @@ -77,4 +92,22 @@ def test_constructs_when_generated_client_is_present raise end + + def test_badge_count_clears_and_targets_channels + client = ActivitySmith::Client.new(api_key: "test-api-key") + api = client.instance_variable_get(:@app_icon_badges) + + assert_equal({ badge: 0 }, client.badge_count(0)) + assert_equal( + { badge: 3, target: { channels: %w[sales customer-success] } }, + client.badge_count(3, channels: "sales,customer-success") + ) + assert_equal( + [ + [{ badge: 0 }, {}], + [{ badge: 3, target: { channels: %w[sales customer-success] } }, {}] + ], + api.calls + ) + end end