class Netfira::WebConnect::RackApp::Action
Constants
- VALID_BASE64
Attributes
env[R]
headers[R]
input[R]
path[R]
query_string[R]
shop[R]
timeout[R]
verb[R]
Public Class Methods
action_classes()
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 9 def self.action_classes @action_classes ||= find_action_classes end
create(action, version = nil)
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 17 def self.create(action, version = nil) version ||= latest_version klass = nil until klass or version < 1 klass = (action_classes[version] || {})[action] # todo needs explination or to be rewritten to be easily readable version -= 1 end klass and klass.new end
latest_version()
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 13 def self.latest_version @latest_version ||= action_classes.keys.max end
new()
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 27 def initialize @headers = ActiveSupport::HashWithIndifferentAccess.new end
Private Class Methods
find_action_classes()
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 37 def self.find_action_classes action_classes = {} # Loop through all constants in this class's namespace constants.each do |constant| # Match Version# constants (modules containing actions) if constant =~ /\AVersion(\d+)\z/ # The module containing the actions mod = const_get(constant) # A hash of actions, e.g. :commit => Action::Version8::Commit action_classes[$1.to_i] = Hash[mod.constants.map do |name| mod.const_get(name) end.select do |klass| klass < self end.map do |klass| [klass.name.demodulize.underscore.to_sym, klass] end] end end action_classes end
Public Instance Methods
allow(*args)
click to toggle source
This method restricts request verbs (symbols) and input types (classes)
# File lib/netfira/web_connect/rack_app/action_helpers/env_methods.rb, line 22 def allow(*args) # Restrict verbs verbs = args.select { |x| Symbol === x } unless verbs.empty? || verbs.include?(verb) raise MethodNotAllowed.new("The #{verb.to_s.upcase} verb is not allowed", allowed: verbs.map{ |v| v.to_s.upcase }) end # Restrict input type types = args.select { |x| Class === x } unless types.empty? || types.find { |t| t === input } raise BadRequest.new('Unexpected request body type', allowed: types.map { |t| t.name }) end end
class_for_record_type(type)
click to toggle source
# File lib/netfira/web_connect/rack_app/action_helpers/data_types.rb, line 4 def class_for_record_type(type) class_for_type type, Model::Record end
class_for_relation_type(type)
click to toggle source
# File lib/netfira/web_connect/rack_app/action_helpers/data_types.rb, line 8 def class_for_relation_type(type) class_for_type type, Model::Relation end
dispatch_event(*args, &block)
click to toggle source
# File lib/netfira/web_connect/rack_app/action.rb, line 31 def dispatch_event(*args, &block) Netfira::WebConnect.dispatch_event *args, &block end
header(name, value)
click to toggle source
This method sets a response header, e.g.header 'Content-Type', 'text/plain'
# File lib/netfira/web_connect/rack_app/action_helpers/env_methods.rb, line 7 def header(name, value) name = name.to_s.split(/[- _]/).map(&:capitalize).join('-').to_sym if value headers[name] = value else headers.delete name end end
import_env(env)
click to toggle source
# File lib/netfira/web_connect/rack_app/action_helpers/env_importer.rb, line 7 def import_env(env) @env = env @shop = nil session = nil # Parse the environment request = Rack::Request.new env # Restore sessions session_lifetime = Netfira::WebConnect.session_lifetime session_token = session_lifetime && env['HTTP_X_SESSION'] if session_token session = Models::Session.by_token(session_token) if session @shop = session.shop else raise Unauthorized, 'Session has expired' end end # Authentication unless @shop authenticator = Netfira::WebConnect.authenticator if authenticator.respond_to? :call shop_name = env['HTTP_X_SHOP_NAME'] password = request['pw'] || env['HTTP_X_PASSWORD'] # Basic auth auth = Rack::Auth::Basic::Request.new(env) if auth.provided? && auth.basic? shop_name ||= auth.username password ||= auth.credentials[1] end # Make shop_name a copy, so the authenticator can't mutate # the original string shop_name = shop_name.dup if shop_name result = authenticator.call shop_name, password raise Unauthorized unless result @shop = Netfira::WebConnect::Models::Shop.find_or_create_by(name: shop_name) header :x_vary_password, result if String === result # Sessions if session_lifetime session ||= @shop.sessions.new session.expires_at = Time.now + session_lifetime if Fixnum === session_lifetime session.save header :x_session, session.token end elsif authenticator.nil? @shop = Netfira::WebConnect.anonymous_shop else raise 'Authenticator is not callable' end end # The request verb (PUT, GET, POST etc) @verb = request.request_method.downcase.to_sym # Query string @query_string = request.GET # The X-Timeout header timeout = env['HTTP_X_TIMEOUT'] @timeout = timeout.to_i if timeout # Path components if env['PATH_INFO'] =~ /\A\/\d+\/[^\/]+\/(.+)\z/ @path = $1.split('/').map{ |x| Rack::Utils.unescape x } end # Input if put? or post? @input = request.body # Decode base64 if (env['HTTP_CONTENT_ENCODING'] || env['CONTENT_ENCODING'] || '').downcase == 'base64' input = @input.read.gsub(/\s+/, '') raise BadRequest, 'Invalid base64 in request body' unless input.length % 4 == 0 && input =~ VALID_BASE64 @input = StringIO.new(input.unpack('m').first) end # Unserialize JSON begin @input = JSON.parse @input.read.sub(/\A\z/, 'null'), quirks_mode: true if request.media_type == 'application/json' rescue JSON::ParserError => error raise BadRequest.new('Invalid JSON in request body', details: error.message.sub(/^\d+:\s*/, '')) end end end
send_file(path)
click to toggle source
# File lib/netfira/web_connect/rack_app/action_helpers/send_file.rb, line 6 def send_file(path) content = nil if path.to_s.end_with? '.erb' template = ERB.new(path.read) content = template.result(binding) end raise RackApp::Exceptions::SendFile.new(path, content) end
Private Instance Methods
class_for_type(type, superclass)
click to toggle source
# File lib/netfira/web_connect/rack_app/action_helpers/data_types.rb, line 14 def class_for_type(type, superclass) raise BadRequest, 'No data type specified' if type.nil? klass = Models.const_defined?(type) && Models.const_get(type) raise BadRequest, 'Invalid or unknown data type' unless klass && klass < superclass klass end