workarea-core 3.5.13 → 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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/workarea/impersonation.rb +2 -1
  3. data/app/mailers/workarea/application_mailer.rb +4 -1
  4. data/app/middleware/workarea/application_middleware.rb +5 -2
  5. data/app/models/workarea/checkout.rb +7 -7
  6. data/app/models/workarea/data_file/csv.rb +9 -1
  7. data/app/models/workarea/inquiry.rb +2 -1
  8. data/app/models/workarea/inventory/sku.rb +2 -2
  9. data/app/models/workarea/metrics/user.rb +24 -8
  10. data/app/models/workarea/order.rb +10 -0
  11. data/app/models/workarea/payment.rb +1 -6
  12. data/app/models/workarea/search/storefront/category_query.rb +1 -1
  13. data/app/queries/workarea/search/admin_search.rb +4 -0
  14. data/app/queries/workarea/search/admin_sorting.rb +1 -1
  15. data/app/services/workarea/index_release_schedule_previews.rb +37 -0
  16. data/app/workers/workarea/index_release_schedule_change.rb +32 -0
  17. data/app/workers/workarea/publish_release.rb +1 -0
  18. data/config/initializers/00_configuration.rb +3 -2
  19. data/config/locales/en.yml +2 -0
  20. data/lib/generators/workarea/install/install_generator.rb +13 -0
  21. data/lib/generators/workarea/install/templates/initializer.rb.erb +1 -13
  22. data/lib/tasks/cache.rake +3 -33
  23. data/lib/tasks/help.rake +4 -43
  24. data/lib/tasks/insights.rake +3 -35
  25. data/lib/tasks/migrate.rake +3 -96
  26. data/lib/tasks/search.rake +6 -68
  27. data/lib/tasks/services.rake +4 -54
  28. data/lib/workarea/configuration.rb +11 -2
  29. data/lib/workarea/configuration/administrable_options.rb +1 -5
  30. data/lib/workarea/core.rb +1 -0
  31. data/lib/workarea/core/engine.rb +4 -0
  32. data/lib/workarea/ext/jbuilder/jbuilder_cache.rb +29 -0
  33. data/lib/workarea/tasks/cache.rb +43 -0
  34. data/lib/workarea/tasks/help.rb +55 -0
  35. data/lib/workarea/tasks/insights.rb +47 -0
  36. data/lib/workarea/tasks/migrate.rb +106 -0
  37. data/lib/workarea/tasks/search.rb +105 -0
  38. data/lib/workarea/tasks/services.rb +71 -0
  39. data/lib/workarea/version.rb +1 -1
  40. data/test/generators/workarea/install_generator_test.rb +6 -2
  41. data/test/mailers/workarea/application_mailer_test.rb +10 -0
  42. data/test/models/workarea/checkout_test.rb +57 -0
  43. data/test/models/workarea/data_file/import_test.rb +40 -0
  44. data/test/models/workarea/search/storefront/category_query_test.rb +11 -0
  45. data/test/queries/workarea/search/admin_search_test.rb +10 -0
  46. data/test/services/workarea/index_release_schedule_previews_test.rb +28 -0
  47. data/test/workers/workarea/{reindex_release_test.rb → index_release_schedule_change_test.rb} +30 -4
  48. data/test/workers/workarea/publish_release_test.rb +24 -0
  49. data/workarea-core.gemspec +2 -2
  50. metadata +17 -8
  51. data/app/workers/workarea/reindex_release.rb +0 -42
@@ -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 = 13
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,5 +79,11 @@ module Workarea
81
79
  def test_favicon
82
80
  assert_no_file 'public/favicon.ico'
83
81
  end
82
+
83
+ def test_development_mailer_port
84
+ assert_file 'config/environments/development.rb' do |file|
85
+ assert_match(%(config.action_mailer.default_url_options = { port: 3000 }), file)
86
+ end
87
+ end
84
88
  end
85
89
  end
@@ -21,5 +21,15 @@ module Workarea
21
21
  assert_equal([changed_email], changed_mail.from)
22
22
  end
23
23
  end
24
+
25
+ def test_default_url_options
26
+ @current_options = Rails.application.config.action_mailer.default_url_options.deep_dup
27
+ Rails.application.config.action_mailer.default_url_options = { port: 12345 }
28
+
29
+ assert_equal(12345, ApplicationMailer.new.default_url_options[:port])
30
+
31
+ ensure
32
+ Rails.application.config.action_mailer.default_url_options = @current_options
33
+ end
24
34
  end
25
35
  end
@@ -51,6 +51,63 @@ module Workarea
51
51
  refute_equal(payment_id, checkout.payment.object_id)
52
52
  end
53
53
 
54
+ def test_update
55
+ create_shipping_service
56
+ checkout = Checkout.new(@order)
57
+
58
+ checkout.start_as(:guest)
59
+
60
+ refute(
61
+ checkout.update(
62
+ email: 'test@workarea.com',
63
+ shipping_address: {
64
+ last_name: 'Crouse',
65
+ street: '22 S. 3rd St.',
66
+ street_2: 'Second Floor',
67
+ city: 'Philadelphia',
68
+ region: 'PA',
69
+ postal_code: '19106',
70
+ country: 'US'
71
+ },
72
+ billing_address: {
73
+ first_name: 'Ben',
74
+ street: '22 S. 3rd St.',
75
+ street_2: 'Second Floor',
76
+ city: 'Philadelphia',
77
+ region: 'PA',
78
+ postal_code: '19106',
79
+ country: 'US'
80
+ }
81
+ )
82
+ )
83
+
84
+ assert(
85
+ checkout.update(
86
+ email: 'test@workarea.com',
87
+ shipping_address: {
88
+ first_name: 'Ben',
89
+ last_name: 'Crouse',
90
+ street: '22 S. 3rd St.',
91
+ street_2: 'Second Floor',
92
+ city: 'Philadelphia',
93
+ region: 'PA',
94
+ postal_code: '19106',
95
+ country: 'US'
96
+ },
97
+ billing_address: {
98
+ first_name: 'Ben',
99
+ last_name: 'Crouse',
100
+ street: '22 S. 3rd St.',
101
+ street_2: 'Second Floor',
102
+ city: 'Philadelphia',
103
+ region: 'PA',
104
+ postal_code: '19106',
105
+ country: 'US'
106
+ }
107
+ )
108
+ )
109
+ end
110
+
54
111
  def test_continue_as
55
112
  checkout = Checkout.new(@order)
56
113
  checkout.continue_as(@user)