shoperb-theme-editor 0.8.0

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +40 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +124 -0
  5. data/bin/shoperb +313 -0
  6. data/lib/shoperb_theme_editor/api/server.rb +10 -0
  7. data/lib/shoperb_theme_editor/api/views/callback.erb +53 -0
  8. data/lib/shoperb_theme_editor/api.rb +264 -0
  9. data/lib/shoperb_theme_editor/build/json.rb +167 -0
  10. data/lib/shoperb_theme_editor/build/liquid.rb +38 -0
  11. data/lib/shoperb_theme_editor/build/section.rb +51 -0
  12. data/lib/shoperb_theme_editor/build/settings.rb +224 -0
  13. data/lib/shoperb_theme_editor/build.rb +68 -0
  14. data/lib/shoperb_theme_editor/configuration.rb +98 -0
  15. data/lib/shoperb_theme_editor/error.rb +35 -0
  16. data/lib/shoperb_theme_editor/ext/array.rb +17 -0
  17. data/lib/shoperb_theme_editor/ext/nil_class.rb +7 -0
  18. data/lib/shoperb_theme_editor/ext/sequel.rb +82 -0
  19. data/lib/shoperb_theme_editor/ext.rb +2 -0
  20. data/lib/shoperb_theme_editor/init.rb +87 -0
  21. data/lib/shoperb_theme_editor/logger.rb +58 -0
  22. data/lib/shoperb_theme_editor/mounter/models/address.rb +65 -0
  23. data/lib/shoperb_theme_editor/mounter/models/attribute.rb +11 -0
  24. data/lib/shoperb_theme_editor/mounter/models/attribute_key.rb +17 -0
  25. data/lib/shoperb_theme_editor/mounter/models/base.rb +196 -0
  26. data/lib/shoperb_theme_editor/mounter/models/blog_category.rb +47 -0
  27. data/lib/shoperb_theme_editor/mounter/models/blog_post.rb +45 -0
  28. data/lib/shoperb_theme_editor/mounter/models/brand.rb +11 -0
  29. data/lib/shoperb_theme_editor/mounter/models/cart.rb +35 -0
  30. data/lib/shoperb_theme_editor/mounter/models/cart_item.rb +71 -0
  31. data/lib/shoperb_theme_editor/mounter/models/category.rb +99 -0
  32. data/lib/shoperb_theme_editor/mounter/models/collection.rb +40 -0
  33. data/lib/shoperb_theme_editor/mounter/models/country.rb +18 -0
  34. data/lib/shoperb_theme_editor/mounter/models/currency.rb +17 -0
  35. data/lib/shoperb_theme_editor/mounter/models/custom_field.rb +22 -0
  36. data/lib/shoperb_theme_editor/mounter/models/customer.rb +77 -0
  37. data/lib/shoperb_theme_editor/mounter/models/customer_customer_group.rb +12 -0
  38. data/lib/shoperb_theme_editor/mounter/models/customer_group.rb +13 -0
  39. data/lib/shoperb_theme_editor/mounter/models/customer_subscription.rb +40 -0
  40. data/lib/shoperb_theme_editor/mounter/models/customer_subscription_plan.rb +32 -0
  41. data/lib/shoperb_theme_editor/mounter/models/discount.rb +40 -0
  42. data/lib/shoperb_theme_editor/mounter/models/discount_variant.rb +15 -0
  43. data/lib/shoperb_theme_editor/mounter/models/image.rb +51 -0
  44. data/lib/shoperb_theme_editor/mounter/models/language.rb +17 -0
  45. data/lib/shoperb_theme_editor/mounter/models/link.rb +61 -0
  46. data/lib/shoperb_theme_editor/mounter/models/media_file.rb +19 -0
  47. data/lib/shoperb_theme_editor/mounter/models/menu.rb +21 -0
  48. data/lib/shoperb_theme_editor/mounter/models/meta.rb +10 -0
  49. data/lib/shoperb_theme_editor/mounter/models/news_item.rb +11 -0
  50. data/lib/shoperb_theme_editor/mounter/models/order.rb +133 -0
  51. data/lib/shoperb_theme_editor/mounter/models/order_item.rb +137 -0
  52. data/lib/shoperb_theme_editor/mounter/models/order_item_attribute.rb +17 -0
  53. data/lib/shoperb_theme_editor/mounter/models/order_return.rb +42 -0
  54. data/lib/shoperb_theme_editor/mounter/models/order_return_item.rb +29 -0
  55. data/lib/shoperb_theme_editor/mounter/models/order_return_item_entity.rb +25 -0
  56. data/lib/shoperb_theme_editor/mounter/models/order_return_parcel.rb +20 -0
  57. data/lib/shoperb_theme_editor/mounter/models/page.rb +26 -0
  58. data/lib/shoperb_theme_editor/mounter/models/payment_card.rb +21 -0
  59. data/lib/shoperb_theme_editor/mounter/models/payment_method.rb +67 -0
  60. data/lib/shoperb_theme_editor/mounter/models/payment_provider.rb +23 -0
  61. data/lib/shoperb_theme_editor/mounter/models/product.rb +144 -0
  62. data/lib/shoperb_theme_editor/mounter/models/product_attribute.rb +32 -0
  63. data/lib/shoperb_theme_editor/mounter/models/product_search.rb +53 -0
  64. data/lib/shoperb_theme_editor/mounter/models/product_type.rb +21 -0
  65. data/lib/shoperb_theme_editor/mounter/models/review.rb +38 -0
  66. data/lib/shoperb_theme_editor/mounter/models/search.rb +11 -0
  67. data/lib/shoperb_theme_editor/mounter/models/shipping_method.rb +39 -0
  68. data/lib/shoperb_theme_editor/mounter/models/shop.rb +58 -0
  69. data/lib/shoperb_theme_editor/mounter/models/state.rb +17 -0
  70. data/lib/shoperb_theme_editor/mounter/models/theme.rb +89 -0
  71. data/lib/shoperb_theme_editor/mounter/models/variant.rb +96 -0
  72. data/lib/shoperb_theme_editor/mounter/models/variant_attribute.rb +46 -0
  73. data/lib/shoperb_theme_editor/mounter/models/vendor.rb +38 -0
  74. data/lib/shoperb_theme_editor/mounter/server/assets.rb +35 -0
  75. data/lib/shoperb_theme_editor/mounter/server/defaults.rb +44 -0
  76. data/lib/shoperb_theme_editor/mounter/server/exception_handler.rb +22 -0
  77. data/lib/shoperb_theme_editor/mounter/server/partials/_shoperb_footer.liquid +0 -0
  78. data/lib/shoperb_theme_editor/mounter/server/partials/_shoperb_header.liquid +0 -0
  79. data/lib/shoperb_theme_editor/mounter/server/partials/_shoperb_stylesheets.liquid +3 -0
  80. data/lib/shoperb_theme_editor/mounter/server/renderer.rb +166 -0
  81. data/lib/shoperb_theme_editor/mounter/server/routes/cart.rb +127 -0
  82. data/lib/shoperb_theme_editor/mounter/server/routes/dummy.rb +34 -0
  83. data/lib/shoperb_theme_editor/mounter/server/routes/locale.rb +31 -0
  84. data/lib/shoperb_theme_editor/mounter/server/routes/pages.rb +33 -0
  85. data/lib/shoperb_theme_editor/mounter/server/routes/search.rb +18 -0
  86. data/lib/shoperb_theme_editor/mounter/server/routes.rb +366 -0
  87. data/lib/shoperb_theme_editor/mounter/server/routes_helper.rb +278 -0
  88. data/lib/shoperb_theme_editor/mounter/server.rb +66 -0
  89. data/lib/shoperb_theme_editor/mounter.rb +30 -0
  90. data/lib/shoperb_theme_editor/os.rb +13 -0
  91. data/lib/shoperb_theme_editor/package.rb +81 -0
  92. data/lib/shoperb_theme_editor/sync/images.rb +69 -0
  93. data/lib/shoperb_theme_editor/sync/pagination.rb +52 -0
  94. data/lib/shoperb_theme_editor/sync.rb +229 -0
  95. data/lib/shoperb_theme_editor/translations.rb +22 -0
  96. data/lib/shoperb_theme_editor/utils.rb +50 -0
  97. data/lib/shoperb_theme_editor.rb +159 -0
  98. data/shoperb_theme_editor.gemspec +60 -0
  99. metadata +510 -0
@@ -0,0 +1,166 @@
1
+ module Tilt
2
+ class LiquidTemplate
3
+ def evaluate scope, context, *args, &block
4
+ @engine.render(context)
5
+ end
6
+ end
7
+ end
8
+ module Shoperb module Theme module Editor
9
+ module Mounter
10
+ class Server
11
+ module Renderer
12
+
13
+ module Helpers
14
+ def respond(templates, locals={}, registers={}, dir=settings.templates_directory, &block)
15
+ result = template_result(templates, locals, registers, dir)
16
+ format = Sinatra::RespondWith::Format.new(self)
17
+
18
+ halt result if result
19
+
20
+ format.finish(&block)
21
+ end
22
+
23
+ def content_for_template(template, locals, registers)
24
+ settings_data = Shoperb::Theme::Editor.settings_data
25
+ return nil unless settings_data && settings_data["content_for_#{template}"]
26
+
27
+ section_ids = settings_data["content_for_#{template}"]
28
+
29
+ section_ids.map do |id|
30
+ data = settings_data['sections'][id]
31
+ file = template_path(data['type'], settings.sections_directory)
32
+ section_drop = ShoperbLiquid::ThemeSectionDrop.new(id, data)
33
+ process_file(file, locals.merge(section: section_drop), registers)
34
+ end.join(' ')
35
+ end
36
+
37
+ def respond_email(templates, locals={}, registers={}, &block)
38
+ respond(templates, locals, {layout:nil}.reverse_merge(registers), settings.emails_directory, &block)
39
+ end
40
+
41
+ def process_file file, locals, registers
42
+ file = Pathname.new(file)
43
+ result = File.read(file).force_encoding("UTF-8").gsub("\xC2\xA0", " ")
44
+ if result.start_with?("---\n")
45
+ result = result.split("---\n")[2] # taking only meaning part
46
+ end
47
+
48
+ while (ext = file.extname.gsub(".", "")).to_sym != settings.destination_format
49
+ file = Pathname.new(file.to_s.gsub(".#{ext}", ""))
50
+ result = send(ext, result)
51
+ end
52
+
53
+ Liquid::Template.parse(result).render!(locals.stringify_keys!, :registers => registers)
54
+ end
55
+
56
+ def template_result(templates, locals={}, registers={}, dir=settings.templates_directory)
57
+ locals, registers = registers_and_locals(locals, registers)
58
+ templates = [templates] unless templates.kind_of?(Array)
59
+ if (template = @template = template_name(templates, dir))
60
+ locals.merge!(template_name: template.to_s)
61
+ locals[:content_for_template] = content_for_template(template.to_s, locals, registers)
62
+
63
+ file = template_path(template, dir)
64
+ result = process_file(file, locals, registers)
65
+ unless (layout_name = registers[:layout].to_s).blank?
66
+ result = process_file(template_path(layout_name, settings.layouts_directory), locals.merge(content_for_layout: result), registers)
67
+ end
68
+ result
69
+ end
70
+ end
71
+ attr_reader :template
72
+
73
+ def registers_and_locals locals={}, registers={}
74
+ registers.reverse_merge!(
75
+ controller: self,
76
+ locale: Translations.locale,
77
+ shop: shop,
78
+ theme: Mounter::Model::Theme.new,
79
+ request_forgery_protection_token: -> { %(<input type="hidden" name="" value="">) }
80
+ )
81
+
82
+ [
83
+ locals.reverse_merge(default_locals),
84
+ registers.reverse_merge({layout: "layout"})
85
+ ]
86
+ end
87
+
88
+ def template_path name, base=settings.templates_directory
89
+ template_paths(name, base).first
90
+ end
91
+
92
+ def template_name names, base=settings.templates_directory
93
+ names.detect { |name| template_paths(name, base).any? }
94
+ end
95
+
96
+ def template_paths name, base=settings.templates_directory
97
+ Dir[base.to_s + "/" + name.to_s + ".#{settings.destination_format}" + "{#{settings.allowed_engines.map { |ext_name| ".#{ext_name}" }.join(",")},}"]
98
+ end
99
+ end
100
+
101
+ def self.registered app
102
+ app.register Sinatra::RespondWith
103
+ app.helpers Helpers
104
+ app.set :templates_directory, Proc.new { File.join(root, "templates") }
105
+ app.set :sections_directory, Proc.new { File.join(root, "sections") }
106
+ app.set :layouts_directory, Proc.new { File.join(root, "layouts") }
107
+ app.set :emails_directory, Proc.new { File.join(root, "emails") }
108
+
109
+ app.set :destination_format, :liquid
110
+ app.set :allowed_engines, [:haml]
111
+
112
+ ShoperbLiquid.configure do |config|
113
+ config.translator = Translations
114
+ config.environment = :theme_development
115
+ config.models_namespace = Mounter::Model
116
+ config.routes = Mounter::Server::RoutesHelper
117
+ config.file_system = FileReader.new
118
+ config.error_mode = :strict
119
+ end
120
+ end
121
+
122
+ class FileReader
123
+ def read_template_file(path)
124
+ templates_file_reader.read_template_file(path) rescue
125
+ shared_templates_reader.read_template_file(path)
126
+ end
127
+
128
+ def read_section_file(path)
129
+ sections_file_reader.read_template_file(path)
130
+ end
131
+
132
+ def read_asset_file(path)
133
+ assets_file_reader.read_template_file(path)
134
+ end
135
+
136
+ def absolute_asset_path(path)
137
+ path = path.gsub(/^\//, '')
138
+ "/system/assets/#{path}"
139
+ end
140
+
141
+ private
142
+
143
+ def sections_file_reader
144
+ ::Liquid::LocalFileSystem.new(File.join(root, "sections"), "%s.liquid")
145
+ end
146
+
147
+ def templates_file_reader
148
+ ::Liquid::LocalFileSystem.new(File.join(root, "templates"))
149
+ end
150
+
151
+ def shared_templates_reader
152
+ ::Liquid::LocalFileSystem.new(Pathname.new(__FILE__).join("../partials"), "_%s.liquid")
153
+ end
154
+
155
+ def assets_file_reader
156
+ ::Liquid::LocalFileSystem.new(File.join(root, "assets"))
157
+ end
158
+
159
+ def root
160
+ Dir.pwd
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end end end
@@ -0,0 +1,127 @@
1
+ module Shoperb module Theme module Editor
2
+ module Mounter
3
+ class Server
4
+ module Routes
5
+ module Cart
6
+ def self.registered(app)
7
+ app.helpers do
8
+ include ::ActionView::Helpers::NumberHelper
9
+
10
+ def cart_json(cart)
11
+ json = { }
12
+
13
+ json[:count] = cart.items.count
14
+ json[:total] = number_with_precision(cart.total, :precision => 2)
15
+ json[:weight] = number_with_precision(cart.weight, :precision => 2)
16
+ json[:requires_shipping] = cart.require_shipping?
17
+
18
+ json[:items] = cart.items.map do |item|
19
+ {:id => item.id,
20
+ :sku => item.sku,
21
+ :name => item.variant.name,
22
+ :handle => item.product.handle,
23
+ :permalink => item.product.permalink,
24
+ :price => number_with_precision(item.variant.active_price, :precision => 2),
25
+ :weight => number_with_precision(item.variant.weight, :precision => 2),
26
+ :quantity => item.amount,
27
+ :total => number_with_precision(item.total, :precision => 2),
28
+ :product => item.product.name,
29
+ :variant_id => item.variant.id,
30
+ :product_id => item.product.id,
31
+ :requires_taxing => item.variant.charge_taxes?,
32
+ :requires_shipping => item.variant.require_shipping?,
33
+ :dimensions => {
34
+ :width => number_with_precision(item.variant.width, :precision => 2),
35
+ :height => number_with_precision(item.variant.height, :precision => 2),
36
+ :depth => number_with_precision(item.variant.depth, :precision => 2)
37
+ },
38
+ :attributes => {
39
+ :product => item.product.product_attributes.map do |attribute|
40
+ [attribute.handle, { name: attribute.name, value: attribute.value }]
41
+ end.to_h,
42
+ :variant => item.variant.variant_attributes.map do |attribute|
43
+ [attribute.handle, { name: attribute.name, value: attribute.value }]
44
+ end.to_h
45
+ }
46
+ }
47
+ end
48
+
49
+ if Array(params[:include]).include?("liquid")
50
+ json[:liquid] = template_result(:cart, {}, {layout:nil})
51
+ end
52
+
53
+ json
54
+ end
55
+ end
56
+
57
+ app.post "/cart/checkout" do
58
+ redirect "/cart"
59
+ end
60
+
61
+ app.post "/cart/add" do
62
+ by_subscription = %w(1 true).include?(params[:by_subscription])
63
+ variant_id = params[:variant].to_i
64
+ amount = params[:amount].to_i
65
+
66
+ cart = current_cart
67
+
68
+ cart.token ||= SecureRandom.hex(12)
69
+
70
+ item = Model::CartItem.where(variant_id: variant_id, by_subscription: by_subscription).first || Model::CartItem.new(variant_id: variant_id, by_subscription: by_subscription)
71
+ item.amount ||= 0
72
+ item.amount += amount
73
+
74
+ # to add more variants
75
+ params[:other].each do |key, pars|
76
+ variant_id2 = key.to_i
77
+ amount2 = pars[:amount].to_i
78
+ item_original_id2 = pars[:item_original_id]
79
+ by_subscription2 = %w(1 true).include?(pars[:by_subscription])
80
+ item2 = Model::CartItem.where(variant_id: variant_id2, by_subscription: by_subscription2).first || Model::CartItem.new(variant_id: variant_id2, by_subscription: by_subscription2)
81
+ item2.amount ||= 0
82
+ item2.amount += amount2
83
+ end if params[:other].present?
84
+
85
+
86
+ item.save
87
+ cart.save
88
+
89
+ respond_to do |f|
90
+ f.json { json(cart_json(current_cart)) }
91
+ f.html { redirect "/cart" }
92
+ end
93
+ end
94
+
95
+ app.post "/cart/update" do
96
+ cart = current_cart
97
+ params[:update].each do |item, amount|
98
+ item = cart.items.where(id: item.to_i).first
99
+ item.amount = amount.to_i
100
+ item.save
101
+ end if params[:update]
102
+
103
+ respond_to do |f|
104
+ f.json { json(cart_json(current_cart)) }
105
+ f.html { redirect "/cart" }
106
+ end
107
+ end
108
+
109
+ app.post "/cart" do
110
+ params[:update].each do |id, amount|
111
+ Model::CartItem.find(id: id.to_i).tap do |item|
112
+ item.amount = amount.to_i
113
+ item.save
114
+ end
115
+ end
116
+
117
+ respond_to do |f|
118
+ f.json { json(cart_json(current_cart)) }
119
+ f.html { redirect "/cart" }
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end end end
@@ -0,0 +1,34 @@
1
+ module Shoperb module Theme module Editor
2
+ module Mounter
3
+ class Server
4
+ module Routes
5
+ module Dummy
6
+
7
+ def self.registered(app)
8
+
9
+ app.post "/cart/checkout" do
10
+ redirect "/cart"
11
+ end
12
+
13
+ cart_response = -> {
14
+ respond_to do |f|
15
+ f.json { respond :cart, params, layout: "" }
16
+ f.html { redirect "/cart" }
17
+ end
18
+ }
19
+
20
+
21
+ app.post "/cart", &cart_response
22
+
23
+ app.post "/cart/add", &cart_response
24
+
25
+ app.get "/search" do
26
+ respond :search
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end end end
@@ -0,0 +1,31 @@
1
+ module Shoperb module Theme module Editor
2
+ module Mounter
3
+ class Server
4
+ module Routes
5
+ module Locale
6
+
7
+ module Helpers
8
+ def get_locale
9
+ if shop.all_languages.any? && request.path_info=~(/\A\/(#{shop.all_languages.join("|")})(\/.*)?/)
10
+ request.path_info = $2 || ""
11
+ $1
12
+ elsif shop.language_code
13
+ shop.language_code
14
+ else
15
+ shop.all_languages.first
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.registered(app)
21
+ app.helpers Helpers
22
+ app.before "*" do
23
+ Translations.locale = get_locale
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end end end
@@ -0,0 +1,33 @@
1
+ module Shoperb module Theme module Editor
2
+ module Mounter
3
+ class Server
4
+ module Routes
5
+ module Pages
6
+
7
+ class PageFinder
8
+ def self.match str
9
+ !!Model::Page.all.detect { |p| "/#{p.permalink}" == str }
10
+ end
11
+ def self.serve
12
+ ->(id) {
13
+ page = Model::Page.all.detect { |p| p.permalink == id }
14
+ respond (page.template.presence&.to_sym || :page), page: page.to_liquid
15
+ }
16
+ end
17
+ end
18
+
19
+
20
+
21
+ def self.registered(app)
22
+ app.get "/pages/:id/?", &PageFinder.serve
23
+ app.get "/:id/?" do
24
+ pass if !PageFinder.match(params[:id])
25
+ PageFinder.serve(params[:id])
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end end end
@@ -0,0 +1,18 @@
1
+ module Shoperb module Theme module Editor
2
+ module Mounter
3
+ class Server
4
+ module Routes
5
+ module Search
6
+
7
+ def self.registered(app)
8
+
9
+ app.get "/search" do
10
+ respond :search
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end end end