197 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| #require "providers/provider_factory"
 | |
| require "exceptions/invalid_record"
 | |
| require "json"
 | |
| require 'db/validators/all'
 | |
| 
 | |
| module Devops
 | |
|   module Model
 | |
|     class MongoModel
 | |
| 
 | |
|       attr_accessor :created_at
 | |
| 
 | |
|       # multi_json sends argument to 'to_json' method
 | |
|       def to_json arg=nil
 | |
|         JSON.pretty_generate self.to_hash
 | |
|       end
 | |
| 
 | |
|       def to_hash
 | |
|         h = to_hash_without_id
 | |
|         h["id"] = self.id
 | |
|         h
 | |
|       end
 | |
| 
 | |
|       def to_mongo_hash
 | |
|         h = to_hash_without_id
 | |
|         h["_id"] = self.id
 | |
|         h
 | |
|       end
 | |
| 
 | |
|       def is_empty? val
 | |
|         val.nil? or val.strip.empty?
 | |
|       end
 | |
| 
 | |
|       def check_string! val
 | |
|         raise ArgumentError unless val.is_a?(String)
 | |
|         val.strip!
 | |
|         raise ArgumentError if val.empty?
 | |
|       end
 | |
| 
 | |
|       def check_array! val, type, empty=false
 | |
|         raise ArgumentError unless val.is_a?(Array)
 | |
|         raise ArgumentError if !empty and val.empty?
 | |
|         val.each do |v|
 | |
|           raise ArgumentError unless v.is_a?(type)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       def check_name_value val
 | |
|         raise ArgumentError.new "Invalid name, it should contains 0-9, a-z, A-Z, _, - symbols only" if val.match(/^[0-9a-zA-Z_\-]+$/).nil?
 | |
|       end
 | |
| 
 | |
|       def check_provider provider=self.provider
 | |
|         unless ::Provider::ProviderFactory.providers.include?(provider)
 | |
|           raise InvalidRecord.new "Invalid provider '#{provider}'"
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       def validate!
 | |
|         begin
 | |
|           # TODO: we should validate type in request parser
 | |
| #          self.validate_fields_types
 | |
|           self.class.validate_model(self)
 | |
|           validate_fields!
 | |
|           true
 | |
|         rescue InvalidRecord => e
 | |
|           error_message = self.build_error_message(e.message)
 | |
|           raise InvalidRecord.new(error_message)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       def validate_fields!
 | |
|         result = []
 | |
|         self.class.field_validators.each do |field, validation_method|
 | |
|           begin
 | |
|             self.send(validation_method)
 | |
|           rescue InvalidRecord => e
 | |
|             result << {key: field, message: e.message}
 | |
|           end
 | |
|         end
 | |
|         unless result.empty?
 | |
|           raise InvalidRecord.new(error_data: result)
 | |
|         end
 | |
|         true
 | |
|       end
 | |
| 
 | |
|       def valid?
 | |
|         validate!
 | |
|         true
 | |
|       rescue InvalidRecord
 | |
|         false
 | |
|       end
 | |
| 
 | |
|       def build_error_message(message)
 | |
|         # overrided in descendants
 | |
|         message
 | |
|       end
 | |
| 
 | |
|       # types - Hash
 | |
|       #   key - param name
 | |
|       #   value - Hash
 | |
|       #     :type - param type
 | |
|       #     :empty - can param be empty? (false)
 | |
|       #     :nil - can param be nil? (false)
 | |
|       #     :value_type - type of array element (String)
 | |
|       # TODO: @deprecated
 | |
|       def self.types types
 | |
|         define_method :validate_fields_types do
 | |
|           t = types.keys
 | |
|           e = types.keys
 | |
|           n = types.keys
 | |
|           types.each do |name, value|
 | |
|             if value[:nil]
 | |
|               n.delete(name)
 | |
|               if self.send(name).nil?
 | |
|                 e.delete(name)
 | |
|                 t.delete(name)
 | |
|                 next
 | |
|               end
 | |
|             else
 | |
|               n.delete(name) unless self.send(name).nil?
 | |
|             end
 | |
|             if self.send(name).is_a? value[:type]
 | |
|               t.delete(name)
 | |
|               self.send(name).strip! if value[:type] == String
 | |
|               if value[:type] == Array
 | |
|                 unless value[:value_type] == false
 | |
|                   type = value[:value_type] || String
 | |
|                   self.send(name).each do |e|
 | |
|                     unless e.is_a?(type)
 | |
|                       t.push(name)
 | |
|                       break
 | |
|                     end
 | |
|                   end
 | |
|                 end
 | |
|               end
 | |
|               e.delete(name) if value[:empty] or !self.send(name).empty?
 | |
|             end
 | |
|           end
 | |
|           raise InvalidRecord.new "Parameter(s) '#{n.join("', '")}' can not be undefined" unless n.empty?
 | |
|           raise InvalidRecord.new "Parameter(s) '#{t.join("', '")}' have invalid type(s)" unless t.empty?
 | |
|           raise InvalidRecord.new "Parameter(s) '#{e.join("', '")}' can not be empty" unless e.empty?
 | |
|           if types.has_key? :provider
 | |
|             self.send("check_provider")
 | |
|           end
 | |
|           true
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       @validators = []
 | |
|       @field_validators = {}
 | |
|       class << self
 | |
| 
 | |
|         attr_accessor :validators
 | |
|         attr_accessor :field_validators
 | |
| 
 | |
|         def inherited(subclass)
 | |
|           subclass.validators = []
 | |
|           subclass.validators += self.validators
 | |
|           subclass.field_validators = self.field_validators.clone
 | |
|         end
 | |
| 
 | |
|         # all exceptions are handled in @validate! method
 | |
|         def validate_model(model)
 | |
|           validators.each do |validator|
 | |
|             validator.new(model).validate!
 | |
|           end
 | |
|         end
 | |
| 
 | |
| 
 | |
|         # validate field value
 | |
|         # if method validate! returns false, then stop validation without error
 | |
|         def set_field_validators field, *validators
 | |
|           method_name = "validate_" + field.to_s + "!"
 | |
|           define_method(method_name) do
 | |
|             validators.each do |validator|
 | |
|               break unless validator.new(self, send(field)).validate!
 | |
|             end
 | |
|           end
 | |
|           self.field_validators[field] = method_name
 | |
|         end
 | |
| 
 | |
|         # private class methods
 | |
|         private
 | |
| 
 | |
|         def set_validators(*validators_to_add)
 | |
|           self.validators += validators_to_add
 | |
|         end
 | |
| 
 | |
|         def unset_validators(*validators_to_remove)
 | |
|           self.validators -= validators_to_remove
 | |
|         end
 | |
| 
 | |
|       end
 | |
| 
 | |
|     end
 | |
|   end
 | |
| end
 | 
