workarea-core 3.5.17 → 3.5.18

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d24b6af137b806311dbd5d13fb13a57f8693f99d767f94fb3144994fe9c7028
4
- data.tar.gz: dbbfb80358c11fc03b2e470ac741f615dc2d68e5f9c6c0d55b3b69567eaa4d02
3
+ metadata.gz: 84d99f1dbf010e7d67b9dbc7785720bbed5cd17c22528dfe57e194dfbb660892
4
+ data.tar.gz: c5453a27cf96335ae9d35fe857ccc770a0412117579b37dc1cb84e9221cd6efe
5
5
  SHA512:
6
- metadata.gz: a7f587ddc4e1e9c425eaace526f562f99ec5885002f833fd33a134164d3d20a405938a1e762b3cfd221824a77f435ebb79383591ae2bd0c3b81bd407ba0ceb12
7
- data.tar.gz: 61da7b2aa4a72d5e0b5456b401f9124769fa5f43c601d33e6e14b6a64bf820910bed36faf6992a1865e603455710b05647fa62b62488fa8fd973d33edac02564
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 ||= User.find(session[:user_id])
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
@@ -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
- return @app.call(env) if request.path =~ /(jpe?g|png|ico|gif|css|js|svg)$/
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)
@@ -11,6 +11,10 @@ module Workarea
11
11
  def self.available_sorts
12
12
  AdminSorting.available_sorts
13
13
  end
14
+
15
+ def default_admin_sort
16
+ [{ _score: :desc }, { updated_at: :desc }]
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -16,7 +16,7 @@ module Workarea
16
16
  end
17
17
 
18
18
  def default_admin_sort
19
- [{ _score: :desc }, { updated_at: :desc }]
19
+ [{ updated_at: :desc }, { _score: :desc }]
20
20
  end
21
21
 
22
22
  def user_selected_sort
@@ -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: 'noreply@example.com',
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: 'customerservice@example.com',
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',
@@ -7,16 +7,4 @@ Workarea.configure do |config|
7
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
@@ -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
- include Rails.application.routes.url_helpers
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
@@ -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::Article.delete_all
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::Article.all.each_by(50) do |article|
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
@@ -1,49 +1,17 @@
1
- require 'active_support/testing/time_helpers'
1
+ require 'workarea/tasks/insights'
2
2
 
3
3
  namespace :workarea do
4
4
  namespace :insights do
5
5
  desc 'Creates metrics and insights based on orders'
6
6
  task generate: :environment do
7
- include ActiveSupport::Testing::TimeHelpers
8
- batch_size = ENV['WORKAREA_INSIGHTS_BATCH_SIZE'].presence || 1000
9
-
10
- Workarea::Order
11
- .placed
12
- .each_by(batch_size.to_i) { |o| Workarea::SaveOrderMetrics.perform(o) }
13
-
14
- 8.times do |i|
15
- travel_to (i.weeks.ago.beginning_of_week + 1.hour)
16
- Workarea::GenerateInsights.generate_all!
17
- end
18
-
7
+ Workarea::Tasks::Insights.generate
19
8
  puts "Success! Generated #{Workarea::Insights::Base.count} insights."
20
9
  end
21
10
 
22
11
  # Clear the metrics/insights environment - deletes lots of data, this task
23
12
  # is very dangerous! Useful for testing/debugging.
24
13
  task reset: :environment do
25
- Workarea::Order
26
- .where(:metrics_saved_at.gt => 0)
27
- .update_all(metrics_saved_at: nil)
28
-
29
-
30
- Workarea::Metrics::CategoryByDay.delete_all
31
- Workarea::Metrics::CountryByDay.delete_all
32
- Workarea::Metrics::DiscountByDay.delete_all
33
- Workarea::Metrics::MenuByDay.delete_all
34
- Workarea::Metrics::ProductByDay.delete_all
35
- Workarea::Metrics::ProductByWeek.delete_all
36
- Workarea::Metrics::ProductForLastWeek.delete_all
37
- Workarea::Metrics::SalesByDay.delete_all
38
- Workarea::Metrics::SearchByDay.delete_all
39
- Workarea::Metrics::SearchByWeek.delete_all
40
- Workarea::Metrics::SearchForLastWeek.delete_all
41
- Workarea::Metrics::SkuByDay.delete_all
42
- Workarea::Metrics::TenderByDay.delete_all
43
- Workarea::Metrics::TrafficReferrerByDay.delete_all
44
- Workarea::Metrics::User.delete_all
45
- Workarea::Insights::Base.delete_all
46
-
14
+ Workarea::Tasks::Insights.reset!
47
15
  puts "Success! Insights and metrics have been cleared."
48
16
  end
49
17
  end
@@ -1,103 +1,10 @@
1
+ require 'workarea/tasks/migrate'
2
+
1
3
  namespace :workarea do
2
4
  namespace :migrate do
3
5
  desc 'Migrate the database from v3.4 to v3.5'
4
6
  task v3_5: :environment do
5
- count = 0
6
-
7
- Workarea::Release.where(:undo_at.gte => Time.current).each do |release|
8
- undo = release.build_undo(publish_at: release.undo_at).tap(&:save!)
9
-
10
- release.changesets.each do |changeset|
11
- changeset.build_undo(release: undo).save!
12
- end
13
-
14
- Workarea::Scheduler.delete(release.undo_job_id)
15
-
16
- release.update_attributes!(undo_at: nil, undo_job_id: nil)
17
- count += 1
18
- end
19
-
20
- Workarea::Release.all.each { |r| Workarea::IndexAdminSearch.perform(r) }
21
-
22
- puts "✅ #{count} undo releases have been created."
23
-
24
- count = 0
25
-
26
- Workarea::Tax::Category.all.each_by(100) do |category|
27
- category.rates.each_by(500) do |rate|
28
- rate.postal_code_percentage = rate.percentage
29
- rate.percentage = nil
30
- end
31
-
32
- category.save!
33
- count += 1
34
- end
35
-
36
- puts "✅ #{count} tax categories updated."
37
-
38
- count = 0
39
- failed_ids = []
40
- backup = Mongo::Collection.new(Mongoid::Clients.default.database, 'workarea_legacy_segments')
41
-
42
- legacy_segments = Workarea::Segment.collection.find.to_a
43
- legacy_segments.each do |doc|
44
- backup.insert_one(doc)
45
- Workarea::Segment.collection.delete_one(doc.slice('_id'))
46
-
47
- segment = Workarea::Segment.new(
48
- id: doc['_id'],
49
- name: doc['name'],
50
- subscribed_user_ids: doc['subscribed_user_ids'],
51
- created_at: doc['created_at'],
52
- updated_at: doc['updated_at']
53
- )
54
-
55
- doc['conditions'].each do |condition|
56
- if condition['_type'] =~ /UserTag/
57
- segment.rules << Workarea::Segment::Rules::Tags.new(tags: condition['tags'])
58
- elsif condition['_type'] =~ /TotalSpent/
59
- rule = Workarea::Segment::Rules::Revenue.new
60
-
61
- if condition['operator'] == 'equals'
62
- rule.minimum = rule.maximum = Money.demongoize(condition['amount'])
63
- elsif condition['operator'] == 'less_than_or_equals'
64
- rule.maximum = Money.demongoize(condition['amount'])
65
- elsif condition['operator'] == 'less_than'
66
- rule.maximum = (Money.demongoize(condition['amount']) - 0.01.to_m)
67
- elsif condition['operator'] == 'greater_than_or_equals'
68
- rule.minimum = Money.demongoize(condition['amount'])
69
- elsif condition['operator'] == 'greater_than'
70
- rule.minimum = (Money.demongoize(condition['amount']) + 0.01.to_m)
71
- end
72
-
73
- segment.rules << rule
74
- end
75
- end
76
-
77
- if doc['conditions'].size == segment.rules.size && segment.save
78
- count += 1
79
- else
80
- failed_ids << doc['_id']
81
- end
82
- end
83
-
84
- puts "✅ #{count} segments have been migrated." if count > 0
85
- if failed_ids.any?
86
- puts "⛔️ #{failed_ids.count} segments failed to migrate."
87
- puts "You can find copies of the original segments in the workarea_legacy_segments collection."
88
- puts "The segments that failed are #{failed_ids.to_sentence}."
89
- end
90
-
91
- Workarea::Segment::LifeCycle.create!
92
- puts "✅ Life cycle segments have been created."
93
-
94
- admin_ids = Workarea::User.admins.pluck(:id)
95
- admin_ids.each do |id|
96
- Workarea::SynchronizeUserMetrics.new.perform(id)
97
- end
98
- puts "✅ #{admin_ids.count} admins have had their metrics synchronized." if admin_ids.count > 0
99
-
100
- puts "\nMigration complete!"
7
+ Workarea::Tasks::Migrate.v3_5
101
8
  end
102
9
  end
103
10
  end
@@ -1,8 +1,9 @@
1
+ require 'workarea/tasks/search'
2
+
1
3
  namespace :workarea do
2
4
  namespace :search_index do
3
5
  def setup
4
- require 'sidekiq/testing/inline' unless ENV['INLINE'] == 'false'
5
- Workarea.config.bulk_index_batch_size = ENV['BATCH_SIZE'].to_i if ENV['BATCH_SIZE'].present?
6
+ Workarea::Tasks::Search.setup
6
7
  end
7
8
 
8
9
  desc 'Reindex all data'
@@ -16,84 +17,21 @@ namespace :workarea do
16
17
  task admin: :environment do
17
18
  setup
18
19
  puts 'Indexing admin...'
19
- Workarea::QueuesPauser.with_paused_queues do
20
- Workarea::Search::Admin.reset_indexes!
21
- end
22
-
23
- Mongoid.models.each do |klass|
24
- next unless Workarea::Search::Admin.for(klass.first).present?
25
-
26
- klass.all.each_slice_of(Workarea.config.bulk_index_batch_size) do |models|
27
- Workarea::BulkIndexAdmin.perform_by_models(models)
28
- end
29
- end
30
-
31
- Workarea.config.jump_to_navigation.to_a.each do |tuple|
32
- Workarea::Search::Admin::Navigation.new(tuple).save
33
- end
20
+ Workarea::Tasks::Search.index_admin
34
21
  end
35
22
 
36
23
  desc 'Reindex storefront'
37
24
  task storefront: :environment do
38
25
  setup
39
26
  puts 'Indexing storefront...'
40
-
41
- Workarea::QueuesPauser.with_paused_queues do
42
- Workarea::Search::Storefront.reset_indexes!
43
- Workarea::Search::Storefront.ensure_dynamic_mappings
44
- end
45
-
46
- # This code finds all unique filters for products so we can index a sample
47
- # product for each to ensure the dynamic mappings get created.
48
- #
49
- # This is necessary to fix mapping errors from Elasticsearch when trying
50
- # to index category percolations against fields which have no mapping.
51
- #
52
- map = %{
53
- function() {
54
- for (var key in this.filters.#{I18n.locale}) {
55
- emit(key, null);
56
- }
57
- }
58
- }
59
- reduce = 'function(key) { return null; }'
60
- results = Workarea::Catalog::Product.map_reduce(map, reduce).out(inline: 1)
61
- unique_filters = results.map { |r| r['_id'] }
62
-
63
- sample_products = unique_filters.reduce([]) do |memo, filter|
64
- filter = "filters.#{I18n.locale}.#{filter}"
65
- memo << Workarea::Catalog::Product.exists(filter => true).sample
66
- end
67
-
68
- sample_products.each do |product|
69
- Workarea::Search::Storefront::Product.new(product).save
70
- end
71
-
72
- Workarea::Catalog::Category.all.each_by(Workarea.config.bulk_index_batch_size) do |category|
73
- Workarea::Search::Storefront::CategoryQuery.new(category).create
74
- Workarea::Search::Storefront::Category.new(category).save
75
- end
76
-
77
- Workarea::Content::Page.all.each_by(Workarea.config.bulk_index_batch_size) do |page|
78
- Workarea::Search::Storefront::Page.new(page).save
79
- end
80
-
81
- Workarea::BulkIndexProducts.perform
82
- Workarea::BulkIndexSearches.perform
27
+ Workarea::Tasks::Search.index_storefront
83
28
  end
84
29
 
85
30
  desc 'Reindex help'
86
31
  task help: :environment do
87
32
  setup
88
33
  puts 'Indexing help...'
89
-
90
- Workarea::QueuesPauser.with_paused_queues do
91
- Workarea::Search::Help.reset_indexes!
92
- end
93
-
94
- Workarea::Help::Article.all.each_by(Workarea.config.bulk_index_batch_size) do |help_article|
95
- Workarea::Search::Help.new(help_article).save
96
- end
34
+ Workarea::Tasks::Search.index_help
97
35
  end
98
36
  end
99
37
  end
@@ -1,73 +1,23 @@
1
- require 'workarea/version'
1
+ require 'workarea/tasks/services'
2
2
 
3
3
  namespace :workarea do
4
4
  namespace :services do
5
- def assert_docker_compose_installed!
6
- unless system('docker-compose -v > /dev/null 2>&1')
7
- STDERR.puts <<~eos
8
- **************************************************
9
- ⛔️ ERROR: workarea:services tasks depend on Docker Compose being installed. \
10
- See https://docs.docker.com/compose/install/ for how to install.
11
- **************************************************
12
- eos
13
- exit
14
- end
15
- end
16
-
17
- def compose_file_path
18
- File.join(Gem::Specification.find_by_name('workarea').gem_dir, 'docker-compose.yml')
19
- end
20
-
21
- def compose_env
22
- {
23
- 'COMPOSE_FILE' => compose_file_path,
24
- 'COMPOSE_PROJECT_NAME' => File.basename(Dir.pwd),
25
-
26
- 'MONGODB_VERSION' => Workarea::VERSION::MONGODB::STRING,
27
- 'MONGODB_PORT' => ENV['WORKAREA_MONGODB_PORT'] || '27017',
28
-
29
- 'REDIS_VERSION' => Workarea::VERSION::REDIS::STRING,
30
- 'REDIS_PORT' => ENV['WORKAREA_REDIS_PORT'] || '6379',
31
-
32
- 'ELASTICSEARCH_VERSION' => Workarea::VERSION::ELASTICSEARCH::STRING,
33
- 'ELASTICSEARCH_PORT' => ENV['WORKAREA_ELASTICSEARCH_PORT'] || '9200'
34
- }
35
- end
36
-
37
5
  desc 'Start Workarea background services for this app'
38
6
  task :up do
39
7
  puts 'Starting Workarea services...'
40
- assert_docker_compose_installed!
41
-
42
- if system(compose_env, "docker-compose up -d #{ENV['COMPOSE_ARGUMENTS']} #{ENV['WORKAREA_SERVICES']}")
43
- puts '✅ Success! Workarea services are running in the background. Run workarea:services:down to stop them.'
44
- else
45
- STDERR.puts '⛔️ Error! There was an error starting Workarea services.'
46
- end
8
+ Workarea::Tasks::Services.up
47
9
  end
48
10
 
49
11
  desc 'Stop Workarea external services for this app'
50
12
  task :down do
51
13
  puts 'Stopping Workarea services...'
52
- assert_docker_compose_installed!
53
-
54
- if system(compose_env, "docker-compose down #{ENV['COMPOSE_ARGUMENTS']}")
55
- puts '✅ Success! Workarea services are stopped. Run workarea:services:up to start them.'
56
- else
57
- STDERR.puts '⛔️ Error! There was an error stopping Workarea services.'
58
- end
14
+ Workarea::Tasks::Services.down
59
15
  end
60
16
 
61
17
  desc 'Remove data volumes associated with Workarea external services. Stops containers.'
62
18
  task :clean do
63
19
  puts 'Removing Workarea service data...'
64
- assert_docker_compose_installed!
65
-
66
- if system(compose_env, "docker-compose down -v #{ENV['COMPOSE_ARGUMENTS']}")
67
- puts '✅ Success! Workarea service volumes have been removed. Run workarea:services:up to start services and recreate volumes.'
68
- else
69
- STDERR.puts '⛔️ Error! There was an error removing Workarea service volumes.'
70
- end
20
+ Workarea::Tasks::Services.clean
71
21
  end
72
22
  end
73
23
  end
@@ -26,8 +26,6 @@ module Workarea
26
26
 
27
27
  config.site_name = 'Workarea'
28
28
  config.host = 'www.example.com'
29
- config.email_to = 'customerservice@example.com'
30
- config.email_from = 'noreply@example.com'
31
29
 
32
30
  # Config sent to the ImageMagick through Dragonfly for optimizing jpgs
33
31
  # All metadata profiles are removed, comments cleared by comment -set ""
@@ -78,6 +78,10 @@ module Workarea
78
78
  # get autoloaded. Without this, admin actions like updating product
79
79
  # attributes raises a {NameError} "uninitialized constant BulkIndexProducts".
80
80
  require_dependency 'workarea/bulk_index_products'
81
+
82
+ # Fixes a constant error raised in middleware (when doing segmentation)
83
+ # No idea what the cause is. TODO revisit after Zeitwerk.
84
+ require_dependency 'workarea/metrics/user'
81
85
  end
82
86
  end
83
87
  end
@@ -0,0 +1,43 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Cache
4
+ extend self
5
+
6
+ def prime_images
7
+ include Rails.application.routes.url_helpers
8
+ include Workarea::Storefront::ProductsHelper
9
+ include Workarea::Core::Engine.routes.url_helpers
10
+
11
+ built_in_jobs = [:thumb, :gif, :jpg, :png, :strip, :convert, :optimized]
12
+
13
+ jobs = Dragonfly.app(:workarea).processor_methods.reject do |job|
14
+ built_in_jobs.include?(job)
15
+ end
16
+
17
+ Workarea::Catalog::Product.all.each_by(50) do |product|
18
+ product.images.each do |image|
19
+ jobs.each do |job|
20
+ url = URI.join(
21
+ "https://#{Workarea.config.host}",
22
+ dynamic_product_image_url(
23
+ image.product.slug,
24
+ image.option,
25
+ image.id,
26
+ job,
27
+ only_path: true
28
+ )
29
+ ).to_s
30
+
31
+ begin
32
+ `curl #{url}`
33
+ puts "Downloaded image #{url}"
34
+ rescue StandardError => e
35
+ puts e.inspect
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Help
4
+ extend self
5
+
6
+ def reload
7
+ Workarea::Help::Article.delete_all
8
+ Workarea::Help::Asset.delete_all
9
+ Workarea::HelpSeeds.new.perform
10
+ end
11
+
12
+ def dump
13
+ Workarea::Help::Article.all.each_by(50) do |article|
14
+ article_root = Rails.root.join(
15
+ 'data',
16
+ 'help',
17
+ article.category.systemize,
18
+ article.name.systemize
19
+ )
20
+
21
+ asset_path = article_root.join('assets')
22
+
23
+ FileUtils.mkdir_p(article_root)
24
+
25
+ if article.thumbnail.present?
26
+ article.thumbnail.to_file(article_root.join(article.thumbnail.name))
27
+ end
28
+
29
+ Workarea::Help::Asset.all.each_by(50) do |asset|
30
+ if article.summary.include?(asset.url) || article.body.include?(asset.url)
31
+ FileUtils.mkdir_p(asset_path)
32
+ asset.to_file(asset_path.join(asset.name))
33
+ reference = "<%= #{asset.name.split('.').first} %>"
34
+
35
+ article.summary.gsub!(asset.url, reference)
36
+ article.body.gsub!(asset.url, reference)
37
+ end
38
+ end
39
+
40
+ if article.summary.present?
41
+ File.open(article_root.join('summary.md'), 'w') do |file|
42
+ file.write(article.summary)
43
+ end
44
+ end
45
+
46
+ if article.body.present?
47
+ File.open(article_root.join('body.md'), 'w') do |file|
48
+ file.write(article.body)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,47 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Insights
4
+ extend self
5
+
6
+ def generate
7
+ require 'active_support/testing/time_helpers'
8
+ include ActiveSupport::Testing::TimeHelpers
9
+ batch_size = ENV['WORKAREA_INSIGHTS_BATCH_SIZE'].presence || 1000
10
+
11
+ Workarea::Order
12
+ .placed
13
+ .each_by(batch_size.to_i) { |o| Workarea::SaveOrderMetrics.perform(o) }
14
+
15
+ 8.times do |i|
16
+ travel_to (i.weeks.ago.beginning_of_week + 1.hour)
17
+ Workarea::GenerateInsights.generate_all!
18
+ end
19
+ end
20
+
21
+ # Clear the metrics/insights environment - deletes lots of data, this task
22
+ # is very dangerous! Useful for testing/debugging.
23
+ def reset!
24
+ Workarea::Order
25
+ .where(:metrics_saved_at.gt => 0)
26
+ .update_all(metrics_saved_at: nil)
27
+
28
+ Workarea::Metrics::CategoryByDay.delete_all
29
+ Workarea::Metrics::CountryByDay.delete_all
30
+ Workarea::Metrics::DiscountByDay.delete_all
31
+ Workarea::Metrics::MenuByDay.delete_all
32
+ Workarea::Metrics::ProductByDay.delete_all
33
+ Workarea::Metrics::ProductByWeek.delete_all
34
+ Workarea::Metrics::ProductForLastWeek.delete_all
35
+ Workarea::Metrics::SalesByDay.delete_all
36
+ Workarea::Metrics::SearchByDay.delete_all
37
+ Workarea::Metrics::SearchByWeek.delete_all
38
+ Workarea::Metrics::SearchForLastWeek.delete_all
39
+ Workarea::Metrics::SkuByDay.delete_all
40
+ Workarea::Metrics::TenderByDay.delete_all
41
+ Workarea::Metrics::TrafficReferrerByDay.delete_all
42
+ Workarea::Metrics::User.delete_all
43
+ Workarea::Insights::Base.delete_all
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,106 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Migrate
4
+ extend self
5
+
6
+ def v3_5
7
+ count = 0
8
+
9
+ Workarea::Release.where(:undo_at.gte => Time.current).each do |release|
10
+ undo = release.build_undo(publish_at: release.undo_at).tap(&:save!)
11
+
12
+ release.changesets.each do |changeset|
13
+ changeset.build_undo(release: undo).save!
14
+ end
15
+
16
+ Workarea::Scheduler.delete(release.undo_job_id)
17
+
18
+ release.update_attributes!(undo_at: nil, undo_job_id: nil)
19
+ count += 1
20
+ end
21
+
22
+ Workarea::Release.all.each { |r| Workarea::IndexAdminSearch.perform(r) }
23
+
24
+ puts "✅ #{count} undo releases have been created."
25
+
26
+ count = 0
27
+
28
+ Workarea::Tax::Category.all.each_by(100) do |category|
29
+ category.rates.each_by(500) do |rate|
30
+ rate.postal_code_percentage = rate.percentage
31
+ rate.percentage = nil
32
+ end
33
+
34
+ category.save!
35
+ count += 1
36
+ end
37
+
38
+ puts "✅ #{count} tax categories updated."
39
+
40
+ count = 0
41
+ failed_ids = []
42
+ backup = Mongo::Collection.new(Mongoid::Clients.default.database, 'workarea_legacy_segments')
43
+
44
+ legacy_segments = Workarea::Segment.collection.find.to_a
45
+ legacy_segments.each do |doc|
46
+ backup.insert_one(doc)
47
+ Workarea::Segment.collection.delete_one(doc.slice('_id'))
48
+
49
+ segment = Workarea::Segment.new(
50
+ id: doc['_id'],
51
+ name: doc['name'],
52
+ subscribed_user_ids: doc['subscribed_user_ids'],
53
+ created_at: doc['created_at'],
54
+ updated_at: doc['updated_at']
55
+ )
56
+
57
+ doc['conditions'].each do |condition|
58
+ if condition['_type'] =~ /UserTag/
59
+ segment.rules << Workarea::Segment::Rules::Tags.new(tags: condition['tags'])
60
+ elsif condition['_type'] =~ /TotalSpent/
61
+ rule = Workarea::Segment::Rules::Revenue.new
62
+
63
+ if condition['operator'] == 'equals'
64
+ rule.minimum = rule.maximum = Money.demongoize(condition['amount'])
65
+ elsif condition['operator'] == 'less_than_or_equals'
66
+ rule.maximum = Money.demongoize(condition['amount'])
67
+ elsif condition['operator'] == 'less_than'
68
+ rule.maximum = (Money.demongoize(condition['amount']) - 0.01.to_m)
69
+ elsif condition['operator'] == 'greater_than_or_equals'
70
+ rule.minimum = Money.demongoize(condition['amount'])
71
+ elsif condition['operator'] == 'greater_than'
72
+ rule.minimum = (Money.demongoize(condition['amount']) + 0.01.to_m)
73
+ end
74
+
75
+ segment.rules << rule
76
+ end
77
+ end
78
+
79
+ if doc['conditions'].size == segment.rules.size && segment.save
80
+ count += 1
81
+ else
82
+ failed_ids << doc['_id']
83
+ end
84
+ end
85
+
86
+ puts "✅ #{count} segments have been migrated." if count > 0
87
+ if failed_ids.any?
88
+ puts "⛔️ #{failed_ids.count} segments failed to migrate."
89
+ puts "You can find copies of the original segments in the workarea_legacy_segments collection."
90
+ puts "The segments that failed are #{failed_ids.to_sentence}."
91
+ end
92
+
93
+ Workarea::Segment::LifeCycle.create!
94
+ puts "✅ Life cycle segments have been created."
95
+
96
+ admin_ids = Workarea::User.admins.pluck(:id)
97
+ admin_ids.each do |id|
98
+ Workarea::SynchronizeUserMetrics.new.perform(id)
99
+ end
100
+ puts "✅ #{admin_ids.count} admins have had their metrics synchronized." if admin_ids.count > 0
101
+
102
+ puts "\nMigration complete!"
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,105 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Search
4
+ extend self
5
+
6
+ def setup
7
+ require 'sidekiq/testing/inline' unless ENV['INLINE'] == 'false'
8
+ Workarea.config.bulk_index_batch_size = ENV['BATCH_SIZE'].to_i if ENV['BATCH_SIZE'].present?
9
+ end
10
+
11
+ def index_admin
12
+ Workarea::QueuesPauser.with_paused_queues do
13
+ Workarea::Search::Admin.reset_indexes!
14
+ end
15
+
16
+ Mongoid.models.each do |klass|
17
+ next unless Workarea::Search::Admin.for(klass.first).present?
18
+
19
+ klass.all.each_slice_of(Workarea.config.bulk_index_batch_size) do |models|
20
+ Workarea::BulkIndexAdmin.perform_by_models(models)
21
+ end
22
+ end
23
+
24
+ Workarea.config.jump_to_navigation.to_a.each do |tuple|
25
+ Workarea::Search::Admin::Navigation.new(tuple).save
26
+ end
27
+ end
28
+
29
+ def index_storefront
30
+ Workarea::QueuesPauser.with_paused_queues do
31
+ Workarea::Search::Storefront.reset_indexes!
32
+ Workarea::Search::Storefront.ensure_dynamic_mappings
33
+ end
34
+
35
+ ensure_dynamic_mappings_for_current_product_filters
36
+
37
+ index_storefront_categories
38
+ index_storefront_content_pages
39
+ index_storefront_products
40
+ index_storefront_searches
41
+ end
42
+
43
+ def index_help
44
+ Workarea::QueuesPauser.with_paused_queues do
45
+ Workarea::Search::Help.reset_indexes!
46
+ end
47
+
48
+ Workarea::Help::Article.all.each_by(Workarea.config.bulk_index_batch_size) do |help_article|
49
+ Workarea::Search::Help.new(help_article).save
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # This code finds all unique filters for products so we can index a sample
56
+ # product for each to ensure the dynamic mappings get created.
57
+ #
58
+ # This is necessary to fix mapping errors from Elasticsearch when trying
59
+ # to index category percolations against fields which have no mapping.
60
+ #
61
+ def ensure_dynamic_mappings_for_current_product_filters
62
+ map = %{
63
+ function() {
64
+ for (var key in this.filters.#{I18n.locale}) {
65
+ emit(key, null);
66
+ }
67
+ }
68
+ }
69
+ reduce = 'function(key) { return null; }'
70
+ results = Workarea::Catalog::Product.map_reduce(map, reduce).out(inline: 1)
71
+ unique_filters = results.map { |r| r['_id'] }
72
+
73
+ sample_products = unique_filters.reduce([]) do |memo, filter|
74
+ filter = "filters.#{I18n.locale}.#{filter}"
75
+ memo << Workarea::Catalog::Product.exists(filter => true).sample
76
+ end
77
+
78
+ sample_products.each do |product|
79
+ Workarea::Search::Storefront::Product.new(product).save
80
+ end
81
+ end
82
+
83
+ def index_storefront_categories
84
+ Workarea::Catalog::Category.all.each_by(Workarea.config.bulk_index_batch_size) do |category|
85
+ Workarea::Search::Storefront::CategoryQuery.new(category).create
86
+ Workarea::Search::Storefront::Category.new(category).save
87
+ end
88
+ end
89
+
90
+ def index_storefront_content_pages
91
+ Workarea::Content::Page.all.each_by(Workarea.config.bulk_index_batch_size) do |page|
92
+ Workarea::Search::Storefront::Page.new(page).save
93
+ end
94
+ end
95
+
96
+ def index_storefront_products
97
+ Workarea::BulkIndexProducts.perform
98
+ end
99
+
100
+ def index_storefront_searches
101
+ Workarea::BulkIndexSearches.perform
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,71 @@
1
+ module Workarea
2
+ module Tasks
3
+ module Services
4
+ extend self
5
+
6
+ def assert_docker_compose_installed!
7
+ unless system('docker-compose -v > /dev/null 2>&1')
8
+ STDERR.puts <<~eos
9
+ **************************************************
10
+ ⛔️ ERROR: workarea:services tasks depend on Docker Compose being installed. \
11
+ See https://docs.docker.com/compose/install/ for how to install.
12
+ **************************************************
13
+ eos
14
+ exit
15
+ end
16
+ end
17
+
18
+ def compose_file_path
19
+ File.join(Gem::Specification.find_by_name('workarea').gem_dir, 'docker-compose.yml')
20
+ end
21
+
22
+ def compose_env
23
+ require 'workarea/version'
24
+
25
+ {
26
+ 'COMPOSE_FILE' => compose_file_path,
27
+ 'COMPOSE_PROJECT_NAME' => File.basename(Dir.pwd),
28
+
29
+ 'MONGODB_VERSION' => Workarea::VERSION::MONGODB::STRING,
30
+ 'MONGODB_PORT' => ENV['WORKAREA_MONGODB_PORT'] || '27017',
31
+
32
+ 'REDIS_VERSION' => Workarea::VERSION::REDIS::STRING,
33
+ 'REDIS_PORT' => ENV['WORKAREA_REDIS_PORT'] || '6379',
34
+
35
+ 'ELASTICSEARCH_VERSION' => Workarea::VERSION::ELASTICSEARCH::STRING,
36
+ 'ELASTICSEARCH_PORT' => ENV['WORKAREA_ELASTICSEARCH_PORT'] || '9200'
37
+ }
38
+ end
39
+
40
+ def up
41
+ assert_docker_compose_installed!
42
+
43
+ if system(compose_env, "docker-compose up -d #{ENV['COMPOSE_ARGUMENTS']} #{ENV['WORKAREA_SERVICES']}")
44
+ puts '✅ Success! Workarea services are running in the background. Run workarea:services:down to stop them.'
45
+ else
46
+ STDERR.puts '⛔️ Error! There was an error starting Workarea services.'
47
+ end
48
+ end
49
+
50
+ def down
51
+ assert_docker_compose_installed!
52
+
53
+ if system(compose_env, "docker-compose down #{ENV['COMPOSE_ARGUMENTS']}")
54
+ puts '✅ Success! Workarea services are stopped. Run workarea:services:up to start them.'
55
+ else
56
+ STDERR.puts '⛔️ Error! There was an error stopping Workarea services.'
57
+ end
58
+ end
59
+
60
+ def clean
61
+ assert_docker_compose_installed!
62
+
63
+ if system(compose_env, "docker-compose down -v #{ENV['COMPOSE_ARGUMENTS']}")
64
+ puts '✅ Success! Workarea service volumes have been removed. Run workarea:services:up to start services and recreate volumes.'
65
+ else
66
+ STDERR.puts '⛔️ Error! There was an error removing Workarea service volumes.'
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -2,7 +2,7 @@ module Workarea
2
2
  module VERSION
3
3
  MAJOR = 3
4
4
  MINOR = 5
5
- PATCH = 17
5
+ PATCH = 18
6
6
  PRE = nil
7
7
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
8
8
 
@@ -55,8 +55,6 @@ module Workarea
55
55
  assert_file 'config/initializers/workarea.rb' do |file|
56
56
  assert_match(%(config.site_name =), file)
57
57
  assert_match(%(config.host =), file)
58
- assert_match(%(config.email_to =), file)
59
- assert_match(%(config.email_from =), file)
60
58
  end
61
59
  end
62
60
 
@@ -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: []),
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.5.17
4
+ version: 3.5.18
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-08-19 00:00:00.000000000 Z
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -1990,6 +1990,12 @@ files:
1990
1990
  - lib/workarea/string_id.rb
1991
1991
  - lib/workarea/svg_asset_finder.rb
1992
1992
  - lib/workarea/swappable_list.rb
1993
+ - lib/workarea/tasks/cache.rb
1994
+ - lib/workarea/tasks/help.rb
1995
+ - lib/workarea/tasks/insights.rb
1996
+ - lib/workarea/tasks/migrate.rb
1997
+ - lib/workarea/tasks/search.rb
1998
+ - lib/workarea/tasks/services.rb
1993
1999
  - lib/workarea/url_token.rb
1994
2000
  - lib/workarea/validators/email_validator.rb
1995
2001
  - lib/workarea/validators/ip_address_validator.rb