workarea-core 3.4.38 → 3.4.43
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 +4 -4
- data/app/controllers/workarea/current_referrer.rb +1 -0
- data/app/controllers/workarea/impersonation.rb +2 -1
- data/app/models/workarea/metrics/user.rb +25 -0
- data/app/queries/workarea/search/admin_search.rb +4 -0
- data/app/queries/workarea/search/admin_sorting.rb +1 -1
- data/app/workers/workarea/update_email.rb +33 -0
- data/lib/workarea/changelog.rake +1 -1
- data/lib/workarea/core.rb +1 -0
- data/lib/workarea/ext/referer_parser/parser.decorator +43 -0
- data/lib/workarea/version.rb +1 -1
- data/test/lib/workarea/ext/referer_parser/parser_test.rb +20 -0
- data/test/models/workarea/metrics/user_test.rb +51 -0
- data/test/queries/workarea/search/admin_search_test.rb +10 -0
- data/test/workers/workarea/update_email_test.rb +39 -0
- metadata +6 -4
- data/app/workers/workarea/update_payment_profile_email.rb +0 -22
- data/test/workers/workarea/update_payment_profile_email_test.rb +0 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30d5b2273f510412bf81387ac4d229e05ef322219dba42166dffd16c2a30d458
|
|
4
|
+
data.tar.gz: 0163e5cd44474ad11c119debb3dd116a0637be8f514b8d920cab4e093f3f4578
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00d52ab3b83bb7057218e4b70d668a98e85b1c953f2607b15826599d75d6970fdd681eea595b1270533889f90e75be3db8a539f4a16016578acd6c285fffb4aa
|
|
7
|
+
data.tar.gz: d73e489b510f361b0a75cbd705c1731ae6bea3693fd25ed3ee76d502ff4802724ba744442bade25b99171d444c0ec0f805591650a852fe74f8f7a5bfef83d5df
|
|
@@ -50,7 +50,8 @@ module Workarea
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def current_impersonation
|
|
53
|
-
@current_impersonation
|
|
53
|
+
return @current_impersonation if defined?(@current_impersonation)
|
|
54
|
+
@current_impersonation = User.find(cookies.signed[:user_id]) rescue nil
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def touch_impersonation
|
|
@@ -123,6 +123,31 @@ module Workarea
|
|
|
123
123
|
return nil if orders.zero?
|
|
124
124
|
revenue / orders.to_f
|
|
125
125
|
end
|
|
126
|
+
|
|
127
|
+
def merge!(other)
|
|
128
|
+
# To recalculate average_order_value
|
|
129
|
+
self.orders += other.orders
|
|
130
|
+
self.revenue += other.revenue
|
|
131
|
+
|
|
132
|
+
update = {
|
|
133
|
+
'$set' => {
|
|
134
|
+
average_order_value: average_order_value,
|
|
135
|
+
updated_at: Time.current.utc
|
|
136
|
+
},
|
|
137
|
+
'$inc' => {
|
|
138
|
+
orders: other.orders,
|
|
139
|
+
revenue: other.revenue,
|
|
140
|
+
discounts: other.discounts
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
update['$min'] = { first_order_at: other.first_order_at.utc } if other.first_order_at.present?
|
|
145
|
+
update['$max'] = { last_order_at: other.last_order_at.utc } if other.last_order_at.present?
|
|
146
|
+
|
|
147
|
+
self.class.collection.update_one({ _id: id }, update, upsert: true)
|
|
148
|
+
other.delete
|
|
149
|
+
reload
|
|
150
|
+
end
|
|
126
151
|
end
|
|
127
152
|
end
|
|
128
153
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Workarea
|
|
2
|
+
class UpdateEmail
|
|
3
|
+
include Sidekiq::Worker
|
|
4
|
+
include Sidekiq::CallbacksWorker
|
|
5
|
+
|
|
6
|
+
sidekiq_options(
|
|
7
|
+
enqueue_on: { User => :update, with: -> { [id, changes] } }
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
def perform(id, changes)
|
|
11
|
+
return unless changes['email'].present? && changes['email'].first.present?
|
|
12
|
+
|
|
13
|
+
old_email, new_email = changes['email']
|
|
14
|
+
update_payment_profile(id, old_email, new_email)
|
|
15
|
+
update_metrics(old_email, new_email)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update_payment_profile(id, old_email, new_email)
|
|
19
|
+
user = User.find(id)
|
|
20
|
+
user.email = old_email # set old email so we lookup by old email value
|
|
21
|
+
|
|
22
|
+
Payment::Profile.update_email(PaymentReference.new(user), new_email)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update_metrics(old_email, new_email)
|
|
26
|
+
old_metrics = Metrics::User.find(old_email) rescue nil
|
|
27
|
+
return if old_metrics.blank?
|
|
28
|
+
|
|
29
|
+
new_metrics = Metrics::User.find_or_initialize_by(id: new_email)
|
|
30
|
+
new_metrics.merge!(old_metrics)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/workarea/changelog.rake
CHANGED
data/lib/workarea/core.rb
CHANGED
|
@@ -140,6 +140,7 @@ require 'workarea/ext/mongoid/find_ordered'
|
|
|
140
140
|
require 'workarea/ext/sprockets/ruby_processor'
|
|
141
141
|
require 'workarea/ext/jbuilder/jbuilder_append_partials'
|
|
142
142
|
require 'workarea/ext/jbuilder/jbuilder_cache'
|
|
143
|
+
require 'workarea/ext/referer_parser/parser.decorator'
|
|
143
144
|
|
|
144
145
|
if Rails.env.development?
|
|
145
146
|
require 'workarea/ext/freedom_patches/routes_reloader'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module RefererParser
|
|
2
|
+
# This code is actually in `master` branch of
|
|
3
|
+
# https://github.com/snowplow-referer-parser/ruby-referer-parser but
|
|
4
|
+
# has not yet been released. It's used to allow through android-app://
|
|
5
|
+
# URLs.
|
|
6
|
+
decorate Parser do
|
|
7
|
+
# Given a string or URI, return a hash of data
|
|
8
|
+
def parse(obj)
|
|
9
|
+
url = obj.is_a?(URI) ? obj : URI.parse(obj.to_s)
|
|
10
|
+
|
|
11
|
+
unless ['android-app', 'http', 'https'].include?(url.scheme)
|
|
12
|
+
raise InvalidUriError, "Only Android-App, HTTP, and HTTPS schemes are supported -- #{url.scheme}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
data = { known: false, uri: url.to_s }
|
|
16
|
+
|
|
17
|
+
domain, name_key = domain_and_name_key_for(url)
|
|
18
|
+
if domain && name_key
|
|
19
|
+
referer_data = @name_hash[name_key]
|
|
20
|
+
data[:known] = true
|
|
21
|
+
data[:source] = referer_data[:source]
|
|
22
|
+
data[:medium] = referer_data[:medium]
|
|
23
|
+
data[:domain] = domain
|
|
24
|
+
|
|
25
|
+
# Parse parameters if the referer uses them
|
|
26
|
+
if url.query && referer_data[:parameters]
|
|
27
|
+
query_params = CGI.parse(url.query)
|
|
28
|
+
referer_data[:parameters].each do |param|
|
|
29
|
+
# If there is a matching parameter, get the first non-blank value
|
|
30
|
+
unless (values = query_params[param]).empty?
|
|
31
|
+
data[:term] = values.reject { |v| v.strip == '' }.first
|
|
32
|
+
break if data[:term]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
data
|
|
39
|
+
rescue URI::InvalidURIError
|
|
40
|
+
raise InvalidUriError.new("Unable to parse URI, not a URI? -- #{obj.inspect}", $ERROR_INFO)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/workarea/version.rb
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module RefererParser
|
|
4
|
+
class ParserTest < Workarea::TestCase
|
|
5
|
+
def test_parse_android_app_referrers
|
|
6
|
+
referrers = [
|
|
7
|
+
'android-app://com.linkedin.android',
|
|
8
|
+
'android-app://org.telegram.plus',
|
|
9
|
+
'android-app://com.twitter.android'
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
referrers.each do |uri|
|
|
13
|
+
referrer = Parser.new.parse(uri)
|
|
14
|
+
|
|
15
|
+
refute(referrer[:known])
|
|
16
|
+
assert_equal(uri, referrer[:uri])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -74,6 +74,57 @@ module Workarea
|
|
|
74
74
|
assert_equal(50, two.revenue_percentile)
|
|
75
75
|
assert_equal(50, two.average_order_value_percentile)
|
|
76
76
|
end
|
|
77
|
+
|
|
78
|
+
def test_merging_metrics
|
|
79
|
+
freeze_time
|
|
80
|
+
|
|
81
|
+
first = User.create!(
|
|
82
|
+
first_order_at: 2.weeks.ago,
|
|
83
|
+
last_order_at: 1.day.ago,
|
|
84
|
+
orders: 2,
|
|
85
|
+
revenue: 100,
|
|
86
|
+
discounts: -10,
|
|
87
|
+
average_order_value: 50,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
first.merge!(User.new)
|
|
91
|
+
first.reload
|
|
92
|
+
assert_equal(1, Metrics::User.count)
|
|
93
|
+
assert_equal(2.weeks.ago, first.first_order_at)
|
|
94
|
+
assert_equal(1.day.ago, first.last_order_at)
|
|
95
|
+
assert_equal(2, first.orders)
|
|
96
|
+
assert_equal(100, first.revenue)
|
|
97
|
+
assert_equal(-10, first.discounts)
|
|
98
|
+
assert_equal(50, first.average_order_value)
|
|
99
|
+
|
|
100
|
+
second = User.create!(id: 'foo').tap { |u| u.merge!(first) }
|
|
101
|
+
second.reload
|
|
102
|
+
assert_equal(1, Metrics::User.count)
|
|
103
|
+
assert_equal(2.weeks.ago, second.first_order_at)
|
|
104
|
+
assert_equal(1.day.ago, second.last_order_at)
|
|
105
|
+
assert_equal(2, second.orders)
|
|
106
|
+
assert_equal(100, second.revenue)
|
|
107
|
+
assert_equal(-10, second.discounts)
|
|
108
|
+
assert_equal(50, second.average_order_value)
|
|
109
|
+
|
|
110
|
+
third = User.create!(
|
|
111
|
+
first_order_at: 3.weeks.ago,
|
|
112
|
+
last_order_at: 3.weeks.ago,
|
|
113
|
+
orders: 2,
|
|
114
|
+
revenue: 120,
|
|
115
|
+
average_order_value: 60,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
third.merge!(second)
|
|
119
|
+
third.reload
|
|
120
|
+
assert_equal(1, Metrics::User.count)
|
|
121
|
+
assert_equal(3.weeks.ago, third.first_order_at)
|
|
122
|
+
assert_equal(1.day.ago, third.last_order_at)
|
|
123
|
+
assert_equal(4, third.orders)
|
|
124
|
+
assert_equal(220, third.revenue)
|
|
125
|
+
assert_equal(-10, third.discounts)
|
|
126
|
+
assert_equal(55, third.average_order_value)
|
|
127
|
+
end
|
|
77
128
|
end
|
|
78
129
|
end
|
|
79
130
|
end
|
|
@@ -81,6 +81,16 @@ module Workarea
|
|
|
81
81
|
assert_equal(results.reverse, search.results)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def test_default_sort_by_score
|
|
85
|
+
# Unlike other admin searches (primarily indexes), we want searching to
|
|
86
|
+
# default sort by score. Testing scores directly is unreliable so just
|
|
87
|
+
# do a simple check here.
|
|
88
|
+
assert_equal(
|
|
89
|
+
[{ _score: :desc }, { updated_at: :desc }],
|
|
90
|
+
AdminSearch.new.default_admin_sort
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
def test_selected_sorting
|
|
85
95
|
results = [
|
|
86
96
|
create_product(name: 'A', variants: []),
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
module Workarea
|
|
4
|
+
class UpdateEmailTest < TestCase
|
|
5
|
+
def test_updating_payment_profile
|
|
6
|
+
user = create_user(email: 'user@workarea.com')
|
|
7
|
+
profile = Payment::Profile.lookup(PaymentReference.new(user))
|
|
8
|
+
|
|
9
|
+
UpdateEmail.new.perform(user.id.to_s, 'email' => [nil, 'user@workarea.com'])
|
|
10
|
+
assert_equal(profile.reload.email, 'user@workarea.com')
|
|
11
|
+
|
|
12
|
+
UpdateEmail.new.perform(
|
|
13
|
+
user.id.to_s,
|
|
14
|
+
'email' => ['user@workarea.com', 'test@workarea.com']
|
|
15
|
+
)
|
|
16
|
+
assert_equal(profile.reload.email, 'test@workarea.com')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_updating_metrics
|
|
20
|
+
user = create_user(email: 'user@workarea.com')
|
|
21
|
+
old_metrics = Metrics::User.find_or_initialize_by(id: 'user@workarea.com')
|
|
22
|
+
old_metrics.update!(orders: 3)
|
|
23
|
+
|
|
24
|
+
UpdateEmail.new.perform(user.id.to_s, 'email' => [nil, 'user@workarea.com'])
|
|
25
|
+
assert_equal(1, Metrics::User.count)
|
|
26
|
+
assert_equal(3, old_metrics.reload.orders)
|
|
27
|
+
|
|
28
|
+
new_metrics = Metrics::User.create!(id: 'test@workarea.com', orders: 1)
|
|
29
|
+
|
|
30
|
+
UpdateEmail.new.perform(
|
|
31
|
+
user.id.to_s,
|
|
32
|
+
'email' => ['user@workarea.com', 'test@workarea.com']
|
|
33
|
+
)
|
|
34
|
+
assert_equal(1, Metrics::User.count)
|
|
35
|
+
assert_raises(Mongoid::Errors::DocumentNotFound) { old_metrics.reload }
|
|
36
|
+
assert_equal(4, new_metrics.reload.orders)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: workarea-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.4.
|
|
4
|
+
version: 3.4.43
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ben Crouse
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-11-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -1711,7 +1711,7 @@ files:
|
|
|
1711
1711
|
- app/workers/workarea/status_reporter.rb
|
|
1712
1712
|
- app/workers/workarea/undo_release.rb
|
|
1713
1713
|
- app/workers/workarea/update_elasticsearch_settings.rb
|
|
1714
|
-
- app/workers/workarea/
|
|
1714
|
+
- app/workers/workarea/update_email.rb
|
|
1715
1715
|
- app/workers/workarea/verify_scheduled_releases.rb
|
|
1716
1716
|
- bin/rails
|
|
1717
1717
|
- config/i18n-js.yml
|
|
@@ -1873,6 +1873,7 @@ files:
|
|
|
1873
1873
|
- lib/workarea/ext/mongoid/list_field.rb
|
|
1874
1874
|
- lib/workarea/ext/mongoid/moped_bson.rb
|
|
1875
1875
|
- lib/workarea/ext/mongoid/timestamps_timeless.rb
|
|
1876
|
+
- lib/workarea/ext/referer_parser/parser.decorator
|
|
1876
1877
|
- lib/workarea/ext/sprockets/ruby_processor.rb
|
|
1877
1878
|
- lib/workarea/ext/sprockets/task.rb
|
|
1878
1879
|
- lib/workarea/geolocation.rb
|
|
@@ -2017,6 +2018,7 @@ files:
|
|
|
2017
2018
|
- test/lib/workarea/ext/mongoid/except_test.rb
|
|
2018
2019
|
- test/lib/workarea/ext/mongoid/find_ordered_test.rb
|
|
2019
2020
|
- test/lib/workarea/ext/mongoid/list_field_test.rb
|
|
2021
|
+
- test/lib/workarea/ext/referer_parser/parser_test.rb
|
|
2020
2022
|
- test/lib/workarea/geolocation_test.rb
|
|
2021
2023
|
- test/lib/workarea/lint/inconsistent_details_test.rb
|
|
2022
2024
|
- test/lib/workarea/lint/products_missing_images_test.rb
|
|
@@ -2366,7 +2368,7 @@ files:
|
|
|
2366
2368
|
- test/workers/workarea/send_refund_email_test.rb
|
|
2367
2369
|
- test/workers/workarea/status_reporter_test.rb
|
|
2368
2370
|
- test/workers/workarea/undo_release_test.rb
|
|
2369
|
-
- test/workers/workarea/
|
|
2371
|
+
- test/workers/workarea/update_email_test.rb
|
|
2370
2372
|
- test/workers/workarea/verify_scheduled_releases_test.rb
|
|
2371
2373
|
- vendor/active_shipping/.gitignore
|
|
2372
2374
|
- vendor/active_shipping/.travis.yml
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
module Workarea
|
|
2
|
-
class UpdatePaymentProfileEmail
|
|
3
|
-
include Sidekiq::Worker
|
|
4
|
-
include Sidekiq::CallbacksWorker
|
|
5
|
-
|
|
6
|
-
sidekiq_options(
|
|
7
|
-
enqueue_on: { User => :update, with: -> { [id, changes] } }
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
def perform(id, changes)
|
|
11
|
-
if changes['email'].present? && changes['email'].first.present?
|
|
12
|
-
old_email = changes['email'].first
|
|
13
|
-
new_email = changes['email'].last
|
|
14
|
-
|
|
15
|
-
user = User.find(id)
|
|
16
|
-
user.email = old_email # set old email so we lookup by old email value
|
|
17
|
-
|
|
18
|
-
Payment::Profile.update_email(PaymentReference.new(user), new_email)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
module Workarea
|
|
4
|
-
class UpdatePaymentProfileEmailTest < Workarea::TestCase
|
|
5
|
-
setup do
|
|
6
|
-
@user = create_user(email: 'user@workarea.com')
|
|
7
|
-
@profile = Payment::Profile.lookup(PaymentReference.new(@user))
|
|
8
|
-
@worker = UpdatePaymentProfileEmail.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def test_updating_payment_profile_email_address
|
|
12
|
-
@worker.perform(
|
|
13
|
-
@user.id.to_s,
|
|
14
|
-
'email' => ['user@workarea.com', 'test@workarea.com']
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
@profile.reload
|
|
18
|
-
assert_equal(@profile.email, 'test@workarea.com')
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_skipping_update_if_email_change_is_nil
|
|
22
|
-
@worker.perform(@user.id.to_s, 'email' => [nil, 'user@workarea.com'])
|
|
23
|
-
@profile.reload
|
|
24
|
-
assert_equal(@profile.email, 'user@workarea.com')
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|