omnievent 0.1.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +48 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +78 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +12 -0
- data/lib/omnievent/builder.rb +34 -0
- data/lib/omnievent/configuration.rb +58 -0
- data/lib/omnievent/event_hash.rb +290 -0
- data/lib/omnievent/key_store.rb +24 -0
- data/lib/omnievent/strategies/developer.rb +88 -0
- data/lib/omnievent/strategy.rb +190 -0
- data/lib/omnievent/utils.rb +87 -0
- data/lib/omnievent/version.rb +5 -0
- data/lib/omnievent.rb +86 -0
- data/omnievent.gemspec +37 -0
- data/sig/omnievent.rbs +4 -0
- metadata +152 -0
@@ -0,0 +1,290 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniEvent
|
4
|
+
# The EventHash is a normalized schema returned by all OmniEvent strategies.
|
5
|
+
class EventHash < OmniEvent::KeyStore
|
6
|
+
def self.subkey_class
|
7
|
+
Hashie::Mash
|
8
|
+
end
|
9
|
+
|
10
|
+
# Tells you if this is considered to be a valid EventHash.
|
11
|
+
def valid?
|
12
|
+
provider? &&
|
13
|
+
data? &&
|
14
|
+
data.valid? &&
|
15
|
+
(!metadata || metadata.valid?) &&
|
16
|
+
(!associated_data || associated_data.valid?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def regular_writer(key, value)
|
20
|
+
value = DataHash.new(value) if key.to_s == "data" && value.is_a?(::Hash) && !value.is_a?(DataHash)
|
21
|
+
value = MetadataHash.new(value) if key.to_s == "metadata" && value.is_a?(::Hash) && !value.is_a?(MetadataHash)
|
22
|
+
if key.to_s == "associated_data" && value.is_a?(::Hash) && !value.is_a?(AssociatedDataHash)
|
23
|
+
value = AssociatedDataHash.new(value)
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
# Base for data hashes
|
29
|
+
class EventHashBase < OmniEvent::KeyStore
|
30
|
+
def permitted?(keys, attribute = nil, sub_attribute = nil)
|
31
|
+
permitted = self.class.permitted_attributes
|
32
|
+
permitted = permitted[attribute] if attribute
|
33
|
+
permitted = permitted[sub_attribute] if sub_attribute
|
34
|
+
permitted = permitted.is_a?(Hash) ? permitted.keys.map(&:to_s) : permitted
|
35
|
+
(keys - permitted).empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Tells you if this is considered to be a valid hash.
|
39
|
+
def valid?
|
40
|
+
if self.class.respond_to?(:required_attributes) && !self.class.required_attributes.all? do |attribute|
|
41
|
+
value = send(attribute)
|
42
|
+
!value.nil? && !value.empty?
|
43
|
+
end
|
44
|
+
# All required attributes have values
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
# All attributes are permitted
|
49
|
+
return false unless permitted?(keys)
|
50
|
+
|
51
|
+
# All attribute values are valid
|
52
|
+
self.class.permitted_attributes.all? do |attribute|
|
53
|
+
value = send(attribute.to_s)
|
54
|
+
return true if value.to_s.empty? || send("#{attribute}_valid?")
|
55
|
+
|
56
|
+
invalid << attribute
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def invalid
|
62
|
+
@invalid ||= []
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# The event data.
|
67
|
+
class DataHash < EventHashBase
|
68
|
+
def self.subkey_class
|
69
|
+
Hashie::Mash
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.permitted_attributes
|
73
|
+
%w[
|
74
|
+
start_time
|
75
|
+
end_time
|
76
|
+
name
|
77
|
+
description
|
78
|
+
url
|
79
|
+
]
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.required_attributes
|
83
|
+
%w[
|
84
|
+
start_time
|
85
|
+
name
|
86
|
+
]
|
87
|
+
end
|
88
|
+
|
89
|
+
def start_time_valid?
|
90
|
+
OmniEvent::Utils.valid_time?(start_time)
|
91
|
+
end
|
92
|
+
|
93
|
+
def end_time_valid?
|
94
|
+
OmniEvent::Utils.valid_time?(end_time)
|
95
|
+
end
|
96
|
+
|
97
|
+
def name_valid?
|
98
|
+
OmniEvent::Utils.valid_type?(name, :string)
|
99
|
+
end
|
100
|
+
|
101
|
+
def description_valid?
|
102
|
+
OmniEvent::Utils.valid_type?(name, :string)
|
103
|
+
end
|
104
|
+
|
105
|
+
def url_valid?
|
106
|
+
OmniEvent::Utils.valid_url?(url)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# The event metadata.
|
111
|
+
class MetadataHash < EventHashBase
|
112
|
+
def self.subkey_class
|
113
|
+
Hashie::Mash
|
114
|
+
end
|
115
|
+
|
116
|
+
# The permitted MetadataHash attributes.
|
117
|
+
def self.permitted_attributes
|
118
|
+
%w[
|
119
|
+
uid
|
120
|
+
created_at
|
121
|
+
updated_at
|
122
|
+
language
|
123
|
+
status
|
124
|
+
taxonomies
|
125
|
+
]
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.permitted_statuses
|
129
|
+
%w[
|
130
|
+
draft
|
131
|
+
published
|
132
|
+
cancelled
|
133
|
+
]
|
134
|
+
end
|
135
|
+
|
136
|
+
def uid_valid?
|
137
|
+
OmniEvent::Utils.valid_uid?(uid)
|
138
|
+
end
|
139
|
+
|
140
|
+
def created_at_valid?
|
141
|
+
OmniEvent::Utils.valid_time?(created_at)
|
142
|
+
end
|
143
|
+
|
144
|
+
def updated_at_valid?
|
145
|
+
OmniEvent::Utils.valid_time?(updated_at)
|
146
|
+
end
|
147
|
+
|
148
|
+
def language_valid?
|
149
|
+
OmniEvent::Utils.valid_language_code?(language)
|
150
|
+
end
|
151
|
+
|
152
|
+
def status_valid?
|
153
|
+
self.class.permitted_statuses.include?(status)
|
154
|
+
end
|
155
|
+
|
156
|
+
def taxonomies_valid?
|
157
|
+
OmniEvent::Utils.all_valid_type?(taxonomies, :string)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# The event's associated data.
|
162
|
+
class AssociatedDataHash < EventHashBase
|
163
|
+
def self.subkey_class
|
164
|
+
Hashie::Mash
|
165
|
+
end
|
166
|
+
|
167
|
+
# The permitted MetadataHash attributes.
|
168
|
+
def self.permitted_attributes
|
169
|
+
{
|
170
|
+
location: %w[uid name address city postal_code country latitude longitude url],
|
171
|
+
virtual_location: { "uid": "", "entry_points": %w[uri type code label] },
|
172
|
+
organizer: %w[uid name email uris],
|
173
|
+
registrations: %w[uid name email status]
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.permitted_entry_point_attributes
|
178
|
+
%w[
|
179
|
+
uri
|
180
|
+
type
|
181
|
+
code
|
182
|
+
label
|
183
|
+
]
|
184
|
+
end
|
185
|
+
|
186
|
+
def location_valid?
|
187
|
+
return true unless location
|
188
|
+
return false unless location.is_a?(Hash)
|
189
|
+
return false unless permitted?(location.keys, :location)
|
190
|
+
|
191
|
+
location.all? do |key, value|
|
192
|
+
case key
|
193
|
+
when "uid"
|
194
|
+
OmniEvent::Utils.valid_uid?(value)
|
195
|
+
when "name", "address", "city", "postal_code"
|
196
|
+
OmniEvent::Utils.valid_type?(value, :string)
|
197
|
+
when "country"
|
198
|
+
OmniEvent::Utils.valid_country_code?(value)
|
199
|
+
when "latitude", "longitude"
|
200
|
+
OmniEvent::Utils.valid_coordinate?(value, key.to_sym)
|
201
|
+
when "url"
|
202
|
+
OmniEvent::Utils.valid_url?(value)
|
203
|
+
else
|
204
|
+
false
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def virtual_location_valid?
|
210
|
+
return true unless virtual_location
|
211
|
+
return false unless virtual_location.is_a?(Hash)
|
212
|
+
return true unless virtual_location["entry_points"]
|
213
|
+
|
214
|
+
return false if virtual_location["uid"] && !OmniEvent::Utils.valid_uid?(virtual_location["uid"])
|
215
|
+
|
216
|
+
virtual_location["entry_points"].all? do |entry_point|
|
217
|
+
return false unless entry_point.is_a?(Hash)
|
218
|
+
return false unless entry_point["uri"] && entry_point["type"]
|
219
|
+
return false unless permitted?(entry_point.keys, :virtual_location, :entry_points)
|
220
|
+
return false unless case entry_point["type"]
|
221
|
+
when "video"
|
222
|
+
OmniEvent::Utils.valid_url?(entry_point["uri"])
|
223
|
+
when "phone", "sip"
|
224
|
+
OmniEvent::Utils.valid_type?(entry_point["uri"], :string)
|
225
|
+
else
|
226
|
+
false
|
227
|
+
end
|
228
|
+
|
229
|
+
OmniEvent::Utils.valid_type?(entry_point["label"], :string) &&
|
230
|
+
OmniEvent::Utils.valid_type?(entry_point["code"], :string)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def organizer_valid?
|
235
|
+
return true unless organizer
|
236
|
+
return false unless organizer.is_a?(Hash)
|
237
|
+
return false unless permitted?(organizer.keys, :organizer)
|
238
|
+
|
239
|
+
organizer.all? do |key, value|
|
240
|
+
case key
|
241
|
+
when "uid"
|
242
|
+
OmniEvent::Utils.valid_uid?(value)
|
243
|
+
when "name"
|
244
|
+
OmniEvent::Utils.valid_type?(value, :string)
|
245
|
+
when "email"
|
246
|
+
OmniEvent::Utils.valid_email?(value)
|
247
|
+
when "uris"
|
248
|
+
OmniEvent::Utils.all_valid_type?(value, :string)
|
249
|
+
else
|
250
|
+
false
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.permitted_registration_statuses
|
256
|
+
%w[
|
257
|
+
confirmed
|
258
|
+
declined
|
259
|
+
tentative
|
260
|
+
]
|
261
|
+
end
|
262
|
+
|
263
|
+
def registrations_valid?
|
264
|
+
return true unless registrations
|
265
|
+
return false unless registrations.is_a?(Array)
|
266
|
+
|
267
|
+
registrations.all? do |registration|
|
268
|
+
return false unless registration.is_a?(Hash)
|
269
|
+
return false unless registration["email"] && registration["status"]
|
270
|
+
return false unless permitted?(registration.keys, :registrations)
|
271
|
+
|
272
|
+
registration.all? do |key, value|
|
273
|
+
case key
|
274
|
+
when "uid"
|
275
|
+
OmniEvent::Utils.valid_uid?(value)
|
276
|
+
when "name"
|
277
|
+
OmniEvent::Utils.valid_type?(value, :string)
|
278
|
+
when "email"
|
279
|
+
OmniEvent::Utils.valid_email?(value)
|
280
|
+
when "status"
|
281
|
+
self.class.permitted_registration_statuses.include?(value)
|
282
|
+
else
|
283
|
+
false
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hashie/mash"
|
4
|
+
|
5
|
+
module OmniEvent
|
6
|
+
# Generic helper hash that allows method access on deeply nested keys.
|
7
|
+
class KeyStore < ::Hashie::Mash
|
8
|
+
# Disables warnings on Hashie 3.5.0+ for overwritten keys
|
9
|
+
def self.override_logging
|
10
|
+
require "hashie/version"
|
11
|
+
return unless Gem::Version.new(Hashie::VERSION) >= Gem::Version.new("3.5.0")
|
12
|
+
|
13
|
+
if respond_to?(:disable_warnings)
|
14
|
+
disable_warnings
|
15
|
+
else
|
16
|
+
define_method(:log_built_in_message) { |*| }
|
17
|
+
private :log_built_in_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Disable on loading of the class
|
22
|
+
override_logging
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module OmniEvent
|
6
|
+
module Strategies
|
7
|
+
# The Developer strategy can be used for testing purposes.
|
8
|
+
#
|
9
|
+
# ## Usage
|
10
|
+
#
|
11
|
+
# All you need to do is add it in like any other strategy:
|
12
|
+
#
|
13
|
+
# @example Basic Usage
|
14
|
+
#
|
15
|
+
# OmniEvent::Builder.new do
|
16
|
+
# provider :developer
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class Developer
|
20
|
+
include OmniEvent::Strategy
|
21
|
+
|
22
|
+
option :name, "developer"
|
23
|
+
|
24
|
+
def self.raw_data
|
25
|
+
fixture = File.join(File.expand_path("../../..", __dir__), "spec", "fixtures", "list_events.json")
|
26
|
+
@raw_data ||= JSON.parse(File.open(fixture).read).to_h
|
27
|
+
end
|
28
|
+
|
29
|
+
def raw_events
|
30
|
+
self.class.raw_data["events"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def event_hash(raw_event)
|
34
|
+
event = OmniEvent::EventHash.new(
|
35
|
+
provider: name,
|
36
|
+
data: raw_event.slice(*OmniEvent::EventHash::DataHash.permitted_attributes),
|
37
|
+
metadata: raw_event.slice(*OmniEvent::EventHash::MetadataHash.permitted_attributes),
|
38
|
+
associated_data: {
|
39
|
+
location: map_location(raw_event["location"]),
|
40
|
+
virtual_location: raw_event["virtual_location"]
|
41
|
+
}
|
42
|
+
)
|
43
|
+
|
44
|
+
event.data.start_time = format_time(event.data.start_time)
|
45
|
+
event.data.end_time = format_time(event.data.end_time)
|
46
|
+
event.metadata.created_at = format_time(event.metadata.created_at)
|
47
|
+
event.metadata.updated_at = format_time(event.metadata.updated_at)
|
48
|
+
event.metadata.uid = raw_event["id"]
|
49
|
+
|
50
|
+
event
|
51
|
+
end
|
52
|
+
|
53
|
+
def authorized?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def location_key_map
|
60
|
+
{
|
61
|
+
countryCode: "country",
|
62
|
+
latitude: "latitude",
|
63
|
+
longitude: "longitude",
|
64
|
+
address1: "address",
|
65
|
+
address2: "address",
|
66
|
+
address3: "address",
|
67
|
+
city: "city",
|
68
|
+
postalCode: "postal_code"
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def map_location(raw_location)
|
73
|
+
raw_location.each_with_object({}) do |(raw_key, raw_value), result|
|
74
|
+
next unless location_key_map[raw_key.to_sym]
|
75
|
+
|
76
|
+
key = location_key_map[raw_key.to_sym]
|
77
|
+
value = result[key]
|
78
|
+
if value && key == "address"
|
79
|
+
value += " #{raw_value}"
|
80
|
+
else
|
81
|
+
value = raw_value
|
82
|
+
end
|
83
|
+
result[key] = value
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniEvent
|
4
|
+
# The Strategy is the base unit of OmniEvent's ability to handle
|
5
|
+
# multiple event providers. It's substantially based on OmniAuth::Strategy.
|
6
|
+
module Strategy
|
7
|
+
class NotImplementedError < NotImplementedError; end
|
8
|
+
class Options < OmniEvent::KeyStore; end
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
OmniEvent.strategies << base
|
12
|
+
base.extend ClassMethods
|
13
|
+
base.class_eval do
|
14
|
+
option :uid_delimiter, "-"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Class methods for Strategy
|
19
|
+
module ClassMethods
|
20
|
+
# Default options for all strategies which can be overriden at the class-level
|
21
|
+
# for each strategy.
|
22
|
+
def default_options
|
23
|
+
@default_options ||= begin
|
24
|
+
d_opts = OmniEvent::Strategy::Options.new
|
25
|
+
d_opts.merge!(superclass.default_options) if superclass.respond_to?(:default_options)
|
26
|
+
d_opts
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# This allows for more declarative subclassing of strategies by allowing
|
31
|
+
# default options to be set using a simple configure call.
|
32
|
+
#
|
33
|
+
# @param options [Hash] If supplied, these will be the default options
|
34
|
+
# (deep-merged into the superclass's default options).
|
35
|
+
# @yield [Options] The options Mash that allows you to set your defaults as you'd like.
|
36
|
+
#
|
37
|
+
# @example Using a yield to configure the default options.
|
38
|
+
#
|
39
|
+
# class MyStrategy
|
40
|
+
# include OmniEvent::Strategy
|
41
|
+
#
|
42
|
+
# configure do |c|
|
43
|
+
# c.foo = 'bar'
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @example Using a hash to configure the default options.
|
48
|
+
#
|
49
|
+
# class MyStrategy
|
50
|
+
# include OmniEvent::Strategy
|
51
|
+
# configure foo: 'bar'
|
52
|
+
# end
|
53
|
+
def configure(options = nil)
|
54
|
+
if block_given?
|
55
|
+
yield default_options
|
56
|
+
else
|
57
|
+
default_options.deep_merge!(options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Directly declare a default option for your class. This is a useful from
|
62
|
+
# a documentation perspective as it provides a simple line-by-line analysis
|
63
|
+
# of the kinds of options your strategy provides by default.
|
64
|
+
#
|
65
|
+
# @param name [Symbol] The key of the default option in your configuration hash.
|
66
|
+
# @param value [Object] The value your object defaults to. Nil if not provided.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
#
|
70
|
+
# class MyStrategy
|
71
|
+
# include OmniEvent::Strategy
|
72
|
+
#
|
73
|
+
# option :foo, 'bar'
|
74
|
+
# option
|
75
|
+
# end
|
76
|
+
def option(name, value = nil)
|
77
|
+
default_options[name] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sets (and retrieves) option key names for initializer arguments to be
|
81
|
+
# recorded as. This takes care of 90% of the use cases for overriding
|
82
|
+
# the initializer in OmniEvent Strategies.
|
83
|
+
def args(args = nil)
|
84
|
+
if args
|
85
|
+
@args = Array(args)
|
86
|
+
return
|
87
|
+
end
|
88
|
+
existing = superclass.respond_to?(:args) ? superclass.args : []
|
89
|
+
(instance_variable_defined?(:@args) && @args) || existing
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
attr_reader :options
|
94
|
+
|
95
|
+
# Initializes the strategy. An `options` hash is automatically
|
96
|
+
# created from the last argument if it is a hash.
|
97
|
+
#
|
98
|
+
# @overload new(options = {})
|
99
|
+
# If nothing but a hash is supplied, initialized with the supplied options
|
100
|
+
# overriding the strategy's default options via a deep merge.
|
101
|
+
# @overload new(*args, options = {})
|
102
|
+
# If the strategy has supplied custom arguments that it accepts, they may
|
103
|
+
# will be passed through and set to the appropriate values.
|
104
|
+
#
|
105
|
+
# @yield [Options] Yields options to block for further configuration.
|
106
|
+
def initialize(*args, &block) # rubocop:disable Lint/UnusedMethodArgument
|
107
|
+
@options = self.class.default_options.dup
|
108
|
+
|
109
|
+
options.deep_merge!(args.pop) if args.last.is_a?(Hash)
|
110
|
+
options[:name] ||= self.class.to_s.split("::").last.downcase
|
111
|
+
|
112
|
+
self.class.args.each do |arg|
|
113
|
+
break if args.empty?
|
114
|
+
|
115
|
+
options[arg] = args.shift
|
116
|
+
end
|
117
|
+
|
118
|
+
# Make sure that all of the args have been dealt with, otherwise error out.
|
119
|
+
|
120
|
+
yield options if block_given?
|
121
|
+
|
122
|
+
validate_options
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate_options
|
126
|
+
# rubocop:disable Style/GuardClause
|
127
|
+
if options[:from_time] && !options[:from_time].respond_to?(:strftime)
|
128
|
+
raise ArgumentError, "from_time must be a valid ruby time object"
|
129
|
+
end
|
130
|
+
if options[:to_time] && !options[:to_time].respond_to?(:strftime)
|
131
|
+
raise ArgumentError, "to_time must be a valid ruby time object"
|
132
|
+
end
|
133
|
+
# rubocop:enable Style/GuardClause
|
134
|
+
end
|
135
|
+
|
136
|
+
def request(method, opts)
|
137
|
+
options.deep_merge!(opts)
|
138
|
+
|
139
|
+
authorize
|
140
|
+
return unless authorized?
|
141
|
+
|
142
|
+
send(method)
|
143
|
+
end
|
144
|
+
|
145
|
+
def authorize; end
|
146
|
+
|
147
|
+
def authorized?
|
148
|
+
raise NotImplementedError
|
149
|
+
end
|
150
|
+
|
151
|
+
def raw_events
|
152
|
+
raise NotImplementedError
|
153
|
+
end
|
154
|
+
|
155
|
+
def event_hash
|
156
|
+
raise NotImplementedError
|
157
|
+
end
|
158
|
+
|
159
|
+
def list_events
|
160
|
+
raw_events.each_with_object([]) do |raw_event, result|
|
161
|
+
event = event_hash(raw_event)
|
162
|
+
|
163
|
+
next unless event.valid?
|
164
|
+
next if options.from_time && Time.parse(event.data.start_time).utc < options.from_time.utc
|
165
|
+
next if options.to_time && Time.parse(event.data.start_time).utc > options.to_time.utc
|
166
|
+
|
167
|
+
result << event
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Direct access to the OmniEvent logger, automatically prefixed
|
172
|
+
# with this strategy's name.
|
173
|
+
#
|
174
|
+
# @example
|
175
|
+
# log :warn, 'This is a warning.'
|
176
|
+
def log(level, message)
|
177
|
+
OmniEvent.logger.send(level, "(#{name}) #{message}")
|
178
|
+
end
|
179
|
+
|
180
|
+
def name
|
181
|
+
options[:name]
|
182
|
+
end
|
183
|
+
|
184
|
+
def format_time(time)
|
185
|
+
return nil if time.nil? || !time.respond_to?(:to_s)
|
186
|
+
|
187
|
+
OmniEvent::Utils.convert_time_to_iso8601(time.to_s)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "tzinfo"
|
5
|
+
require "iso-639"
|
6
|
+
require "time"
|
7
|
+
|
8
|
+
module OmniEvent
|
9
|
+
# Utility methods
|
10
|
+
module Utils
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def camelize(word, first_letter_in_uppercase = true)
|
14
|
+
return OmniEvent.config.camelizations[word.to_s] if OmniEvent.config.camelizations[word.to_s]
|
15
|
+
|
16
|
+
if first_letter_in_uppercase
|
17
|
+
word.to_s.gsub(%r{/(.?)}) do
|
18
|
+
"::#{Regexp.last_match[1].upcase}"
|
19
|
+
end.gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
|
20
|
+
else
|
21
|
+
camelize(word).tap { |w| w[0] = w[0].downcase }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_time?(value)
|
26
|
+
!!Time.iso8601(value)
|
27
|
+
rescue ArgumentError
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_language_code?(value)
|
32
|
+
!!ISO_639.find_by_code(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid_country_code?(value)
|
36
|
+
!!TZInfo::Country.all_codes.include?(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_coordinate?(value, type)
|
40
|
+
case type
|
41
|
+
when :latitude
|
42
|
+
/^-?([1-8]?\d(?:\.\d{1,})?|90(?:\.0{1,6})?)$/ =~ value
|
43
|
+
when :longitude
|
44
|
+
/^-?((?:1[0-7]|[1-9])?\d(?:\.\d{1,})?|180(?:\.0{1,})?)$/ =~ value
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def valid_email?(value)
|
51
|
+
URI::MailTo::EMAIL_REGEXP =~ value
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid_url?(value)
|
55
|
+
(URI.parse value).is_a? URI::HTTP
|
56
|
+
rescue URI::InvalidURIError
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def valid_type?(value, type)
|
61
|
+
case type
|
62
|
+
when :boolean
|
63
|
+
[true, false].include? value
|
64
|
+
when :string
|
65
|
+
value.is_a?(String)
|
66
|
+
when :array
|
67
|
+
value.is_a?(Array)
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def valid_uid?(value)
|
74
|
+
value.is_a?(String)
|
75
|
+
end
|
76
|
+
|
77
|
+
def all_valid_type?(array, type)
|
78
|
+
valid_type?(array, :array) && array.all? { |t| valid_type?(t, type) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def convert_time_to_iso8601(value)
|
82
|
+
Time.parse(value).iso8601
|
83
|
+
rescue ArgumentError
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|