web-connect 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +1 -0
- data/Rakefile +3 -0
- data/lib/netfira/web_connect/components/checksum.rb +19 -0
- data/lib/netfira/web_connect/components/guid.rb +11 -0
- data/lib/netfira/web_connect/components/octa_word.rb +73 -0
- data/lib/netfira/web_connect/components.rb +1 -0
- data/lib/netfira/web_connect/configuration.rb +33 -0
- data/lib/netfira/web_connect/db_schema/20140514_support.rb +38 -0
- data/lib/netfira/web_connect/db_schema/20140515_alpha.rb +106 -0
- data/lib/netfira/web_connect/events.rb +14 -0
- data/lib/netfira/web_connect/migration/base_methods.rb +59 -0
- data/lib/netfira/web_connect/migration/refinements.rb +16 -0
- data/lib/netfira/web_connect/migration.rb +101 -0
- data/lib/netfira/web_connect/model/record/digests.rb +24 -0
- data/lib/netfira/web_connect/model/record/events.rb +35 -0
- data/lib/netfira/web_connect/model/record/file_record.rb +79 -0
- data/lib/netfira/web_connect/model/record/materialization.rb +59 -0
- data/lib/netfira/web_connect/model/record/relations.rb +51 -0
- data/lib/netfira/web_connect/model/record/sendable.rb +29 -0
- data/lib/netfira/web_connect/model/record/serializer.rb +56 -0
- data/lib/netfira/web_connect/model/record/translated_string.rb +42 -0
- data/lib/netfira/web_connect/model/record/translation.rb +58 -0
- data/lib/netfira/web_connect/model/record/translations.rb +63 -0
- data/lib/netfira/web_connect/model/record/tree.rb +13 -0
- data/lib/netfira/web_connect/model/record.rb +132 -0
- data/lib/netfira/web_connect/model/relation/events.rb +34 -0
- data/lib/netfira/web_connect/model/relation.rb +67 -0
- data/lib/netfira/web_connect/model/support.rb +13 -0
- data/lib/netfira/web_connect/model.rb +33 -0
- data/lib/netfira/web_connect/models/image.rb +48 -0
- data/lib/netfira/web_connect/models/order.rb +5 -0
- data/lib/netfira/web_connect/models/order_line.rb +13 -0
- data/lib/netfira/web_connect/models/support/setting.rb +31 -0
- data/lib/netfira/web_connect/models/support/shop/settings.rb +42 -0
- data/lib/netfira/web_connect/models/support/shop.rb +22 -0
- data/lib/netfira/web_connect/models/support/table.rb +5 -0
- data/lib/netfira/web_connect/models.rb +73 -0
- data/lib/netfira/web_connect/rack_app/action.rb +66 -0
- data/lib/netfira/web_connect/rack_app/action_helpers/data_types.rb +22 -0
- data/lib/netfira/web_connect/rack_app/action_helpers/env_importer.rb +59 -0
- data/lib/netfira/web_connect/rack_app/action_helpers/env_methods.rb +23 -0
- data/lib/netfira/web_connect/rack_app/actions/version_1/not_supported.rb +11 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/checksums.rb +14 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/commit/records.rb +45 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/commit/relations.rb +48 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/commit.rb +33 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/files.rb +21 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/info.rb +18 -0
- data/lib/netfira/web_connect/rack_app/actions/version_8/settings.rb +79 -0
- data/lib/netfira/web_connect/rack_app/exceptions/http_exception.rb +44 -0
- data/lib/netfira/web_connect/rack_app/exceptions.rb +6 -0
- data/lib/netfira/web_connect/rack_app.rb +56 -0
- data/lib/netfira/web_connect/request_filter.rb +66 -0
- data/lib/netfira/web_connect/schema/table.rb +58 -0
- data/lib/netfira/web_connect/schema.rb +22 -0
- data/lib/netfira/web_connect/version.rb +5 -0
- data/lib/netfira/web_connect.rb +82 -0
- data/lib/netfira.rb +10 -0
- data/lib/web_connect.rb +1 -0
- metadata +246 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'active_support/core_ext/object/deep_dup'
|
3
|
+
|
4
|
+
module Netfira::WebConnect
|
5
|
+
class Models::Shop::Settings
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def initialize(proxy)
|
9
|
+
@proxy = proxy
|
10
|
+
@models = proxy.map{ |model| [model.key.to_sym, model] }.to_h
|
11
|
+
@hash = @models.map{ |key, model| [key, model.typed_value]}.to_h
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
@hash[key.to_sym]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
key = key.to_sym
|
20
|
+
model = @models[key] ||= @proxy.new(key: key.to_s)
|
21
|
+
model.typed_value = value
|
22
|
+
model.save!
|
23
|
+
@hash[key] = value
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
@hash.deep_dup
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(key)
|
31
|
+
key = key.to_sym
|
32
|
+
return false unless @models[key]
|
33
|
+
@models[key].destroy!
|
34
|
+
@models.delete key
|
35
|
+
@hash.delete key
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
delegate [:count, :length, :size, :each, :map] => :@hash
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Netfira::WebConnect
|
2
|
+
class Models::Shop < Model::Support
|
3
|
+
|
4
|
+
has_many :setting_models, class_name: Models::Setting.name, inverse_of: :shop
|
5
|
+
|
6
|
+
def settings
|
7
|
+
@settings ||= Settings.new(setting_models)
|
8
|
+
end
|
9
|
+
|
10
|
+
def reload
|
11
|
+
@settings = nil
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def locale
|
16
|
+
settings[:locale] || Netfira::WebConnect.system_locale
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require_relative 'shop/settings'
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module Netfira::WebConnect
|
4
|
+
module Models
|
5
|
+
|
6
|
+
def self.materialize
|
7
|
+
|
8
|
+
# Scrap any existing definitions
|
9
|
+
Models.constants.each do |name|
|
10
|
+
klass = Models.const_get(name)
|
11
|
+
Models.__send__ :remove_const, name if klass < Model::Record || klass < Model::Relation
|
12
|
+
end
|
13
|
+
|
14
|
+
# Load pre-defined models
|
15
|
+
Dir[File.expand_path('../models/*.rb', __FILE__)].each { |p| load p }
|
16
|
+
|
17
|
+
table_names = []
|
18
|
+
tables_to_localize = []
|
19
|
+
tables_to_relate = []
|
20
|
+
|
21
|
+
Model.connection.tables.reject{|x| x == Netfira::WebConnect.schema_migrations_table_name }.each do |table_name|
|
22
|
+
unprefixed_table_name = unprefix_table_name(table_name)
|
23
|
+
if unprefixed_table_name.nil? or unprefixed_table_name[0] == '_'
|
24
|
+
next
|
25
|
+
elsif l10n_table_name? table_name
|
26
|
+
tables_to_localize << l10n_table_owner_name(unprefixed_table_name)
|
27
|
+
elsif unprefixed_table_name =~ /\A(.+)_to_(.+)\z/
|
28
|
+
tables_to_relate << [$1, $2]
|
29
|
+
else
|
30
|
+
table_names << unprefixed_table_name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
table_props = Models::Table.all.map{ |model| [model.name, model] }.to_h
|
35
|
+
|
36
|
+
table_names.each do |name|
|
37
|
+
props = table_props[name]
|
38
|
+
next unless props
|
39
|
+
Model::Record.materialize name.camelize.singularize,
|
40
|
+
tables_to_localize.include?(name),
|
41
|
+
props
|
42
|
+
end
|
43
|
+
|
44
|
+
tables_to_relate.each do |names|
|
45
|
+
Model::Relation.materialize *names.map{ |x| x.camelize.singularize }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self.unprefix_table_name(name)
|
53
|
+
return unless name.starts_with? Netfira::WebConnect.db_table_prefix.to_s
|
54
|
+
@prefix_range ||= (Netfira::WebConnect.db_table_prefix.length)..-1
|
55
|
+
name[@prefix_range]
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.l10n_table_name?(name)
|
59
|
+
@l10n_suffix ||= Netfira::WebConnect.db_table_l10n_suffix.to_s
|
60
|
+
@l10n_suffix_range ||= (-@l10n_suffix.length)..-1
|
61
|
+
@l10n_suffix == name[@l10n_suffix_range]
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.l10n_table_owner_name(name)
|
65
|
+
name[@l10n_table_name_range ||= 0..(-@l10n_suffix.length - 1)] if l10n_table_name? name
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
require_relative 'models/support/setting'
|
72
|
+
require_relative 'models/support/shop'
|
73
|
+
require_relative 'models/support/table'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'active_support/hash_with_indifferent_access'
|
3
|
+
|
4
|
+
#todo needs comment
|
5
|
+
module Netfira::WebConnect
|
6
|
+
class RackApp::Action
|
7
|
+
include RackApp::Exceptions::HttpExceptions
|
8
|
+
|
9
|
+
def self.action_classes
|
10
|
+
@action_classes ||= find_action_classes
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.latest_version
|
14
|
+
@latest_version ||= action_classes.keys.max
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.create(action, version = nil)
|
18
|
+
version ||= latest_version
|
19
|
+
klass = nil
|
20
|
+
until klass or version < 1
|
21
|
+
klass = (action_classes[version] || {})[action] # todo needs explination or to be rewritten to be easily readable
|
22
|
+
version -= 1
|
23
|
+
end
|
24
|
+
klass and klass.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@headers = ActiveSupport::HashWithIndifferentAccess.new
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.find_action_classes
|
34
|
+
action_classes = {}
|
35
|
+
|
36
|
+
# Loop through all constants in this class's namespace
|
37
|
+
constants.each do |constant|
|
38
|
+
|
39
|
+
# Match Version# constants (modules containing actions)
|
40
|
+
if constant =~ /\AVersion(\d+)\z/
|
41
|
+
|
42
|
+
# The module containing the actions
|
43
|
+
mod = const_get(constant)
|
44
|
+
|
45
|
+
# A hash of actions, e.g. :commit => Action::Version8::Commit
|
46
|
+
action_classes[$1.to_i] = Hash[mod.constants.map do |name|
|
47
|
+
mod.const_get(name)
|
48
|
+
end.select do |klass|
|
49
|
+
klass < self
|
50
|
+
end.map do |klass|
|
51
|
+
[klass.name.demodulize.underscore.to_sym, klass]
|
52
|
+
end]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
action_classes
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Load action helpers
|
63
|
+
Dir[File.expand_path('../action_helpers/*.rb', __FILE__)].each{ |f| require f }
|
64
|
+
|
65
|
+
# Pre load all action classes in all versions
|
66
|
+
Dir[File.expand_path('../actions/version_*/*.rb', __FILE__)].each{ |f| require f }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Netfira::WebConnect
|
2
|
+
class RackApp::Action
|
3
|
+
|
4
|
+
def class_for_record_type(type)
|
5
|
+
class_for_type type, Model::Record
|
6
|
+
end
|
7
|
+
|
8
|
+
def class_for_relation_type(type)
|
9
|
+
class_for_type type, Model::Relation
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def class_for_type(type, superclass)
|
15
|
+
raise BadRequest, 'No data type specified' if type.nil?
|
16
|
+
klass = Models.const_defined?(type) && Models.const_get(type)
|
17
|
+
raise BadRequest, 'Invalid or unknown data type' unless klass && klass < superclass
|
18
|
+
klass
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Netfira::WebConnect
|
2
|
+
class RackApp::Action
|
3
|
+
|
4
|
+
def import_env(env)
|
5
|
+
@env = env
|
6
|
+
|
7
|
+
# Parse the environment
|
8
|
+
request = Rack::Request.new env
|
9
|
+
|
10
|
+
# Authentication
|
11
|
+
authenticator = Netfira::WebConnect.authenticator
|
12
|
+
if authenticator.respond_to? :call
|
13
|
+
shop_name = env['HTTP_X_SHOP_NAME']
|
14
|
+
password = request['pw'] || env['HTTP_X_PASSWORD']
|
15
|
+
|
16
|
+
# Basic auth
|
17
|
+
auth = Rack::Auth::Basic::Request.new(env)
|
18
|
+
if auth.provided? && auth.basic?
|
19
|
+
shop_name ||= auth.username
|
20
|
+
password ||= auth.credentials[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
result = authenticator.call shop_name, password
|
24
|
+
raise Unauthorized unless result
|
25
|
+
header :x_vary_password, result if String === result
|
26
|
+
@shop = Netfira::WebConnect::Models::Shop.find_or_create_by(name: shop_name)
|
27
|
+
|
28
|
+
elsif authenticator.nil?
|
29
|
+
@shop = Netfira::WebConnect.anonymous_shop
|
30
|
+
else
|
31
|
+
raise 'Authenticator is not callable'
|
32
|
+
end
|
33
|
+
|
34
|
+
# The request verb (PUT, GET, POST etc)
|
35
|
+
@verb = request.request_method.downcase.to_sym
|
36
|
+
|
37
|
+
# Query string
|
38
|
+
@query_string = request.GET
|
39
|
+
|
40
|
+
# The X-Timeout header
|
41
|
+
timeout = env['HTTP_X_TIMEOUT']
|
42
|
+
@timeout = timeout.to_i if timeout
|
43
|
+
|
44
|
+
# Path components
|
45
|
+
if env['PATH_INFO'] =~ /\A\/\d+\/[^\/]+\/(.+)\z/
|
46
|
+
@path = $1.split('/').map{ |x| Rack::Utils.unescape x }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Input
|
50
|
+
if put? or post?
|
51
|
+
@input = request.body
|
52
|
+
@input = StringIO.new(@input.read.unpack('m').first) if env['CONTENT_ENCODING'] == 'base64'
|
53
|
+
@input = JSON.parse @input.read if request.media_type == 'application/json'
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Netfira::WebConnect
|
2
|
+
class RackApp::Action
|
3
|
+
|
4
|
+
attr_reader :timeout, :input, :path, :verb, :shop, :headers, :query_string, :env
|
5
|
+
|
6
|
+
# This method sets a response header, e.g.header 'Content-Type', 'text/plain'
|
7
|
+
def header(name, value)
|
8
|
+
name = name.to_s.split(/[- _]/).map(&:capitalize).join('-').to_sym
|
9
|
+
if value
|
10
|
+
headers[name] = value
|
11
|
+
else
|
12
|
+
headers.delete name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# These methods tell you if a given verb was used, e.g. post?
|
17
|
+
%w[get post put delete].each do |verb|
|
18
|
+
define_method(:"#{verb}?") { self.verb.to_s == verb }
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Checksums < Action
|
4
|
+
def call
|
5
|
+
raise MethodNotAllowed unless get?
|
6
|
+
|
7
|
+
klass = class_for_record_type(query_string['type'])
|
8
|
+
checksums = klass.where(shop_id: shop.id).map{ |record| [record.origin_id, record.digest]}.to_h
|
9
|
+
|
10
|
+
{checksums: checksums}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Netfira::WebConnect
|
2
|
+
module RackApp::Action::Version8
|
3
|
+
class Commit
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def commit_records(records)
|
8
|
+
records.each do |class_name, attribute_sets|
|
9
|
+
klass = class_for_record_type(class_name)
|
10
|
+
attribute_sets.each do |attributes|
|
11
|
+
update_record klass, attributes
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_record(klass, attributes)
|
17
|
+
origin_key = attributes[klass.origin_key.to_s.camelize(:lower)]
|
18
|
+
raise BadRequest, "#{klass.name.demodulize} sent with no #{klass.origin_key}" unless origin_key
|
19
|
+
record = klass.find_or_initialize_by_origin_id(shop, origin_key)
|
20
|
+
attributes.each do |key, value|
|
21
|
+
key = key.underscore
|
22
|
+
next if key == origin_key
|
23
|
+
if key == 'checksum' && klass < Model::Record::FileRecord
|
24
|
+
request_file klass, attributes['fileName'] if record.checksum != value
|
25
|
+
next
|
26
|
+
end
|
27
|
+
record.write_with_type_casting(key.to_sym, value) or raise BadRequest, "#{klass.name.demodulize.pluralize} don't have #{key} fields"
|
28
|
+
end
|
29
|
+
record.save or raise InternalServerError, record.errors
|
30
|
+
complete_record record
|
31
|
+
end
|
32
|
+
|
33
|
+
def complete_record(record)
|
34
|
+
list = complete[:records][record.class.name.demodulize] ||= {}
|
35
|
+
list[record.origin_id.to_s] = record.digest
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_file(klass, file_name)
|
39
|
+
list = files_to_send[klass.name.demodulize] ||= []
|
40
|
+
list << file_name unless list.include? file_name
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Commit
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def commit_relations(relations)
|
8
|
+
relations.each do |class_name, relation_sets|
|
9
|
+
klass = class_for_relation_type class_name.sub('&', 'To')
|
10
|
+
relation_sets.each do |relation|
|
11
|
+
update_relation klass, relation
|
12
|
+
complete_relation class_name, relation
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_relation(klass, relation)
|
18
|
+
|
19
|
+
# Make a hash of models => IDs, e.g. {Product => '123', Image => 'file.jpg'}
|
20
|
+
origin_ids = [relation['a'], relation['b']].each_with_index.map do |origin_id, index|
|
21
|
+
[klass.related_classes[index], origin_id]
|
22
|
+
end.to_h
|
23
|
+
|
24
|
+
if relation['x']
|
25
|
+
relate_records origin_ids
|
26
|
+
else
|
27
|
+
unrelate_records origin_ids
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def relate_records(origin_ids)
|
32
|
+
records = origin_ids.map{ |k, id| k.find_or_create_by_origin_id shop, id }
|
33
|
+
records[0] << records[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
def unrelate_records(origin_ids)
|
37
|
+
records = origin_ids.map{ |k, id| k.find_by_origin_id shop, id }.reject(&:nil?)
|
38
|
+
records[0].delete records[1] if records.size == 2
|
39
|
+
end
|
40
|
+
|
41
|
+
def complete_relation(class_name, relation)
|
42
|
+
list = complete[:relations][class_name] ||= []
|
43
|
+
list << relation
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Commit < Action
|
4
|
+
|
5
|
+
def call
|
6
|
+
raise MethodNotAllowed unless verb == :post
|
7
|
+
commit_records input['records'] if input['records']
|
8
|
+
commit_relations input['relations'] if input['relations']
|
9
|
+
{
|
10
|
+
complete: complete,
|
11
|
+
filesToSend: files_to_send
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def files_to_send
|
18
|
+
@files_to_send ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def complete
|
22
|
+
@complete ||= {
|
23
|
+
records: {},
|
24
|
+
relations: {}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require_relative 'commit/records'
|
33
|
+
require_relative 'commit/relations'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Files < Action
|
4
|
+
def call
|
5
|
+
raise MethodNotAllowed unless post?
|
6
|
+
klass = class_for_record_type(path[0])
|
7
|
+
raise BadRequest, "You can't upload files for that data type" unless klass < Netfira::WebConnect::Model::Record::FileRecord
|
8
|
+
|
9
|
+
file_name = path[1]
|
10
|
+
raise BadRequest, 'You must specify a file name' unless file_name.length > 0
|
11
|
+
|
12
|
+
file = klass.find_or_initialize_by_origin_id(shop, file_name)
|
13
|
+
file << input
|
14
|
+
file.file_name = file_name
|
15
|
+
|
16
|
+
file.save or raise InternalServerError, file.errors
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Info < Action
|
4
|
+
def call
|
5
|
+
{
|
6
|
+
info: {
|
7
|
+
apiVersion: Action.latest_version,
|
8
|
+
libVersion: Netfira::WebConnect::VERSION,
|
9
|
+
schema: Netfira::WebConnect.schema,
|
10
|
+
customFields: false,
|
11
|
+
acceptableRequestTypes: env['WC_ACCEPTABLE_REQUEST_TYPES'] || ['unpacked'],
|
12
|
+
locale: shop.locale
|
13
|
+
}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Netfira::WebConnect::RackApp
|
2
|
+
module Action::Version8
|
3
|
+
class Settings < Action
|
4
|
+
def call
|
5
|
+
key = path && path.first
|
6
|
+
if key
|
7
|
+
handle_single key
|
8
|
+
else
|
9
|
+
handle_multiple
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def handle_single(key)
|
16
|
+
case verb
|
17
|
+
when :put, :post then update_single key
|
18
|
+
when :get then get_single key
|
19
|
+
when :delete then delete_single key
|
20
|
+
else raise MethodNotAllowed
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_single(key)
|
25
|
+
if input.respond_to? :read
|
26
|
+
setting = shop.setting_models.find_or_initialize_by(key: key)
|
27
|
+
setting.value = input.read
|
28
|
+
setting.content_type = env['CONTENT_TYPE'] || 'application/x-octet-stream'
|
29
|
+
setting.save
|
30
|
+
else
|
31
|
+
shop.settings[key] = input
|
32
|
+
end
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_single(key)
|
37
|
+
setting = shop.setting_models.find_by(key: key)
|
38
|
+
raise NotFound unless setting
|
39
|
+
# if setting.content_type == 'application/json'
|
40
|
+
# JSON.parse(setting.value, quirks_mode: true)
|
41
|
+
# else
|
42
|
+
header 'Content-Type', setting.content_type
|
43
|
+
setting.value
|
44
|
+
# end
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_single(key)
|
48
|
+
shop.setting_models.where(key: key).destroy_all
|
49
|
+
{}
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_multiple
|
53
|
+
case verb
|
54
|
+
when :put, :post then update_multiple
|
55
|
+
when :get then get_all
|
56
|
+
when :delete then delete_all
|
57
|
+
else raise MethodNotAllowed
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_multiple
|
62
|
+
input.each do |key, value|
|
63
|
+
shop.settings[key] = value.unpack('m').first
|
64
|
+
end
|
65
|
+
{}
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_all
|
69
|
+
{settings: shop.setting_models.map{ |model| [model.key, [model.value.b].pack('m0')] }.to_h}
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_all
|
73
|
+
shop.setting_models.destroy_all
|
74
|
+
{}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Netfira::WebConnect::RackApp::Exceptions
|
5
|
+
|
6
|
+
class HttpException < Base
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :status, :code, :category
|
11
|
+
attr_reader :headers
|
12
|
+
end
|
13
|
+
|
14
|
+
def_delegators :'self.class', :status, :code, :category
|
15
|
+
|
16
|
+
def initialize(*args, &block)
|
17
|
+
super *args, &block
|
18
|
+
@headers = self.class.headers.dup
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :headers
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
module HttpExceptions
|
26
|
+
|
27
|
+
Rack::Utils::HTTP_STATUS_CODES.each do |code, status|
|
28
|
+
next if status == 'Unassigned'
|
29
|
+
const_set status.gsub(/[ -](\w)/){$1.upcase}.sub(/ .*/, ''), (Class.new(HttpException) do
|
30
|
+
|
31
|
+
@status = status
|
32
|
+
@code = code
|
33
|
+
@category = code / 100
|
34
|
+
|
35
|
+
@headers = {}
|
36
|
+
|
37
|
+
end)
|
38
|
+
end
|
39
|
+
|
40
|
+
Unauthorized.headers['WWW-Authenticate'] = 'Basic realm="Authentication required"'
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|