rpush 4.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +254 -162
  3. data/README.md +57 -16
  4. data/lib/generators/rpush_migration_generator.rb +2 -0
  5. data/lib/generators/templates/rpush.rb +4 -0
  6. data/lib/generators/templates/rpush_4_1_1_updates.rb +9 -0
  7. data/lib/generators/templates/rpush_4_2_0_updates.rb +10 -0
  8. data/lib/rpush/apns_feedback.rb +1 -0
  9. data/lib/rpush/cli.rb +9 -22
  10. data/lib/rpush/client/active_model.rb +1 -1
  11. data/lib/rpush/client/active_model/apns/notification.rb +9 -1
  12. data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
  13. data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
  14. data/lib/rpush/client/active_model/gcm/notification.rb +4 -3
  15. data/lib/rpush/client/active_model/wns/notification.rb +8 -0
  16. data/lib/rpush/client/active_record.rb +1 -0
  17. data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
  18. data/lib/rpush/client/active_record/apns/notification.rb +1 -29
  19. data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
  20. data/lib/rpush/client/active_record/app.rb +1 -1
  21. data/lib/rpush/client/active_record/notification.rb +1 -1
  22. data/lib/rpush/client/redis/apns2/notification.rb +1 -0
  23. data/lib/rpush/client/redis/app.rb +2 -1
  24. data/lib/rpush/client/redis/notification.rb +2 -1
  25. data/lib/rpush/client/redis/pushy/notification.rb +0 -1
  26. data/lib/rpush/configuration.rb +2 -1
  27. data/lib/rpush/daemon.rb +2 -2
  28. data/lib/rpush/daemon/apns/feedback_receiver.rb +2 -1
  29. data/lib/rpush/daemon/apns2/delivery.rb +6 -1
  30. data/lib/rpush/daemon/apnsp8/delivery.rb +7 -2
  31. data/lib/rpush/daemon/app_runner.rb +1 -1
  32. data/lib/rpush/daemon/batch.rb +12 -5
  33. data/lib/rpush/daemon/delivery.rb +1 -2
  34. data/lib/rpush/daemon/dispatcher/apns_http2.rb +4 -2
  35. data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +2 -1
  36. data/lib/rpush/daemon/signal_handler.rb +1 -1
  37. data/lib/rpush/daemon/store/active_record.rb +1 -1
  38. data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
  39. data/lib/rpush/daemon/store/redis.rb +1 -1
  40. data/lib/rpush/daemon/wns/badge_request.rb +8 -3
  41. data/lib/rpush/daemon/wns/raw_request.rb +9 -2
  42. data/lib/rpush/daemon/wns/toast_request.rb +6 -2
  43. data/lib/rpush/logger.rb +1 -0
  44. data/lib/rpush/version.rb +2 -2
  45. data/spec/.rubocop.yml +1 -1
  46. data/spec/functional/apns2_spec.rb +85 -0
  47. data/spec/functional/gcm_priority_spec.rb +40 -0
  48. data/spec/support/active_record_setup.rb +5 -1
  49. data/spec/support/simplecov_helper.rb +1 -1
  50. data/spec/unit/apns_feedback_spec.rb +17 -6
  51. data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
  52. data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
  53. data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
  54. data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
  55. data/spec/unit/client/active_record/apns/notification_spec.rb +29 -288
  56. data/spec/unit/client/active_record/apns2/app_spec.rb +4 -0
  57. data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
  58. data/spec/unit/client/active_record/app_spec.rb +1 -26
  59. data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
  60. data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -83
  61. data/spec/unit/client/active_record/notification_spec.rb +10 -11
  62. data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
  63. data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
  64. data/spec/unit/client/active_record/shared/app.rb +14 -0
  65. data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
  66. data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
  67. data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
  68. data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
  69. data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
  70. data/spec/unit/client/redis/adm/app_spec.rb +5 -0
  71. data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
  72. data/spec/unit/client/redis/apns/app_spec.rb +5 -0
  73. data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
  74. data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
  75. data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
  76. data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
  77. data/spec/unit/client/redis/app_spec.rb +5 -0
  78. data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
  79. data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
  80. data/spec/unit/client/redis/notification_spec.rb +5 -0
  81. data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
  82. data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
  83. data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
  84. data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
  85. data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
  86. data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
  87. data/spec/unit/client/shared/adm/app.rb +51 -0
  88. data/spec/unit/client/shared/adm/notification.rb +39 -0
  89. data/spec/unit/client/shared/apns/app.rb +29 -0
  90. data/spec/unit/client/shared/apns/feedback.rb +9 -0
  91. data/spec/unit/client/shared/apns/notification.rb +262 -0
  92. data/spec/unit/client/shared/app.rb +17 -0
  93. data/spec/unit/client/shared/gcm/app.rb +4 -0
  94. data/spec/unit/client/shared/gcm/notification.rb +77 -0
  95. data/spec/unit/client/shared/notification.rb +10 -0
  96. data/spec/unit/client/shared/pushy/app.rb +17 -0
  97. data/spec/unit/client/shared/pushy/notification.rb +55 -0
  98. data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
  99. data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
  100. data/spec/unit/client/shared/wpns/app.rb +4 -0
  101. data/spec/unit/client/shared/wpns/notification.rb +18 -0
  102. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +19 -1
  103. data/spec/unit/daemon/batch_spec.rb +50 -2
  104. data/spec/unit/daemon/delivery_spec.rb +10 -0
  105. data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
  106. data/spec/unit/daemon/shared/store.rb +312 -0
  107. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
  108. data/spec/unit/daemon/store/active_record_spec.rb +7 -295
  109. data/spec/unit/daemon/store/redis_spec.rb +4 -293
  110. data/spec/unit/daemon/wns/post_request_spec.rb +64 -0
  111. data/spec/unit_spec_helper.rb +3 -0
  112. metadata +114 -14
  113. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
data/README.md CHANGED
@@ -21,7 +21,7 @@ Rpush aims to be the *de facto* gem for sending push notifications in Ruby. Its
21
21
 
22
22
  #### Feature Highlights
23
23
 
24
- * Use [**ActiveRecord**](https://github.com/rpush/rpush/wiki/Using-ActiveRecord) or [**Redis**](https://github.com/rpush/rpush/wiki/Using-Redis) for storage. **Note:** Redis support for Rails 5.2 is not yet working if you're using Modis, see [this issue](https://github.com/ileitch/modis/issues/13).
24
+ * Use [**ActiveRecord**](https://github.com/rpush/rpush/wiki/Using-ActiveRecord) or [**Redis**](https://github.com/rpush/rpush/wiki/Using-Redis) for storage.
25
25
  * Plugins for [**Bugsnag**](https://github.com/rpush/rpush-plugin-bugsnag),
26
26
  [**Sentry**](https://github.com/rpush/rpush-plugin-sentry), [**StatsD**](https://github.com/rpush/rpush-plugin-statsd) or [write your own](https://github.com/rpush/rpush/wiki/Writing-a-Plugin).
27
27
  * Seamless integration with your projects, including **Rails**.
@@ -52,56 +52,97 @@ $ bundle exec rpush init
52
52
 
53
53
  #### Apple Push Notification Service
54
54
 
55
+ There is a choice of two modes (and one legacy mode) using certificates or using tokens:
55
56
 
56
- If this is your first time using the APNs, you will need to generate SSL certificates. See [Generating Certificates](https://github.com/rpush/rpush/wiki/Generating-Certificates) for instructions.
57
+ * `Rpush::Apns2` This requires an annually renewable certificate. see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns
58
+ * `Rpush::Apnsp8` This uses encrypted tokens and requires an encryption key id and encryption key (provide as a p8 file). (see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns)
59
+ * `Rpush::Apns` There is also the original APNS (the original version using certificates with a binary underlying protocol over TCP directly rather than over Http/2).
60
+ Apple have [announced](https://developer.apple.com/news/?id=11042019a) that this is not supported after November 2020.
61
+
62
+ If this is your first time using the APNs, you will need to generate either SSL certificates (for Apns2 or Apns) or an Encryption Key (p8) and an Encryption Key ID (for Apnsp8). See [Generating Certificates](https://github.com/rpush/rpush/wiki/Generating-Certificates) for instructions.
63
+
64
+ ##### Apnsp8
65
+
66
+ To use the p8 APNs Api:
57
67
 
58
68
  ```ruby
59
- app = Rpush::Apns::App.new
69
+ app = Rpush::Apnsp8::App.new
60
70
  app.name = "ios_app"
61
- app.certificate = File.read("/path/to/sandbox.pem")
71
+ app.apn_key = File.read("/path/to/sandbox.p8")
62
72
  app.environment = "development" # APNs environment.
63
- app.password = "certificate password"
73
+ app.apn_key_id = "APN KEY ID" # This is the Encryption Key ID provided by apple
74
+ app.team_id = "TEAM ID" # the team id - e.g. ABCDE12345
75
+ app.bundle_id = "BUNDLE ID" # the unique bundle id of the app, like com.example.appname
64
76
  app.connections = 1
65
77
  app.save!
66
78
  ```
67
79
 
68
80
  ```ruby
69
81
  n = Rpush::Apns::Notification.new
70
- n.app = Rpush::Apns::App.find_by_name("ios_app")
82
+ n.app = Rpush::Apnsp8::App.find_by_name("ios_app")
71
83
  n.device_token = "..." # hex string
72
84
  n.alert = "hi mom!"
73
85
  n.data = { foo: :bar }
74
86
  n.save!
75
87
  ```
76
88
 
77
- The `url_args` attribute is available for Safari Push Notifications.
89
+ ##### Apns2
78
90
 
79
- You should also implement the [ssl_certificate_will_expire](https://github.com/rpush/rpush/wiki/Reflection-API) reflection to monitor when your certificate is due to expire.
91
+ (NB this uses the same protocol as Apnsp8, but authenticates with a certificate rather than tokens)
92
+
93
+ ```ruby
94
+ app = Rpush::Apns2::App.new
95
+ app.name = "ios_app"
96
+ app.certificate = File.read("/path/to/sandbox.pem")
97
+ app.environment = "development"
98
+ app.password = "certificate password"
99
+ app.connections = 1
100
+ app.save!
101
+ ```
80
102
 
81
- To use the newer APNs Api replace `Rpush::Apns::App` with `Rpush::Apns2::App`.
103
+ ```ruby
104
+ n = Rpush::Apns2::Notification.new
105
+ n.app = Rpush::Apns2::App.find_by_name("ios_app")
106
+ n.device_token = "..." # hex string
107
+ n.alert = "hi mom!"
108
+ n.data = {
109
+ headers: { 'apns-topic': "BUNDLE ID", # the bundle id of the app, like com.example.appname
110
+ foo: :bar }
111
+ }
112
+ n.save!
113
+ ```
82
114
 
83
- To use the p8 APNs Api replace `Rpush::Apns::App` with `Rpush::Apnsp8::App`.
115
+ You should also implement the [ssl_certificate_will_expire](https://github.com/rpush/rpush/wiki/Reflection-API) reflection to monitor when your certificate is due to expire.
116
+
117
+ ##### Apns (legacy protocol)
84
118
 
85
119
  ```ruby
86
- app = Rpush::Apnsp8::App.new
120
+ app = Rpush::Apns::App.new
87
121
  app.name = "ios_app"
88
- app.apn_key = File.read("/path/to/sandbox.p8")
122
+ app.certificate = File.read("/path/to/sandbox.pem")
89
123
  app.environment = "development" # APNs environment.
90
- app.apn_key_id = "APN KEY ID"
91
- app.team_id = "TEAM ID"
92
- app.bundle_id = "BUNDLE ID"
124
+ app.password = "certificate password"
93
125
  app.connections = 1
94
126
  app.save!
95
127
  ```
96
128
 
97
129
  ```ruby
98
130
  n = Rpush::Apns::Notification.new
99
- n.app = Rpush::Apnsp8::App.find_by_name("ios_app")
131
+ n.app = Rpush::Apns::App.find_by_name("ios_app")
100
132
  n.device_token = "..." # hex string
101
133
  n.alert = "hi mom!"
102
134
  n.data = { foo: :bar }
103
135
  n.save!
104
136
  ```
137
+
138
+ ##### Safari Push Notifications
139
+
140
+ Using one of the notifications methods above, the `url_args` attribute is available for Safari Push Notifications.
141
+
142
+ ##### Environment
143
+
144
+ The app `environment` for any Apns* option is "development" for XCode installs, and "production" for app store and TestFlight. Note that for Apns2 you can now use one (production + sandbox) certificate (you don't need a separate "sandbox" or development certificate), but if you do generate a development/sandbox certificate it can only be used for "development". With Apnsp8 tokens, you can target either "development" or "production" environments.
145
+
105
146
  #### Firebase Cloud Messaging
106
147
 
107
148
  FCM and GCM are – as of writing – compatible with each other. See also [this comment](https://github.com/rpush/rpush/issues/284#issuecomment-228330206) for further references.
@@ -51,6 +51,8 @@ class RpushMigrationGenerator < Rails::Generators::Base
51
51
  add_rpush_migration('rpush_3_3_0_updates')
52
52
  add_rpush_migration('rpush_3_3_1_updates')
53
53
  add_rpush_migration('rpush_4_1_0_updates')
54
+ add_rpush_migration('rpush_4_1_1_updates')
55
+ add_rpush_migration('rpush_4_2_0_updates')
54
56
  end
55
57
 
56
58
  protected
@@ -26,6 +26,10 @@ Rpush.configure do |config|
26
26
  # Define a custom logger.
27
27
  # config.logger = MyLogger.new
28
28
 
29
+ # By default in foreground mode logs are directed both to the logger and to stdout.
30
+ # If the logger goes to stdout, you can disable foreground logging to avoid duplication.
31
+ # config.foreground_logging = false
32
+
29
33
  # config.apns.feedback_receiver.enabled = true
30
34
  # config.apns.feedback_receiver.frequency = 60
31
35
 
@@ -0,0 +1,9 @@
1
+ class Rpush411Updates < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"] : ActiveRecord::Migration
2
+ def self.up
3
+ add_column :rpush_apps, :feedback_enabled, :boolean, default: true
4
+ end
5
+
6
+ def self.down
7
+ remove_column :rpush_apps, :feedback_enabled
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class Rpush420Updates < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"] : ActiveRecord::Migration
2
+ def self.up
3
+ add_column :rpush_notifications, :sound_is_json, :boolean, null: true, default: false
4
+ end
5
+
6
+ def self.down
7
+ remove_column :rpush_notifications, :sound_is_json
8
+ end
9
+ end
10
+
@@ -7,6 +7,7 @@ module Rpush
7
7
  # Redis stores every App type on the same namespace, hence the
8
8
  # additional filtering
9
9
  next unless app.service_name == 'apns'
10
+ next unless app.feedback_enabled
10
11
 
11
12
  receiver = Rpush::Daemon::Apns::FeedbackReceiver.new(app)
12
13
  receiver.check_for_feedback
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  require 'thor'
4
- require 'ansi/code'
4
+ require 'rainbow'
5
5
 
6
6
  module Rpush
7
7
  class CLI < Thor
@@ -14,7 +14,7 @@ module Rpush
14
14
  end
15
15
 
16
16
  class_option :config, type: :string, aliases: '-c', default: default_config_path
17
- class_option 'rails-env', type: :string, aliases: '-e', default: 'development'
17
+ class_option 'rails-env', type: :string, aliases: '-e', default: ENV.fetch('RAILS_ENV', 'development')
18
18
 
19
19
  option :foreground, type: :boolean, aliases: '-f', default: false
20
20
  option 'pid-file', type: :string, aliases: '-p'
@@ -46,37 +46,29 @@ module Rpush
46
46
  end
47
47
  end
48
48
 
49
- puts ANSI.green { '✔' }
49
+ puts Rainbow('✔').green
50
50
  end
51
51
 
52
52
  desc 'init', 'Initialize Rpush into the current directory'
53
53
  option 'active-record', type: :boolean, desc: 'Install ActiveRecord migrations'
54
54
  def init
55
55
  underscore_option_names
56
- check_ruby_version
57
56
  require 'rails/generators'
58
57
 
59
- puts "* " + ANSI.green { 'Installing config...' }
58
+ puts "* " + Rainbow('Installing config...').green
60
59
  $RPUSH_CONFIG_PATH = default_config_path # rubocop:disable Style/GlobalVars
61
60
  Rails::Generators.invoke('rpush_config')
62
61
 
63
62
  install_migrations = options['active_record']
64
63
 
65
64
  unless options.key?('active_record')
66
- has_answer = false
67
- until has_answer
68
- STDOUT.write "\n* #{ANSI.green { 'Install ActiveRecord migrations?' }} [y/n]: "
69
- STDOUT.flush
70
- answer = STDIN.gets.chomp.downcase
71
- has_answer = %w(y n).include?(answer)
72
- end
73
-
65
+ answer = ask("\n* #{Rainbow('Install ActiveRecord migrations?').green}", limited_to: %w[y n])
74
66
  install_migrations = answer == 'y'
75
67
  end
76
68
 
77
69
  Rails::Generators.invoke('rpush_migration', ['--force']) if install_migrations
78
70
 
79
- puts "\n* #{ANSI.green { 'Next steps:' }}"
71
+ puts "\n* #{Rainbow('Next steps:').green}"
80
72
  puts " - Run 'bundle exec rake db:migrate'." if install_migrations
81
73
  puts " - Review and update your configuration in #{default_config_path}."
82
74
  puts " - Create your first app, see https://github.com/rpush/rpush for examples."
@@ -111,7 +103,6 @@ module Rpush
111
103
 
112
104
  def config_setup
113
105
  underscore_option_names
114
- check_ruby_version
115
106
  configure_rpush
116
107
  end
117
108
 
@@ -126,7 +117,7 @@ module Rpush
126
117
  ENV['RAILS_ENV'] = options['rails_env']
127
118
  load 'config/environment.rb'
128
119
  Rpush.config.update(options)
129
- puts ANSI.green { '✔' }
120
+ puts Rainbow('✔').green
130
121
 
131
122
  return true
132
123
  end
@@ -136,7 +127,7 @@ module Rpush
136
127
 
137
128
  def load_standalone
138
129
  if !File.exist?(options[:config])
139
- STDERR.puts(ANSI.red { 'ERROR: ' } + "#{options[:config]} does not exist. Please run 'rpush init' to generate it or specify the --config option.")
130
+ STDERR.puts(Rainbow('ERROR: ').red + "#{options[:config]} does not exist. Please run 'rpush init' to generate it or specify the --config option.")
140
131
  exit 1
141
132
  else
142
133
  load options[:config]
@@ -152,10 +143,6 @@ module Rpush
152
143
  self.class.default_config_path
153
144
  end
154
145
 
155
- def check_ruby_version
156
- STDERR.puts(ANSI.yellow { 'WARNING: ' } + "You are using an old and unsupported version of Ruby.") if RUBY_VERSION < '2.3.0' && RUBY_ENGINE == 'ruby'
157
- end
158
-
159
146
  def underscore_option_names
160
147
  # Underscore option names so that they map directly to Configuration options.
161
148
  new_options = options.dup
@@ -175,7 +162,7 @@ module Rpush
175
162
 
176
163
  def rpush_process_pid
177
164
  if Rpush.config.pid_file.blank?
178
- STDERR.puts(ANSI.red { 'ERROR: ' } + 'config.pid_file is not set.')
165
+ STDERR.puts(Rainbow('ERROR: ').red + 'config.pid_file is not set.')
179
166
  exit 1
180
167
  end
181
168
 
@@ -4,10 +4,10 @@ require 'rpush/client/active_model/notification'
4
4
  require 'rpush/client/active_model/payload_data_size_validator'
5
5
  require 'rpush/client/active_model/registration_ids_count_validator'
6
6
 
7
- require 'rpush/client/active_model/apns/binary_notification_validator'
8
7
  require 'rpush/client/active_model/apns/device_token_format_validator'
9
8
  require 'rpush/client/active_model/apns/app'
10
9
  require 'rpush/client/active_model/apns/notification'
10
+ require 'rpush/client/active_model/apns/notification_payload_size_validator'
11
11
 
12
12
  require 'rpush/client/active_model/apns2/app'
13
13
  require 'rpush/client/active_model/apns2/notification'
@@ -7,15 +7,23 @@ module Rpush
7
7
  APNS_PRIORITY_IMMEDIATE = 10
8
8
  APNS_PRIORITY_CONSERVE_POWER = 5
9
9
  APNS_PRIORITIES = [APNS_PRIORITY_IMMEDIATE, APNS_PRIORITY_CONSERVE_POWER]
10
+ MAX_PAYLOAD_BYTESIZE = 2048
11
+
12
+ module ClassMethods
13
+ def max_payload_bytesize
14
+ MAX_PAYLOAD_BYTESIZE
15
+ end
16
+ end
10
17
 
11
18
  def self.included(base)
19
+ base.extend ClassMethods
12
20
  base.instance_eval do
13
21
  validates :device_token, presence: true
14
22
  validates :badge, numericality: true, allow_nil: true
15
23
  validates :priority, inclusion: { in: APNS_PRIORITIES }, allow_nil: true
16
24
 
17
25
  validates_with Rpush::Client::ActiveModel::Apns::DeviceTokenFormatValidator
18
- validates_with Rpush::Client::ActiveModel::Apns::BinaryNotificationValidator
26
+ validates_with Rpush::Client::ActiveModel::Apns::NotificationPayloadSizeValidator
19
27
 
20
28
  base.const_set('APNS_DEFAULT_EXPIRY', APNS_DEFAULT_EXPIRY) unless base.const_defined?('APNS_DEFAULT_EXPIRY')
21
29
  base.const_set('APNS_PRIORITY_IMMEDIATE', APNS_PRIORITY_IMMEDIATE) unless base.const_defined?('APNS_PRIORITY_IMMEDIATE')
@@ -0,0 +1,15 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveModel
4
+ module Apns
5
+ class NotificationPayloadSizeValidator < ::ActiveModel::Validator
6
+ def validate(record)
7
+ limit = record.class.max_payload_bytesize
8
+ return unless record.payload.bytesize > limit
9
+ record.errors[:base] << "APN notification cannot be larger than #{limit} bytes. Try condensing your alert and device attributes."
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,6 +3,20 @@ module Rpush
3
3
  module ActiveModel
4
4
  module Apns2
5
5
  include Rpush::Client::ActiveModel::Apns
6
+
7
+ module Notification
8
+ MAX_PAYLOAD_BYTESIZE = 4096
9
+
10
+ module ClassMethods
11
+ def max_payload_bytesize
12
+ MAX_PAYLOAD_BYTESIZE
13
+ end
14
+ end
15
+
16
+ def self.included(base)
17
+ base.extend ClassMethods
18
+ end
19
+ end
6
20
  end
7
21
  end
8
22
  end
@@ -26,16 +26,16 @@ module Rpush
26
26
  # I'm not happy about it, but this will have to do until I can take a further look.
27
27
  def priority=(priority)
28
28
  case priority
29
- when 'high'
29
+ when 'high', GCM_PRIORITY_HIGH
30
30
  super(GCM_PRIORITY_HIGH)
31
- when 'normal'
31
+ when 'normal', GCM_PRIORITY_NORMAL
32
32
  super(GCM_PRIORITY_NORMAL)
33
33
  else
34
34
  errors.add(:priority, 'must be one of either "normal" or "high"')
35
35
  end
36
36
  end
37
37
 
38
- def as_json(options = nil)
38
+ def as_json(options = nil) # rubocop:disable Metrics/PerceivedComplexity
39
39
  json = {
40
40
  'registration_ids' => registration_ids,
41
41
  'delay_while_idle' => delay_while_idle,
@@ -43,6 +43,7 @@ module Rpush
43
43
  }
44
44
  json['collapse_key'] = collapse_key if collapse_key
45
45
  json['content_available'] = content_available if content_available
46
+ json['mutable_content'] = mutable_content if mutable_content
46
47
  json['dry_run'] = dry_run if dry_run
47
48
  json['notification'] = notification if notification
48
49
  json['priority'] = priority_for_notification if priority
@@ -3,6 +3,13 @@ module Rpush
3
3
  module ActiveModel
4
4
  module Wns
5
5
  module Notification
6
+ WNS_PRIORITY_HIGH = 1
7
+ WNS_PRIORITY_MEDIUM = 2
8
+ WNS_PRIORITY_LOW = 3
9
+ WNS_PRIORITY_VERY_LOW = 4
10
+
11
+ WNS_PRIORITIES = [WNS_PRIORITY_HIGH, WNS_PRIORITY_MEDIUM, WNS_PRIORITY_LOW, WNS_PRIORITY_VERY_LOW]
12
+
6
13
  module InstanceMethods
7
14
  def alert=(value)
8
15
  return unless value
@@ -23,6 +30,7 @@ module Rpush
23
30
  validates :uri, presence: true
24
31
  validates :uri, format: { with: %r{https?://[\S]+} }
25
32
  validates :data, presence: true, unless: :skip_data_validation?
33
+ validates :priority, inclusion: { in: WNS_PRIORITIES }, allow_nil: true
26
34
  end
27
35
  end
28
36
  end
@@ -5,6 +5,7 @@ require 'rpush/client/active_model'
5
5
  require 'rpush/client/active_record/notification'
6
6
  require 'rpush/client/active_record/app'
7
7
 
8
+ require 'rpush/client/active_record/apns/active_record_serializable_notification'
8
9
  require 'rpush/client/active_record/apns/notification'
9
10
  require 'rpush/client/active_record/apns/feedback'
10
11
  require 'rpush/client/active_record/apns/app'
@@ -0,0 +1,65 @@
1
+ module Rpush
2
+ module Client
3
+ module ActiveRecord
4
+ module Apns
5
+ module ActiveRecordSerializableNotification
6
+ def alert=(alert)
7
+ if alert.is_a?(Hash)
8
+ write_attribute(:alert, multi_json_dump(alert))
9
+ self.alert_is_json = true if has_attribute?(:alert_is_json)
10
+ else
11
+ write_attribute(:alert, alert)
12
+ self.alert_is_json = false if has_attribute?(:alert_is_json)
13
+ end
14
+ end
15
+
16
+ def alert
17
+ string_or_json = read_attribute(:alert)
18
+
19
+ if has_attribute?(:alert_is_json)
20
+ if alert_is_json?
21
+ multi_json_load(string_or_json)
22
+ else
23
+ string_or_json
24
+ end
25
+ else
26
+ begin
27
+ multi_json_load(string_or_json)
28
+ rescue StandardError
29
+ string_or_json
30
+ end
31
+ end
32
+ end
33
+
34
+ def sound=(sound)
35
+ if sound.is_a?(Hash)
36
+ write_attribute(:sound, multi_json_dump(sound))
37
+ self.sound_is_json = true if has_attribute?(:sound_is_json)
38
+ else
39
+ write_attribute(:sound, sound)
40
+ self.sound_is_json = false if has_attribute?(:sound_is_json)
41
+ end
42
+ end
43
+
44
+ def sound
45
+ string_or_json = read_attribute(:sound)
46
+
47
+ if has_attribute?(:sound_is_json)
48
+ if sound_is_json?
49
+ multi_json_load(string_or_json)
50
+ else
51
+ string_or_json
52
+ end
53
+ else
54
+ begin
55
+ multi_json_load(string_or_json)
56
+ rescue StandardError
57
+ string_or_json
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end