workarea-core 3.5.13 → 3.5.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/workarea/impersonation.rb +2 -1
- data/app/mailers/workarea/application_mailer.rb +4 -1
- data/app/middleware/workarea/application_middleware.rb +5 -2
- data/app/models/workarea/checkout.rb +7 -7
- data/app/models/workarea/data_file/csv.rb +9 -1
- data/app/models/workarea/inquiry.rb +2 -1
- data/app/models/workarea/inventory/sku.rb +2 -2
- data/app/models/workarea/metrics/user.rb +24 -8
- data/app/models/workarea/order.rb +10 -0
- data/app/models/workarea/payment.rb +1 -6
- data/app/models/workarea/search/storefront/category_query.rb +1 -1
- data/app/queries/workarea/search/admin_search.rb +4 -0
- data/app/queries/workarea/search/admin_sorting.rb +1 -1
- data/app/services/workarea/index_release_schedule_previews.rb +37 -0
- data/app/workers/workarea/index_release_schedule_change.rb +32 -0
- data/app/workers/workarea/publish_release.rb +1 -0
- data/config/initializers/00_configuration.rb +3 -2
- data/config/locales/en.yml +2 -0
- data/lib/generators/workarea/install/install_generator.rb +13 -0
- data/lib/generators/workarea/install/templates/initializer.rb.erb +1 -13
- data/lib/tasks/cache.rake +3 -33
- data/lib/tasks/help.rake +4 -43
- data/lib/tasks/insights.rake +3 -35
- data/lib/tasks/migrate.rake +3 -96
- data/lib/tasks/search.rake +6 -68
- data/lib/tasks/services.rake +4 -54
- data/lib/workarea/configuration.rb +11 -2
- data/lib/workarea/configuration/administrable_options.rb +1 -5
- data/lib/workarea/core.rb +1 -0
- data/lib/workarea/core/engine.rb +4 -0
- data/lib/workarea/ext/jbuilder/jbuilder_cache.rb +29 -0
- data/lib/workarea/tasks/cache.rb +43 -0
- data/lib/workarea/tasks/help.rb +55 -0
- data/lib/workarea/tasks/insights.rb +47 -0
- data/lib/workarea/tasks/migrate.rb +106 -0
- data/lib/workarea/tasks/search.rb +105 -0
- data/lib/workarea/tasks/services.rb +71 -0
- data/lib/workarea/version.rb +1 -1
- data/test/generators/workarea/install_generator_test.rb +6 -2
- data/test/mailers/workarea/application_mailer_test.rb +10 -0
- data/test/models/workarea/checkout_test.rb +57 -0
- data/test/models/workarea/data_file/import_test.rb +40 -0
- data/test/models/workarea/search/storefront/category_query_test.rb +11 -0
- data/test/queries/workarea/search/admin_search_test.rb +10 -0
- data/test/services/workarea/index_release_schedule_previews_test.rb +28 -0
- data/test/workers/workarea/{reindex_release_test.rb → index_release_schedule_change_test.rb} +30 -4
- data/test/workers/workarea/publish_release_test.rb +24 -0
- data/workarea-core.gemspec +2 -2
- metadata +17 -8
- data/app/workers/workarea/reindex_release.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84d99f1dbf010e7d67b9dbc7785720bbed5cd17c22528dfe57e194dfbb660892
|
4
|
+
data.tar.gz: c5453a27cf96335ae9d35fe857ccc770a0412117579b37dc1cb84e9221cd6efe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4605fd9a72741e6cac8ab7a32d2408ba1b8f2bfb79ac875875461ab59fe660ffd5254e3b0eb69d5534222217de0ec2fc3d60351bee5e7575d93d2393fb8d9221
|
7
|
+
data.tar.gz: e2946da1f9618bc92f65ceca4281c426747f4c75d162b33e68a6fe629008507c43e07dcde39e12f871b2f0011225f40bfd5d9ecdc8d7f563586b90900f43c447
|
@@ -39,7 +39,8 @@ module Workarea
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def current_impersonation
|
42
|
-
@current_impersonation
|
42
|
+
return @current_impersonation if defined?(@current_impersonation)
|
43
|
+
@current_impersonation = User.find(session[:user_id]) rescue nil
|
43
44
|
end
|
44
45
|
|
45
46
|
def admin_browse_as_guest
|
@@ -8,7 +8,10 @@ module Workarea
|
|
8
8
|
default from: -> (*) { Workarea.config.email_from }
|
9
9
|
|
10
10
|
def default_url_options(options = {})
|
11
|
-
super
|
11
|
+
# super isn't returning the configured options, so manually merge them in
|
12
|
+
super
|
13
|
+
.merge(Rails.application.config.action_mailer.default_url_options.to_h)
|
14
|
+
.merge(host: Workarea.config.host)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module Workarea
|
2
2
|
class ApplicationMiddleware
|
3
|
+
ASSET_REGEX = /(jpe?g|png|ico|gif|bmp|webp|tif?f|css|js|svg|otf|ttf|woff|woff2)$/
|
4
|
+
|
3
5
|
def initialize(app)
|
4
6
|
@app = app
|
5
7
|
end
|
6
8
|
|
7
9
|
def call(env)
|
8
10
|
request = Rack::Request.new(env)
|
9
|
-
|
11
|
+
env['workarea.asset_request'] = request.path =~ ASSET_REGEX
|
12
|
+
return @app.call(env) if env['workarea.asset_request']
|
10
13
|
|
11
14
|
set_locale(env, request)
|
12
15
|
setup_environment(env, request)
|
@@ -25,7 +28,7 @@ module Workarea
|
|
25
28
|
env['workarea.visit'] = Visit.new(env)
|
26
29
|
env['workarea.cache_varies'] = Cache::Varies.new(env['workarea.visit']).to_s
|
27
30
|
env['rack-cache.cache_key'] = Cache::RackCacheKey
|
28
|
-
env['rack-cache.force-pass'] = env['workarea.visit'].admin?
|
31
|
+
env['rack-cache.force-pass'] = env['workarea.visit'].admin? && !env['workarea.asset_request']
|
29
32
|
end
|
30
33
|
|
31
34
|
def set_segment_request_headers(env)
|
@@ -47,11 +47,7 @@ module Workarea
|
|
47
47
|
def inventory
|
48
48
|
@inventory ||= Inventory::Transaction.from_order(
|
49
49
|
order.id,
|
50
|
-
order.
|
51
|
-
memo[item.sku] ||= 0
|
52
|
-
memo[item.sku] += item.quantity
|
53
|
-
memo
|
54
|
-
end
|
50
|
+
order.sku_quantities
|
55
51
|
)
|
56
52
|
end
|
57
53
|
|
@@ -158,10 +154,14 @@ module Workarea
|
|
158
154
|
# Used in auto completing an order for a logged in user.
|
159
155
|
#
|
160
156
|
# @param [Hash] parameters for updating
|
161
|
-
# @return [
|
157
|
+
# @return [Boolean] whether the update was successful.
|
162
158
|
#
|
163
159
|
def update(params = {})
|
164
|
-
|
160
|
+
return true if params.blank?
|
161
|
+
|
162
|
+
steps.reduce(true) do |result, step|
|
163
|
+
result &= step.new(self).update(params)
|
164
|
+
end
|
165
165
|
end
|
166
166
|
|
167
167
|
# Whether this checkout needs any further information
|
@@ -17,7 +17,15 @@ module Workarea
|
|
17
17
|
assign_attributes(root, attrs)
|
18
18
|
assign_embedded_attributes(root, attrs)
|
19
19
|
|
20
|
-
|
20
|
+
possibly_affected_models = root.embedded_children + [root]
|
21
|
+
was_successful = true
|
22
|
+
|
23
|
+
possibly_affected_models.each do |model|
|
24
|
+
meaningful_changes = model.changes.except('updated_at')
|
25
|
+
was_successful &= model.save if model.changed? && meaningful_changes.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
if was_successful || failed_new_record_ids.exclude?(id)
|
21
29
|
log(index, root)
|
22
30
|
else
|
23
31
|
operation.total += 1 # ensure line numbers remain consistent
|
@@ -142,11 +142,11 @@ module Workarea
|
|
142
142
|
end
|
143
143
|
|
144
144
|
def policy_class
|
145
|
-
"Workarea::Inventory::Policies::#{policy.
|
145
|
+
"Workarea::Inventory::Policies::#{policy.camelize}".constantize
|
146
146
|
rescue NameError
|
147
147
|
raise(
|
148
148
|
InvalidPolicy,
|
149
|
-
"Workarea::Inventory::Policies::#{policy.
|
149
|
+
"Workarea::Inventory::Policies::#{policy.camelize} must be a policy class"
|
150
150
|
)
|
151
151
|
end
|
152
152
|
|
@@ -110,14 +110,28 @@ module Workarea
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def merge!(other)
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
# To recalculate average_order_value
|
114
|
+
self.orders += other.orders
|
115
|
+
self.revenue += other.revenue
|
116
|
+
|
117
|
+
update = {
|
118
|
+
'$set' => {
|
119
|
+
average_order_value: average_order_value,
|
120
|
+
updated_at: Time.current.utc
|
121
|
+
},
|
122
|
+
'$inc' => {
|
123
|
+
orders: other.orders,
|
124
|
+
revenue: other.revenue,
|
125
|
+
discounts: other.discounts,
|
126
|
+
cancellations: other.cancellations,
|
127
|
+
refund: other.refund
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
update['$min'] = { first_order_at: other.first_order_at.utc } if other.first_order_at.present?
|
132
|
+
update['$max'] = { last_order_at: other.last_order_at.utc } if other.last_order_at.present?
|
133
|
+
|
134
|
+
self.class.collection.update_one({ _id: id }, update, upsert: true)
|
121
135
|
|
122
136
|
self.class.save_affinity(
|
123
137
|
id: id,
|
@@ -133,6 +147,8 @@ module Workarea
|
|
133
147
|
category_ids: other.purchased.category_ids,
|
134
148
|
search_ids: other.purchased.search_ids
|
135
149
|
)
|
150
|
+
|
151
|
+
reload
|
136
152
|
end
|
137
153
|
end
|
138
154
|
end
|
@@ -375,6 +375,16 @@ module Workarea
|
|
375
375
|
)
|
376
376
|
end
|
377
377
|
|
378
|
+
# A hash with the quantity of each SKU in the order
|
379
|
+
#
|
380
|
+
# @return [Hash]
|
381
|
+
#
|
382
|
+
def sku_quantities
|
383
|
+
items.each_with_object(Hash.new(0)) do |item, quantities|
|
384
|
+
quantities[item.sku] += item.quantity
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
378
388
|
private
|
379
389
|
|
380
390
|
def item_count_limit
|
@@ -80,12 +80,7 @@ module Workarea
|
|
80
80
|
build_credit_card unless credit_card
|
81
81
|
credit_card.saved_card_id = nil
|
82
82
|
credit_card.attributes = attrs.slice(
|
83
|
-
|
84
|
-
:year,
|
85
|
-
:saved_card_id,
|
86
|
-
:number,
|
87
|
-
:cvv,
|
88
|
-
:amount
|
83
|
+
*Workarea.config.credit_card_attributes
|
89
84
|
)
|
90
85
|
save
|
91
86
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Workarea
|
2
|
+
class IndexReleaseSchedulePreviews
|
3
|
+
attr_reader :release, :starts_at, :ends_at
|
4
|
+
|
5
|
+
def initialize(release: nil, starts_at: nil, ends_at: nil)
|
6
|
+
@release = release
|
7
|
+
@starts_at = starts_at
|
8
|
+
@ends_at = ends_at
|
9
|
+
end
|
10
|
+
|
11
|
+
def affected_releases
|
12
|
+
result = Release
|
13
|
+
.scheduled(after: starts_at, before: ends_at)
|
14
|
+
.includes(:changesets)
|
15
|
+
.to_a
|
16
|
+
|
17
|
+
result << release if release.present?
|
18
|
+
result.uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def affected_models
|
22
|
+
affected_releases.flat_map(&:changesets).flat_map(&:releasable).compact
|
23
|
+
end
|
24
|
+
|
25
|
+
def perform
|
26
|
+
affected_releases.each do |release|
|
27
|
+
affected_models.each do |releasable|
|
28
|
+
Search::Storefront.new(releasable.in_release(release)).destroy
|
29
|
+
|
30
|
+
# Different models have different indexing workers, running callbacks
|
31
|
+
# ensures the appropriate worker is triggered
|
32
|
+
releasable.run_callbacks(:save_release_changes)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Workarea
|
2
|
+
class IndexReleaseScheduleChange
|
3
|
+
include Sidekiq::Worker
|
4
|
+
include Sidekiq::CallbacksWorker
|
5
|
+
|
6
|
+
sidekiq_options(
|
7
|
+
enqueue_on: {
|
8
|
+
Release => [:save, :destroy],
|
9
|
+
only_if: -> { publish_at_changed? || destroyed? },
|
10
|
+
with: -> { [id, publish_at_was, publish_at] }
|
11
|
+
},
|
12
|
+
queue: 'releases'
|
13
|
+
)
|
14
|
+
|
15
|
+
def perform(id, previous_publish_at, new_publish_at)
|
16
|
+
# When destroyed, changesets for the release ID will still exist and be used to update the index
|
17
|
+
rescheduled_release = Release.find_or_initialize_by(id: id)
|
18
|
+
|
19
|
+
earlier, later = if rescheduled_release.persisted? && previous_publish_at.present? && new_publish_at.present?
|
20
|
+
[previous_publish_at, new_publish_at].sort
|
21
|
+
elsif previous_publish_at.present?
|
22
|
+
[previous_publish_at, nil]
|
23
|
+
else
|
24
|
+
[new_publish_at, nil]
|
25
|
+
end
|
26
|
+
|
27
|
+
IndexReleaseSchedulePreviews
|
28
|
+
.new(release: rescheduled_release, starts_at: earlier, ends_at: later)
|
29
|
+
.perform
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -8,6 +8,7 @@ module Workarea
|
|
8
8
|
system_user = User.find_system_user!(release.name, 'Release')
|
9
9
|
|
10
10
|
Mongoid::AuditLog.record(system_user) { release.publish! }
|
11
|
+
IndexReleaseSchedulePreviews.new(release: release).perform
|
11
12
|
|
12
13
|
rescue Mongoid::Errors::DocumentNotFound
|
13
14
|
# Doesn't matter, release has been removed
|
@@ -156,14 +156,15 @@ Workarea::Configuration.define_fields do
|
|
156
156
|
end
|
157
157
|
|
158
158
|
fieldset 'Communication', namespaced: false do
|
159
|
+
|
159
160
|
field 'Email From',
|
160
161
|
type: :string,
|
161
|
-
default:
|
162
|
+
default: -> { "#{Workarea.config.site_name} <noreply@#{Workarea.config.host}>" },
|
162
163
|
description: 'The email address used as the sender of system emails'
|
163
164
|
|
164
165
|
field 'Email To',
|
165
166
|
type: :string,
|
166
|
-
default:
|
167
|
+
default: -> { "#{Workarea.config.site_name} <customerservice@#{Workarea.config.host}>" },
|
167
168
|
description: 'The email address that receives user generated emails, e.g. contact us inquiries'
|
168
169
|
|
169
170
|
field 'Inquiry Subjects',
|
data/config/locales/en.yml
CHANGED
@@ -55,6 +55,19 @@ module Workarea
|
|
55
55
|
remove_file 'public/favicon.ico'
|
56
56
|
end
|
57
57
|
|
58
|
+
def add_development_mailer_port
|
59
|
+
development_port = <<-CODE
|
60
|
+
|
61
|
+
config.action_mailer.default_url_options = { port: 3000 }
|
62
|
+
CODE
|
63
|
+
|
64
|
+
inject_into_file(
|
65
|
+
'config/environments/development.rb',
|
66
|
+
development_port,
|
67
|
+
before: /^end/
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
58
71
|
private
|
59
72
|
|
60
73
|
def app_name
|
@@ -4,19 +4,7 @@ Workarea.configure do |config|
|
|
4
4
|
|
5
5
|
config.host = {
|
6
6
|
'test' => 'www.example.com',
|
7
|
-
'development' => 'localhost
|
7
|
+
'development' => 'localhost',
|
8
8
|
'production' => 'www.<%= app_name.dasherize %>.com' # TODO
|
9
9
|
}[Rails.env]
|
10
|
-
|
11
|
-
config.email_to = {
|
12
|
-
'test' => "#{config.site_name} <customerservice@example.com>",
|
13
|
-
'development' => "#{config.site_name} <customerservice@<%= app_name %>.test>",
|
14
|
-
'production' => "#{config.site_name} <customerservice@<%= app_name.dasherize %>.com>" # TODO
|
15
|
-
}[Rails.env]
|
16
|
-
|
17
|
-
config.email_from = {
|
18
|
-
'test' => "#{config.site_name} <noreply@example.com>",
|
19
|
-
'development' => "#{config.site_name} <noreply@<%= app_name %>.test",
|
20
|
-
'production' => "#{config.site_name} <noreply@<%= app_name.dasherize %>.com>" # TODO
|
21
|
-
}[Rails.env]
|
22
10
|
end
|
data/lib/tasks/cache.rake
CHANGED
@@ -1,40 +1,10 @@
|
|
1
|
+
require 'workarea/tasks/cache'
|
2
|
+
|
1
3
|
namespace :workarea do
|
2
4
|
namespace :cache do
|
3
5
|
desc 'Prime images cache'
|
4
6
|
task prime_images: :environment do
|
5
|
-
|
6
|
-
include Workarea::Storefront::ProductsHelper
|
7
|
-
include Workarea::Core::Engine.routes.url_helpers
|
8
|
-
|
9
|
-
built_in_jobs = [:thumb, :gif, :jpg, :png, :strip, :convert, :optimized]
|
10
|
-
|
11
|
-
jobs = Dragonfly.app(:workarea).processor_methods.reject do |job|
|
12
|
-
built_in_jobs.include?(job)
|
13
|
-
end
|
14
|
-
|
15
|
-
Workarea::Catalog::Product.all.each_by(50) do |product|
|
16
|
-
product.images.each do |image|
|
17
|
-
jobs.each do |job|
|
18
|
-
url = URI.join(
|
19
|
-
"https://#{Workarea.config.host}",
|
20
|
-
dynamic_product_image_url(
|
21
|
-
image.product.slug,
|
22
|
-
image.option,
|
23
|
-
image.id,
|
24
|
-
job,
|
25
|
-
only_path: true
|
26
|
-
)
|
27
|
-
).to_s
|
28
|
-
|
29
|
-
begin
|
30
|
-
`curl #{url}`
|
31
|
-
puts "Downloaded image #{url}"
|
32
|
-
rescue StandardError => e
|
33
|
-
puts e.inspect
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
7
|
+
Workarea::Tasks::Cache.prime_images
|
38
8
|
end
|
39
9
|
end
|
40
10
|
end
|
data/lib/tasks/help.rake
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
+
require 'workarea/tasks/help'
|
2
|
+
|
1
3
|
namespace :workarea do
|
2
4
|
desc 'Drop and recreate help articles (Warning: all current help will be deleted!)'
|
3
5
|
task reload_help: :environment do
|
4
6
|
puts 'Deleting help articles...'
|
5
|
-
Workarea::Help
|
6
|
-
Workarea::Help::Asset.delete_all
|
7
|
-
|
8
|
-
Workarea::HelpSeeds.new.perform
|
7
|
+
Workarea::Tasks::Help.reload
|
9
8
|
Rake::Task['workarea:search_index:help'].invoke
|
10
9
|
end
|
11
10
|
|
@@ -16,44 +15,6 @@ namespace :workarea do
|
|
16
15
|
end
|
17
16
|
|
18
17
|
task dump_help: :environment do
|
19
|
-
Workarea::Help
|
20
|
-
article_root = Rails.root.join(
|
21
|
-
'data',
|
22
|
-
'help',
|
23
|
-
article.category.systemize,
|
24
|
-
article.name.systemize
|
25
|
-
)
|
26
|
-
|
27
|
-
asset_path = article_root.join('assets')
|
28
|
-
|
29
|
-
FileUtils.mkdir_p(article_root)
|
30
|
-
|
31
|
-
if article.thumbnail.present?
|
32
|
-
article.thumbnail.to_file(article_root.join(article.thumbnail.name))
|
33
|
-
end
|
34
|
-
|
35
|
-
Workarea::Help::Asset.all.each_by(50) do |asset|
|
36
|
-
if article.summary.include?(asset.url) || article.body.include?(asset.url)
|
37
|
-
FileUtils.mkdir_p(asset_path)
|
38
|
-
asset.to_file(asset_path.join(asset.name))
|
39
|
-
reference = "<%= #{asset.name.split('.').first} %>"
|
40
|
-
|
41
|
-
article.summary.gsub!(asset.url, reference)
|
42
|
-
article.body.gsub!(asset.url, reference)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
if article.summary.present?
|
47
|
-
File.open(article_root.join('summary.md'), 'w') do |file|
|
48
|
-
file.write(article.summary)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
if article.body.present?
|
53
|
-
File.open(article_root.join('body.md'), 'w') do |file|
|
54
|
-
file.write(article.body)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
18
|
+
Workarea::Tasks::Help.dump
|
58
19
|
end
|
59
20
|
end
|