noticed 1.6.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +122 -147
  3. data/app/jobs/noticed/application_job.rb +9 -0
  4. data/app/jobs/noticed/event_job.rb +19 -0
  5. data/app/models/concerns/noticed/deliverable.rb +115 -0
  6. data/app/models/concerns/noticed/notification_methods.rb +17 -0
  7. data/app/models/concerns/noticed/readable.rb +62 -0
  8. data/app/models/noticed/application_record.rb +6 -0
  9. data/app/models/noticed/deliverable/deliver_by.rb +43 -0
  10. data/app/models/noticed/event.rb +15 -0
  11. data/app/models/noticed/notification.rb +16 -0
  12. data/db/migrate/20231215190233_create_noticed_tables.rb +25 -0
  13. data/lib/generators/noticed/delivery_method_generator.rb +1 -1
  14. data/lib/generators/noticed/install_generator.rb +19 -0
  15. data/lib/generators/noticed/{notification_generator.rb → notifier_generator.rb} +2 -2
  16. data/lib/generators/noticed/templates/README +5 -4
  17. data/lib/generators/noticed/templates/notifier.rb.tt +24 -0
  18. data/lib/noticed/api_client.rb +44 -0
  19. data/lib/noticed/bulk_delivery_method.rb +46 -0
  20. data/lib/noticed/bulk_delivery_methods/discord.rb +11 -0
  21. data/lib/noticed/bulk_delivery_methods/slack.rb +17 -0
  22. data/lib/noticed/bulk_delivery_methods/webhook.rb +18 -0
  23. data/lib/noticed/coder.rb +2 -0
  24. data/lib/noticed/delivery_method.rb +50 -0
  25. data/lib/noticed/delivery_methods/action_cable.rb +7 -39
  26. data/lib/noticed/delivery_methods/discord.rb +11 -0
  27. data/lib/noticed/delivery_methods/email.rb +9 -45
  28. data/lib/noticed/delivery_methods/fcm.rb +23 -64
  29. data/lib/noticed/delivery_methods/ios.rb +25 -112
  30. data/lib/noticed/delivery_methods/microsoft_teams.rb +5 -22
  31. data/lib/noticed/delivery_methods/slack.rb +6 -16
  32. data/lib/noticed/delivery_methods/test.rb +2 -12
  33. data/lib/noticed/delivery_methods/twilio_messaging.rb +37 -0
  34. data/lib/noticed/delivery_methods/vonage_sms.rb +20 -0
  35. data/lib/noticed/delivery_methods/webhook.rb +17 -0
  36. data/lib/noticed/engine.rb +1 -9
  37. data/lib/noticed/required_options.rb +21 -0
  38. data/lib/noticed/translation.rb +7 -3
  39. data/lib/noticed/version.rb +1 -1
  40. data/lib/noticed.rb +30 -15
  41. metadata +29 -40
  42. data/lib/generators/noticed/model/base_generator.rb +0 -47
  43. data/lib/generators/noticed/model/mysql_generator.rb +0 -18
  44. data/lib/generators/noticed/model/postgresql_generator.rb +0 -18
  45. data/lib/generators/noticed/model/sqlite3_generator.rb +0 -18
  46. data/lib/generators/noticed/model_generator.rb +0 -63
  47. data/lib/generators/noticed/templates/notification.rb.tt +0 -27
  48. data/lib/noticed/base.rb +0 -160
  49. data/lib/noticed/delivery_methods/base.rb +0 -95
  50. data/lib/noticed/delivery_methods/database.rb +0 -34
  51. data/lib/noticed/delivery_methods/twilio.rb +0 -51
  52. data/lib/noticed/delivery_methods/vonage.rb +0 -40
  53. data/lib/noticed/has_notifications.rb +0 -49
  54. data/lib/noticed/model.rb +0 -85
  55. data/lib/noticed/notification_channel.rb +0 -15
  56. data/lib/noticed/text_coder.rb +0 -16
  57. data/lib/rails_6_polyfills/actioncable/test_adapter.rb +0 -70
  58. data/lib/rails_6_polyfills/actioncable/test_helper.rb +0 -143
  59. data/lib/rails_6_polyfills/activejob/serializers.rb +0 -240
  60. data/lib/rails_6_polyfills/base.rb +0 -18
  61. data/lib/tasks/noticed_tasks.rake +0 -4
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "action_cable/subscription_adapter/base"
4
- require "action_cable/subscription_adapter/subscriber_map"
5
- require "action_cable/subscription_adapter/async"
6
-
7
- module ActionCable
8
- module SubscriptionAdapter
9
- # == Test adapter for Action Cable
10
- #
11
- # The test adapter should be used only in testing. Along with
12
- # <tt>ActionCable::TestHelper</tt> it makes a great tool to test your Rails application.
13
- #
14
- # To use the test adapter set +adapter+ value to +test+ in your +config/cable.yml+ file.
15
- #
16
- # NOTE: Test adapter extends the <tt>ActionCable::SubscriptionsAdapter::Async</tt> adapter,
17
- # so it could be used in system tests too.
18
- class Test < Async
19
- def broadcast(channel, payload)
20
- broadcasts(channel) << payload
21
- super
22
- end
23
-
24
- def broadcasts(channel)
25
- channels_data[channel] ||= []
26
- end
27
-
28
- def clear_messages(channel)
29
- channels_data[channel] = []
30
- end
31
-
32
- def clear
33
- @channels_data = nil
34
- end
35
-
36
- private
37
-
38
- def channels_data
39
- @channels_data ||= {}
40
- end
41
- end
42
- end
43
-
44
- # Update how broadcast_for determines the channel name so it's consistent with the Rails 6 way
45
- module Channel
46
- module Broadcasting
47
- delegate :broadcast_to, to: :class
48
- module ClassMethods
49
- def broadcast_to(model, message)
50
- ActionCable.server.broadcast(broadcasting_for(model), message)
51
- end
52
-
53
- def broadcasting_for(model)
54
- serialize_broadcasting([channel_name, model])
55
- end
56
-
57
- def serialize_broadcasting(object) # :nodoc:
58
- case # standard:disable Style/EmptyCaseCondition
59
- when object.is_a?(Array)
60
- object.map { |m| serialize_broadcasting(m) }.join(":")
61
- when object.respond_to?(:to_gid_param)
62
- object.to_gid_param
63
- else
64
- object.to_param
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,143 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionCable
4
- # Have ActionCable pick its Test SubscriptionAdapter when it's called for in cable.yml
5
- module Server
6
- class Configuration
7
- def pubsub_adapter
8
- (cable["adapter"] == "test") ? ActionCable::SubscriptionAdapter::Test : super
9
- end
10
- end
11
- end
12
-
13
- # Provides helper methods for testing Action Cable broadcasting
14
- module TestHelper
15
- def before_setup # :nodoc:
16
- server = ActionCable.server
17
- test_adapter = ActionCable::SubscriptionAdapter::Test.new(server)
18
-
19
- @old_pubsub_adapter = server.pubsub
20
-
21
- server.instance_variable_set(:@pubsub, test_adapter)
22
- super
23
- end
24
-
25
- def after_teardown # :nodoc:
26
- super
27
- ActionCable.server.instance_variable_set(:@pubsub, @old_pubsub_adapter)
28
- end
29
-
30
- # Asserts that the number of broadcasted messages to the stream matches the given number.
31
- #
32
- # def test_broadcasts
33
- # assert_broadcasts 'messages', 0
34
- # ActionCable.server.broadcast 'messages', { text: 'hello' }
35
- # assert_broadcasts 'messages', 1
36
- # ActionCable.server.broadcast 'messages', { text: 'world' }
37
- # assert_broadcasts 'messages', 2
38
- # end
39
- #
40
- # If a block is passed, that block should cause the specified number of
41
- # messages to be broadcasted.
42
- #
43
- # def test_broadcasts_again
44
- # assert_broadcasts('messages', 1) do
45
- # ActionCable.server.broadcast 'messages', { text: 'hello' }
46
- # end
47
- #
48
- # assert_broadcasts('messages', 2) do
49
- # ActionCable.server.broadcast 'messages', { text: 'hi' }
50
- # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
51
- # end
52
- # end
53
- #
54
- def assert_broadcasts(stream, number)
55
- if block_given?
56
- original_count = broadcasts_size(stream)
57
- yield
58
- new_count = broadcasts_size(stream)
59
- actual_count = new_count - original_count
60
- else
61
- actual_count = broadcasts_size(stream)
62
- end
63
-
64
- assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
65
- end
66
-
67
- # Asserts that no messages have been sent to the stream.
68
- #
69
- # def test_no_broadcasts
70
- # assert_no_broadcasts 'messages'
71
- # ActionCable.server.broadcast 'messages', { text: 'hi' }
72
- # assert_broadcasts 'messages', 1
73
- # end
74
- #
75
- # If a block is passed, that block should not cause any message to be sent.
76
- #
77
- # def test_broadcasts_again
78
- # assert_no_broadcasts 'messages' do
79
- # # No job messages should be sent from this block
80
- # end
81
- # end
82
- #
83
- # Note: This assertion is simply a shortcut for:
84
- #
85
- # assert_broadcasts 'messages', 0, &block
86
- #
87
- def assert_no_broadcasts(stream, &block)
88
- assert_broadcasts stream, 0, &block
89
- end
90
-
91
- # Asserts that the specified message has been sent to the stream.
92
- #
93
- # def test_assert_transmitted_message
94
- # ActionCable.server.broadcast 'messages', text: 'hello'
95
- # assert_broadcast_on('messages', text: 'hello')
96
- # end
97
- #
98
- # If a block is passed, that block should cause a message with the specified data to be sent.
99
- #
100
- # def test_assert_broadcast_on_again
101
- # assert_broadcast_on('messages', text: 'hello') do
102
- # ActionCable.server.broadcast 'messages', text: 'hello'
103
- # end
104
- # end
105
- #
106
- def assert_broadcast_on(stream, data)
107
- # Encode to JSON and back–we want to use this value to compare
108
- # with decoded JSON.
109
- # Comparing JSON strings doesn't work due to the order of the keys.
110
- serialized_msg =
111
- ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
112
-
113
- new_messages = broadcasts(stream)
114
- if block_given?
115
- old_messages = new_messages
116
- clear_messages(stream)
117
-
118
- yield
119
- new_messages = broadcasts(stream)
120
- clear_messages(stream)
121
-
122
- # Restore all sent messages
123
- (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
124
- end
125
-
126
- message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
127
-
128
- assert message, "No messages sent with #{data} to #{stream}"
129
- end
130
-
131
- def pubsub_adapter # :nodoc:
132
- ActionCable.server.pubsub
133
- end
134
-
135
- delegate :broadcasts, :clear_messages, to: :pubsub_adapter
136
-
137
- private
138
-
139
- def broadcasts_size(channel)
140
- broadcasts(channel).size
141
- end
142
- end
143
- end
@@ -1,240 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # First add Rails 6.0 ActiveJob Serializers support, and then the
4
- # DurationSerializer and SymbolSerializer.
5
- module ActiveJob
6
- module Arguments
7
- # :nodoc:
8
- OBJECT_SERIALIZER_KEY = "_aj_serialized"
9
-
10
- def serialize_argument(argument)
11
- case argument
12
- when *TYPE_WHITELIST
13
- argument
14
- when GlobalID::Identification
15
- convert_to_global_id_hash(argument)
16
- when Array
17
- argument.map { |arg| serialize_argument(arg) }
18
- when ActiveSupport::HashWithIndifferentAccess
19
- serialize_indifferent_hash(argument)
20
- when Hash
21
- symbol_keys = argument.each_key.grep(Symbol).map(&:to_s)
22
- result = serialize_hash(argument)
23
- result[SYMBOL_KEYS_KEY] = symbol_keys
24
- result
25
- when ->(arg) { arg.respond_to?(:permitted?) }
26
- serialize_indifferent_hash(argument.to_h)
27
- else # Add Rails 6 support for Serializers
28
- Serializers.serialize(argument)
29
- end
30
- end
31
-
32
- def deserialize_argument(argument)
33
- case argument
34
- when String
35
- argument
36
- when *TYPE_WHITELIST
37
- argument
38
- when Array
39
- argument.map { |arg| deserialize_argument(arg) }
40
- when Hash
41
- if serialized_global_id?(argument)
42
- deserialize_global_id argument
43
- elsif custom_serialized?(argument)
44
- Serializers.deserialize(argument)
45
- else
46
- deserialize_hash(argument)
47
- end
48
- else
49
- raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}"
50
- end
51
- end
52
-
53
- def custom_serialized?(hash)
54
- hash.key?(OBJECT_SERIALIZER_KEY)
55
- end
56
- end
57
-
58
- # The <tt>ActiveJob::Serializers</tt> module is used to store a list of known serializers
59
- # and to add new ones. It also has helpers to serialize/deserialize objects.
60
- module Serializers # :nodoc:
61
- # Base class for serializing and deserializing custom objects.
62
- #
63
- # Example:
64
- #
65
- # class MoneySerializer < ActiveJob::Serializers::ObjectSerializer
66
- # def serialize(money)
67
- # super("amount" => money.amount, "currency" => money.currency)
68
- # end
69
- #
70
- # def deserialize(hash)
71
- # Money.new(hash["amount"], hash["currency"])
72
- # end
73
- #
74
- # private
75
- #
76
- # def klass
77
- # Money
78
- # end
79
- # end
80
- class ObjectSerializer
81
- include Singleton
82
-
83
- class << self
84
- delegate :serialize?, :serialize, :deserialize, to: :instance
85
- end
86
-
87
- # Determines if an argument should be serialized by a serializer.
88
- def serialize?(argument)
89
- argument.is_a?(klass)
90
- end
91
-
92
- # Serializes an argument to a JSON primitive type.
93
- def serialize(hash)
94
- {Arguments::OBJECT_SERIALIZER_KEY => self.class.name}.merge!(hash)
95
- end
96
-
97
- # Deserializes an argument from a JSON primitive type.
98
- def deserialize(_argument)
99
- raise NotImplementedError
100
- end
101
-
102
- private
103
-
104
- # The class of the object that will be serialized.
105
- def klass
106
- raise NotImplementedError
107
- end
108
- end
109
-
110
- class DurationSerializer < ObjectSerializer # :nodoc:
111
- def serialize(duration)
112
- super("value" => duration.value, "parts" => Arguments.serialize(duration.parts.each_with_object({}) { |v, s| s[v.first.to_s] = v.last }))
113
- end
114
-
115
- def deserialize(hash)
116
- value = hash["value"]
117
- parts = Arguments.deserialize(hash["parts"])
118
-
119
- klass.new(value, parts)
120
- end
121
-
122
- private
123
-
124
- def klass
125
- ActiveSupport::Duration
126
- end
127
- end
128
-
129
- class SymbolSerializer < ObjectSerializer # :nodoc:
130
- def serialize(argument)
131
- super("value" => argument.to_s)
132
- end
133
-
134
- def deserialize(argument)
135
- argument["value"].to_sym
136
- end
137
-
138
- private
139
-
140
- def klass
141
- Symbol
142
- end
143
- end
144
-
145
- # -----------------------------
146
-
147
- mattr_accessor :_additional_serializers
148
- self._additional_serializers = Set.new
149
-
150
- class << self
151
- # Returns serialized representative of the passed object.
152
- # Will look up through all known serializers.
153
- # Raises <tt>ActiveJob::SerializationError</tt> if it can't find a proper serializer.
154
- def serialize(argument)
155
- serializer = serializers.detect { |s| s.serialize?(argument) }
156
- raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
157
- serializer.serialize(argument)
158
- end
159
-
160
- # Returns deserialized object.
161
- # Will look up through all known serializers.
162
- # If no serializer found will raise <tt>ArgumentError</tt>.
163
- def deserialize(argument)
164
- serializer_name = argument[Arguments::OBJECT_SERIALIZER_KEY]
165
- raise ArgumentError, "Serializer name is not present in the argument: #{argument.inspect}" unless serializer_name
166
-
167
- serializer = serializer_name.safe_constantize
168
- raise ArgumentError, "Serializer #{serializer_name} is not known" unless serializer
169
-
170
- serializer.deserialize(argument)
171
- end
172
-
173
- # Returns list of known serializers.
174
- def serializers
175
- self._additional_serializers # standard:disable Style/RedundantSelf
176
- end
177
-
178
- # Adds new serializers to a list of known serializers.
179
- def add_serializers(*new_serializers)
180
- self._additional_serializers += new_serializers.flatten
181
- end
182
- end
183
-
184
- add_serializers DurationSerializer,
185
- SymbolSerializer
186
- # The full set of 6 serializers that Rails 6.0 normally adds here -- feel free to include any others if you wish:
187
- # SymbolSerializer,
188
- # DurationSerializer, # (The one that we've added above in order to support testing)
189
- # DateTimeSerializer,
190
- # DateSerializer,
191
- # TimeWithZoneSerializer,
192
- # TimeSerializer
193
- end
194
-
195
- # Is the updated version of perform_enqueued_jobs from Rails 6.0 missing from ActionJob's TestHelper?
196
- unless TestHelper.private_instance_methods.include?(:flush_enqueued_jobs)
197
- module TestHelper
198
- def perform_enqueued_jobs(only: nil, except: nil, queue: nil)
199
- return flush_enqueued_jobs(only: only, except: except, queue: queue) unless block_given?
200
-
201
- super
202
- end
203
-
204
- private
205
-
206
- def jobs_with(jobs, only: nil, except: nil, queue: nil)
207
- validate_option(only: only, except: except)
208
-
209
- jobs.count do |job|
210
- job_class = job.fetch(:job)
211
-
212
- if only
213
- next false unless filter_as_proc(only).call(job)
214
- elsif except
215
- next false if filter_as_proc(except).call(job)
216
- end
217
-
218
- if queue
219
- next false unless queue.to_s == job.fetch(:queue, job_class.queue_name)
220
- end
221
-
222
- yield job if block_given?
223
-
224
- true
225
- end
226
- end
227
-
228
- def enqueued_jobs_with(only: nil, except: nil, queue: nil, &block)
229
- jobs_with(enqueued_jobs, only: only, except: except, queue: queue, &block)
230
- end
231
-
232
- def flush_enqueued_jobs(only: nil, except: nil, queue: nil)
233
- enqueued_jobs_with(only: only, except: except, queue: queue) do |payload|
234
- instantiate_job(payload).perform_now
235
- queue_adapter.performed_jobs << payload
236
- end
237
- end
238
- end
239
- end
240
- end
@@ -1,18 +0,0 @@
1
- # The following implements polyfills for Rails < 6.0
2
- module ActionCable
3
- # If the Rails 6.0 ActionCable::TestHelper is missing then allow it to autoload
4
- unless ActionCable.const_defined? :TestHelper
5
- autoload :TestHelper, "rails_6_polyfills/actioncable/test_helper.rb"
6
- end
7
- # If the Rails 6.0 test SubscriptionAdapter is missing then allow it to autoload
8
- unless ActionCable::SubscriptionAdapter.const_defined? :Test
9
- module SubscriptionAdapter
10
- autoload :Test, "rails_6_polyfills/actioncable/test_adapter.rb"
11
- end
12
- end
13
- end
14
-
15
- # If the Rails 6.0 ActionJob Serializers are missing then load support for them
16
- unless ActiveJob.const_defined?(:Serializers)
17
- require "rails_6_polyfills/activejob/serializers"
18
- end
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :noticed do
3
- # # Task goes here
4
- # end