naranya_ecm-sdk 0.0.14 → 0.0.15
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.
- checksums.yaml +4 -4
- data/lib/naranya_ecm/behaviors/localizable.rb +27 -31
- data/lib/naranya_ecm/behaviors/mediable.rb +25 -0
- data/lib/naranya_ecm/behaviors/timestampable.rb +18 -15
- data/lib/naranya_ecm/cache/key.rb +32 -56
- data/lib/naranya_ecm/cache/methods.rb +50 -63
- data/lib/naranya_ecm/lifecycles/content_lifecycle.rb +39 -16
- data/lib/naranya_ecm/models/category.rb +11 -30
- data/lib/naranya_ecm/models/content.rb +73 -73
- data/lib/naranya_ecm/models/content_version.rb +50 -29
- data/lib/naranya_ecm/models/download_authorization.rb +22 -26
- data/lib/naranya_ecm/models/media_resource.rb +49 -15
- data/lib/naranya_ecm/rest/associations.rb +156 -0
- data/lib/naranya_ecm/rest/client.rb +4 -0
- data/lib/naranya_ecm/rest/errors.rb +53 -0
- data/lib/naranya_ecm/rest/finder_methods.rb +50 -0
- data/lib/naranya_ecm/rest/model.rb +215 -0
- data/lib/naranya_ecm/rest/persistence.rb +122 -0
- data/lib/naranya_ecm/rest/relation.rb +54 -0
- data/lib/naranya_ecm/search/hit.rb +19 -14
- data/lib/naranya_ecm/search/methods.rb +18 -20
- data/lib/naranya_ecm/search/query.rb +229 -230
- data/lib/naranya_ecm/search/results.rb +136 -139
- data/lib/naranya_ecm-sdk/version.rb +1 -1
- data/lib/naranya_ecm-sdk.rb +54 -13
- data/naranya_ecm-sdk.gemspec +1 -1
- data/spec/models/category_spec.rb +7 -2
- data/spec/models/content_spec.rb +11 -2
- data/spec/models/media_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/naranya_ecms_shared_specs.rb +0 -12
- metadata +15 -19
- data/lib/naranya_ecm/behaviors/resourceable.rb +0 -22
- data/lib/naranya_ecm/behaviors.rb +0 -10
- data/lib/naranya_ecm/cache.rb +0 -9
- data/lib/naranya_ecm/has_many_patch.rb +0 -105
- data/lib/naranya_ecm/lifecycles/lifecycleable.rb +0 -43
- data/lib/naranya_ecm/lifecycles/version_lifecycle.rb +0 -75
- data/lib/naranya_ecm/lifecycles.rb +0 -10
- data/lib/naranya_ecm/models/embedded_hash.rb +0 -10
- data/lib/naranya_ecm/models/embedded_localized_hash.rb +0 -38
- data/lib/naranya_ecm/models/lifecycle.rb +0 -34
- data/lib/naranya_ecm/models.rb +0 -15
- data/lib/naranya_ecm/search.rb +0 -14
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'active_model'
|
3
|
+
|
4
|
+
module NaranyaEcm::Rest
|
5
|
+
module Model
|
6
|
+
|
7
|
+
# Constant proc that validates if a given value is a boolean:
|
8
|
+
BOOLEAN = Proc.new { |value| !!value == value }
|
9
|
+
|
10
|
+
class LocalizedAttribute < HashWithIndifferentAccess
|
11
|
+
|
12
|
+
alias_method :locales, :keys
|
13
|
+
alias_method :available_locales, :locales
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super()
|
17
|
+
given_attrs = args.shift
|
18
|
+
given_attrs.each { |k,v| self[k] = v } unless given_attrs.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
def lookup
|
22
|
+
locale = ::I18n.locale
|
23
|
+
if ::I18n.respond_to?(:fallbacks)
|
24
|
+
lookup_result = self[::I18n.fallbacks[locale].map(&:to_s).find{ |loc| self.has_key?(loc) }]
|
25
|
+
else
|
26
|
+
lookup_result = self[locale.to_s]
|
27
|
+
end
|
28
|
+
lookup_result || self.present? ? self.first[1] : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(method_name, *args, &block)
|
32
|
+
if method_name == self.class.aliased_lookup_name
|
33
|
+
# El nombre del método debe ser un alias de lookup.
|
34
|
+
# Agregar el alias:
|
35
|
+
self.class.send :alias_method, self.class.aliased_lookup_name, :lookup
|
36
|
+
# llamar el método de lookup. La siguiente ocación no caerá aqui:
|
37
|
+
lookup
|
38
|
+
else
|
39
|
+
super # You *must* call super if you don't handle the
|
40
|
+
# method, otherwise you'll mess up Ruby's method
|
41
|
+
# lookup.
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def aliased_lookup_name
|
47
|
+
@lookup_alias ||= self.name.demodulize[0..-("Translations".length+1)].underscore.to_sym
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
extend ActiveSupport::Concern
|
53
|
+
|
54
|
+
included do
|
55
|
+
|
56
|
+
include ActiveModel::Model
|
57
|
+
extend ActiveModel::Callbacks
|
58
|
+
|
59
|
+
include ActiveModel::Dirty
|
60
|
+
primary_key :id, type: String
|
61
|
+
|
62
|
+
# Ignore the server resource's url attribute:
|
63
|
+
attr_accessor :url
|
64
|
+
|
65
|
+
include HTTParty
|
66
|
+
base_uri NaranyaEcm.options[:site]
|
67
|
+
#debug_output $stderr
|
68
|
+
|
69
|
+
include NaranyaEcm::Rest::Associations
|
70
|
+
include NaranyaEcm::Rest::Persistence
|
71
|
+
|
72
|
+
extend NaranyaEcm::Rest::FinderMethods
|
73
|
+
|
74
|
+
alias_method_chain :initialize, :defaults
|
75
|
+
|
76
|
+
if NaranyaEcm.options[:extra_attributes] && (extra_fields = NaranyaEcm.options[:extra_attributes][self.name.demodulize.underscore])
|
77
|
+
extra_fields.each do |name, type|
|
78
|
+
|
79
|
+
field_options = {}
|
80
|
+
|
81
|
+
field_options[:type] = case type
|
82
|
+
when 'boolean'
|
83
|
+
NaranyaEcm::Rest::Model::BOOLEAN
|
84
|
+
else
|
85
|
+
type.classify.constantize
|
86
|
+
end
|
87
|
+
|
88
|
+
field(name.to_sym, field_options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def initialize_with_defaults(*args)
|
95
|
+
initialize_without_defaults(*args)
|
96
|
+
# inicializar con los valores default los campos que esten nulos y tengan un default definido:
|
97
|
+
self.class.fields.values
|
98
|
+
.select { |f| instance_variable_get("@#{f[:name]}".to_sym).nil? && f[:default] }
|
99
|
+
.each { |f| instance_variable_set("@#{f[:name]}".to_sym, f[:default].call) }
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def method_missing(method, *args, &block)
|
104
|
+
if method =~ /^(\w+)=$/i
|
105
|
+
self.class.send :field, $1.to_sym, type: args.first.class
|
106
|
+
self.send method, *args
|
107
|
+
else
|
108
|
+
super # You *must* call super if you don't handle the
|
109
|
+
# method, otherwise you'll mess up Ruby's method
|
110
|
+
# lookup.
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def attributes
|
115
|
+
HashWithIndifferentAccess[
|
116
|
+
self.class.fields.values
|
117
|
+
.map { |attr_data| [attr_data[:name], self.send(attr_data[:name].to_sym)] }
|
118
|
+
]
|
119
|
+
end
|
120
|
+
|
121
|
+
def associations
|
122
|
+
self.instance_variables
|
123
|
+
.map { |instance_variable| instance_variable[1..-1].to_sym }
|
124
|
+
.select { |accessor_name| self.is_association?(accessor_name) }
|
125
|
+
.inject({}.with_indifferent_access) { |hash, accessor_name| hash[accessor_name] = self.send accessor_name; hash }
|
126
|
+
end
|
127
|
+
|
128
|
+
def load(params={})
|
129
|
+
params.each do |attr, value|
|
130
|
+
self.public_send("#{attr}=", value)
|
131
|
+
end if params
|
132
|
+
end
|
133
|
+
|
134
|
+
def path
|
135
|
+
"#{self.class.path}/#{self.id}"
|
136
|
+
end
|
137
|
+
|
138
|
+
protected
|
139
|
+
|
140
|
+
def off_band_changes
|
141
|
+
@off_band_changes ||= {}.with_indifferent_access
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
module ClassMethods
|
146
|
+
|
147
|
+
def fields
|
148
|
+
@_fields ||= {}.with_indifferent_access
|
149
|
+
end
|
150
|
+
|
151
|
+
def load(*args)
|
152
|
+
loaded = self.new
|
153
|
+
loaded.load(*args)
|
154
|
+
loaded.changed_attributes.clear
|
155
|
+
loaded
|
156
|
+
end
|
157
|
+
|
158
|
+
def primary_key(name, options = {})
|
159
|
+
attr_accessor name
|
160
|
+
define_attribute_method name
|
161
|
+
end
|
162
|
+
|
163
|
+
def field(name, options = {})
|
164
|
+
|
165
|
+
if options[:localize]
|
166
|
+
lookup_alias_name = name
|
167
|
+
name = "#{name}_translations".to_sym
|
168
|
+
end
|
169
|
+
|
170
|
+
fields[name] = {name: name}.merge(options).with_indifferent_access
|
171
|
+
|
172
|
+
attr_accessor name
|
173
|
+
define_attribute_method name
|
174
|
+
|
175
|
+
if options[:localize]
|
176
|
+
# Define localized setter with dirty notification:
|
177
|
+
define_method("#{name}=".to_sym) do |value|
|
178
|
+
value = LocalizedAttribute.new value if value.is_a?(Hash) && !value.is_a?(LocalizedAttribute)
|
179
|
+
raise "Type Mismatch..." unless value.is_a?(LocalizedAttribute)
|
180
|
+
|
181
|
+
variable_name = "@#{name}".to_sym
|
182
|
+
self.send "#{name}_will_change!".to_sym unless value == instance_variable_get(variable_name)
|
183
|
+
instance_variable_set variable_name, value
|
184
|
+
end
|
185
|
+
|
186
|
+
# Define lookup alias:
|
187
|
+
define_method lookup_alias_name do
|
188
|
+
self.send(name).lookup
|
189
|
+
end
|
190
|
+
|
191
|
+
else
|
192
|
+
# Define normal setter with dirty notification:
|
193
|
+
define_method("#{name}=".to_sym) do |value|
|
194
|
+
variable_name = "@#{name}".to_sym
|
195
|
+
self.send "#{name}_will_change!".to_sym unless value == instance_variable_get(variable_name)
|
196
|
+
instance_variable_set variable_name, value
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def path
|
202
|
+
@path ||= "/#{self.name.demodulize.tableize}"
|
203
|
+
end
|
204
|
+
|
205
|
+
def where(given_conditions={})
|
206
|
+
Relation.new self, given_conditions.with_indifferent_access
|
207
|
+
end
|
208
|
+
|
209
|
+
def all
|
210
|
+
where()
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module NaranyaEcm::Rest
|
2
|
+
|
3
|
+
module Persistence
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
define_model_callbacks :create, :update, :save
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
run_callbacks :save do
|
13
|
+
@previously_changed = changes
|
14
|
+
result = self.new_resource? ? self.create : self.update
|
15
|
+
@changed_attributes.clear
|
16
|
+
result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_resource?; self.id.nil?; end
|
21
|
+
alias_method :new?, :new_resource?
|
22
|
+
|
23
|
+
def persisted?; !new_resource? || !self.changed?; end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def load_server_errors(server_error_hash)
|
28
|
+
server_error_hash = server_error_hash.with_indifferent_access
|
29
|
+
if server_error_hash.present? && server_error_hash.has_key?(:errors) && server_error_hash[:errors].present?
|
30
|
+
server_error_hash[:errors].each do |field_name, error_list|
|
31
|
+
error_list.each do |message|
|
32
|
+
self.errors.add field_name.to_sym, message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
self.errors.add :base, 'is invalid in server'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def reload
|
41
|
+
format = NaranyaEcm.options[:format] || 'json'
|
42
|
+
get_path = "#{path}.#{format}"
|
43
|
+
response = self.class.get get_path
|
44
|
+
case response.code
|
45
|
+
when 200
|
46
|
+
load(response.to_hash)
|
47
|
+
true
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def reload!; raise "Ja!" unless reload; end
|
54
|
+
|
55
|
+
def persist_request_options(data)
|
56
|
+
{
|
57
|
+
body: ActiveSupport::JSON.encode({ self.class.name.demodulize.underscore => data }),
|
58
|
+
headers: { 'Content-Type' => 'application/json'}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def create
|
63
|
+
run_callbacks :create do
|
64
|
+
|
65
|
+
format = NaranyaEcm.options[:format] || 'json'
|
66
|
+
create_path = "#{self.class.path}.#{format}"
|
67
|
+
|
68
|
+
response = self.class.post create_path, persist_request_options(self.attributes)
|
69
|
+
|
70
|
+
case response.code
|
71
|
+
when 201
|
72
|
+
self.load(response.to_hash)
|
73
|
+
true
|
74
|
+
when 422 # Unprocessable Entity
|
75
|
+
self.load_server_errors(response.to_hash)
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def update
|
82
|
+
run_callbacks :update do
|
83
|
+
attributes_to_save = self.changes.dup
|
84
|
+
attributes_to_save.each do |key, val|
|
85
|
+
attributes_to_save[key] = val.last
|
86
|
+
end
|
87
|
+
|
88
|
+
attributes_to_save.merge! off_band_changes
|
89
|
+
|
90
|
+
format = NaranyaEcm.options[:format] || 'json'
|
91
|
+
update_path = "#{self.path}.#{format}"
|
92
|
+
|
93
|
+
response = self.class.put update_path, persist_request_options(attributes_to_save)
|
94
|
+
case response.code
|
95
|
+
when 204
|
96
|
+
self.reload!
|
97
|
+
true
|
98
|
+
when 422 # Unprocessable Entity
|
99
|
+
self.load_server_errors(response.to_hash)
|
100
|
+
false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
module ClassMethods
|
107
|
+
|
108
|
+
def create(attributes={})
|
109
|
+
object_to_create = self.new attributes
|
110
|
+
object_to_create.save
|
111
|
+
object_to_create
|
112
|
+
end
|
113
|
+
def create!(attributes={})
|
114
|
+
created_object = create(attributes)
|
115
|
+
raise "ValidationError" unless created_object.persisted?
|
116
|
+
created_object
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module NaranyaEcm::Rest
|
2
|
+
class Relation
|
3
|
+
include Enumerable
|
4
|
+
delegate :to_yaml, :all?, :each, :first, :last, to: :to_a
|
5
|
+
|
6
|
+
attr_reader :klass, :conditions, :elements
|
7
|
+
|
8
|
+
def initialize(given_klass, given_conditions = {})
|
9
|
+
@klass, @conditions = given_klass, given_conditions.with_indifferent_access
|
10
|
+
end
|
11
|
+
|
12
|
+
def where(given_conditions = {})
|
13
|
+
spawn_chain(given_conditions)
|
14
|
+
end
|
15
|
+
|
16
|
+
def limit(given_limit)
|
17
|
+
spawn_chain(limit: given_limit.to_i)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_a
|
21
|
+
materialize! unless @elements
|
22
|
+
elements
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_from_server
|
26
|
+
format = NaranyaEcm.options[:format] || 'json'
|
27
|
+
response = klass.get("#{klass.path}.#{format}", query: conditions)
|
28
|
+
case response.code
|
29
|
+
when 404
|
30
|
+
raise ResourceNotFound
|
31
|
+
when 200
|
32
|
+
response.to_a
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def load(given_list)
|
37
|
+
# Revisar que todos los elementos sean Hash o la clase asociada:
|
38
|
+
raise "Type Mismatch: some elements are not a hash nor associated_class" unless given_list
|
39
|
+
.map { |e| e.is_a?(Hash) || e.is_a?(@klass) }
|
40
|
+
.reduce { |res, e| res && e }
|
41
|
+
@elements = given_list.map { |e| e.is_a?(Hash) ? @klass.load(e) : e }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def spawn_chain(given_conditions = {})
|
46
|
+
self.class.new klass, conditions.merge(given_conditions)
|
47
|
+
end
|
48
|
+
|
49
|
+
def materialize!
|
50
|
+
@elements = fetch_from_server.map { |s| klass.load s }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -1,17 +1,22 @@
|
|
1
|
-
module NaranyaEcm
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@type = attributes.delete :_type
|
9
|
-
@score = attributes.delete :_score
|
1
|
+
module NaranyaEcm::Search
|
2
|
+
class Hit
|
3
|
+
attr_reader :id, :type, :updated_at, :order, :score
|
4
|
+
def initialize(attributes={})
|
5
|
+
@id = attributes.delete :_id
|
6
|
+
@type = attributes.delete :_type
|
7
|
+
@score = attributes.delete :_score
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
source = attributes.delete :_source
|
10
|
+
@updated_at = source.has_key?(:updated_at) ? source.delete(:updated_at).to_datetime : nil
|
11
|
+
@order = attributes.delete :order
|
12
|
+
end
|
13
|
+
|
14
|
+
def klass
|
15
|
+
@klass ||= "NaranyaEcm::#{type.classify}".constantize
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache_key
|
19
|
+
@cache_key ||= NaranyaEcm::Cache::Key.new klass, id, updated_at
|
15
20
|
end
|
16
21
|
end
|
17
|
-
end
|
22
|
+
end
|
@@ -1,26 +1,24 @@
|
|
1
1
|
require 'active_support/concern'
|
2
|
-
module NaranyaEcm
|
3
|
-
module
|
4
|
-
|
5
|
-
extend ActiveSupport::Concern
|
2
|
+
module NaranyaEcm::Search
|
3
|
+
module Methods
|
4
|
+
extend ActiveSupport::Concern
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
included do
|
7
|
+
attr_reader :search_score, :search_order
|
8
|
+
end
|
9
|
+
|
10
|
+
def merge_search_hit_data(hit)
|
11
|
+
@search_score, @search_order = hit.score, hit.order
|
12
|
+
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
14
|
+
module ClassMethods
|
15
|
+
def search(*args)
|
16
|
+
Results.new(self, *args)
|
17
|
+
end
|
18
|
+
def kick_search(terms, options={})
|
19
|
+
search(Query.build_searchkick_like(terms, options))
|
22
20
|
end
|
23
|
-
|
24
21
|
end
|
22
|
+
|
25
23
|
end
|
26
|
-
end
|
24
|
+
end
|