web-connect 0.1.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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -0
  3. data/Rakefile +3 -0
  4. data/lib/netfira/web_connect/components/checksum.rb +19 -0
  5. data/lib/netfira/web_connect/components/guid.rb +11 -0
  6. data/lib/netfira/web_connect/components/octa_word.rb +73 -0
  7. data/lib/netfira/web_connect/components.rb +1 -0
  8. data/lib/netfira/web_connect/configuration.rb +33 -0
  9. data/lib/netfira/web_connect/db_schema/20140514_support.rb +38 -0
  10. data/lib/netfira/web_connect/db_schema/20140515_alpha.rb +106 -0
  11. data/lib/netfira/web_connect/events.rb +14 -0
  12. data/lib/netfira/web_connect/migration/base_methods.rb +59 -0
  13. data/lib/netfira/web_connect/migration/refinements.rb +16 -0
  14. data/lib/netfira/web_connect/migration.rb +101 -0
  15. data/lib/netfira/web_connect/model/record/digests.rb +24 -0
  16. data/lib/netfira/web_connect/model/record/events.rb +35 -0
  17. data/lib/netfira/web_connect/model/record/file_record.rb +79 -0
  18. data/lib/netfira/web_connect/model/record/materialization.rb +59 -0
  19. data/lib/netfira/web_connect/model/record/relations.rb +51 -0
  20. data/lib/netfira/web_connect/model/record/sendable.rb +29 -0
  21. data/lib/netfira/web_connect/model/record/serializer.rb +56 -0
  22. data/lib/netfira/web_connect/model/record/translated_string.rb +42 -0
  23. data/lib/netfira/web_connect/model/record/translation.rb +58 -0
  24. data/lib/netfira/web_connect/model/record/translations.rb +63 -0
  25. data/lib/netfira/web_connect/model/record/tree.rb +13 -0
  26. data/lib/netfira/web_connect/model/record.rb +132 -0
  27. data/lib/netfira/web_connect/model/relation/events.rb +34 -0
  28. data/lib/netfira/web_connect/model/relation.rb +67 -0
  29. data/lib/netfira/web_connect/model/support.rb +13 -0
  30. data/lib/netfira/web_connect/model.rb +33 -0
  31. data/lib/netfira/web_connect/models/image.rb +48 -0
  32. data/lib/netfira/web_connect/models/order.rb +5 -0
  33. data/lib/netfira/web_connect/models/order_line.rb +13 -0
  34. data/lib/netfira/web_connect/models/support/setting.rb +31 -0
  35. data/lib/netfira/web_connect/models/support/shop/settings.rb +42 -0
  36. data/lib/netfira/web_connect/models/support/shop.rb +22 -0
  37. data/lib/netfira/web_connect/models/support/table.rb +5 -0
  38. data/lib/netfira/web_connect/models.rb +73 -0
  39. data/lib/netfira/web_connect/rack_app/action.rb +66 -0
  40. data/lib/netfira/web_connect/rack_app/action_helpers/data_types.rb +22 -0
  41. data/lib/netfira/web_connect/rack_app/action_helpers/env_importer.rb +59 -0
  42. data/lib/netfira/web_connect/rack_app/action_helpers/env_methods.rb +23 -0
  43. data/lib/netfira/web_connect/rack_app/actions/version_1/not_supported.rb +11 -0
  44. data/lib/netfira/web_connect/rack_app/actions/version_8/checksums.rb +14 -0
  45. data/lib/netfira/web_connect/rack_app/actions/version_8/commit/records.rb +45 -0
  46. data/lib/netfira/web_connect/rack_app/actions/version_8/commit/relations.rb +48 -0
  47. data/lib/netfira/web_connect/rack_app/actions/version_8/commit.rb +33 -0
  48. data/lib/netfira/web_connect/rack_app/actions/version_8/files.rb +21 -0
  49. data/lib/netfira/web_connect/rack_app/actions/version_8/info.rb +18 -0
  50. data/lib/netfira/web_connect/rack_app/actions/version_8/settings.rb +79 -0
  51. data/lib/netfira/web_connect/rack_app/exceptions/http_exception.rb +44 -0
  52. data/lib/netfira/web_connect/rack_app/exceptions.rb +6 -0
  53. data/lib/netfira/web_connect/rack_app.rb +56 -0
  54. data/lib/netfira/web_connect/request_filter.rb +66 -0
  55. data/lib/netfira/web_connect/schema/table.rb +58 -0
  56. data/lib/netfira/web_connect/schema.rb +22 -0
  57. data/lib/netfira/web_connect/version.rb +5 -0
  58. data/lib/netfira/web_connect.rb +82 -0
  59. data/lib/netfira.rb +10 -0
  60. data/lib/web_connect.rb +1 -0
  61. 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,5 @@
1
+ module Netfira::WebConnect
2
+ class Models::Table < Model::Support
3
+
4
+ end
5
+ end
@@ -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,11 @@
1
+ class Netfira::WebConnect::RackApp
2
+ module Action::Version1
3
+ %w[Commit Info Settings Checksums Files].each do |name|
4
+ const_set name, (Class.new(Action) do
5
+ def call
6
+ raise Exceptions::HttpExceptions::NotFound
7
+ end
8
+ end)
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,6 @@
1
+ module Netfira::WebConnect::RackApp::Exceptions
2
+ class Base < Exception
3
+ end
4
+ end
5
+
6
+ require_relative 'exceptions/http_exception'