naranya_ecm-sdk 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/naranya_ecm/behaviors/localizable.rb +27 -31
  3. data/lib/naranya_ecm/behaviors/mediable.rb +25 -0
  4. data/lib/naranya_ecm/behaviors/timestampable.rb +18 -15
  5. data/lib/naranya_ecm/cache/key.rb +32 -56
  6. data/lib/naranya_ecm/cache/methods.rb +50 -63
  7. data/lib/naranya_ecm/lifecycles/content_lifecycle.rb +39 -16
  8. data/lib/naranya_ecm/models/category.rb +11 -30
  9. data/lib/naranya_ecm/models/content.rb +73 -73
  10. data/lib/naranya_ecm/models/content_version.rb +50 -29
  11. data/lib/naranya_ecm/models/download_authorization.rb +22 -26
  12. data/lib/naranya_ecm/models/media_resource.rb +49 -15
  13. data/lib/naranya_ecm/rest/associations.rb +156 -0
  14. data/lib/naranya_ecm/rest/client.rb +4 -0
  15. data/lib/naranya_ecm/rest/errors.rb +53 -0
  16. data/lib/naranya_ecm/rest/finder_methods.rb +50 -0
  17. data/lib/naranya_ecm/rest/model.rb +215 -0
  18. data/lib/naranya_ecm/rest/persistence.rb +122 -0
  19. data/lib/naranya_ecm/rest/relation.rb +54 -0
  20. data/lib/naranya_ecm/search/hit.rb +19 -14
  21. data/lib/naranya_ecm/search/methods.rb +18 -20
  22. data/lib/naranya_ecm/search/query.rb +229 -230
  23. data/lib/naranya_ecm/search/results.rb +136 -139
  24. data/lib/naranya_ecm-sdk/version.rb +1 -1
  25. data/lib/naranya_ecm-sdk.rb +54 -13
  26. data/naranya_ecm-sdk.gemspec +1 -1
  27. data/spec/models/category_spec.rb +7 -2
  28. data/spec/models/content_spec.rb +11 -2
  29. data/spec/models/media_spec.rb +1 -1
  30. data/spec/spec_helper.rb +1 -1
  31. data/spec/support/naranya_ecms_shared_specs.rb +0 -12
  32. metadata +15 -19
  33. data/lib/naranya_ecm/behaviors/resourceable.rb +0 -22
  34. data/lib/naranya_ecm/behaviors.rb +0 -10
  35. data/lib/naranya_ecm/cache.rb +0 -9
  36. data/lib/naranya_ecm/has_many_patch.rb +0 -105
  37. data/lib/naranya_ecm/lifecycles/lifecycleable.rb +0 -43
  38. data/lib/naranya_ecm/lifecycles/version_lifecycle.rb +0 -75
  39. data/lib/naranya_ecm/lifecycles.rb +0 -10
  40. data/lib/naranya_ecm/models/embedded_hash.rb +0 -10
  41. data/lib/naranya_ecm/models/embedded_localized_hash.rb +0 -38
  42. data/lib/naranya_ecm/models/lifecycle.rb +0 -34
  43. data/lib/naranya_ecm/models.rb +0 -15
  44. data/lib/naranya_ecm/search.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab5a255c31cbc5ece70b173939a3d883331e2355
4
- data.tar.gz: aa2552ae589d918f381ca929784704e7119e5fcc
3
+ metadata.gz: 3f6a90236bd794d754bdf445805afdf1b4539d4f
4
+ data.tar.gz: e40ad3616ae04fb8932e2df7fb47546efb0ce7b1
5
5
  SHA512:
6
- metadata.gz: 7329e2ad01e89a35391762dc82923953bf813de13ff4378de9dd59a696803d36d02920f74db48cb311c42da8ba8f22ccccde0344fcbfd1dd45ad2f5a7952c3cb
7
- data.tar.gz: c462661938efd0c6f57dc24822500374f46c7f5368df99a8440d3479df1699f91582151dddb0eb89b863a0792c45152a6b3d4d5424e81d871f75a58f65fb3345
6
+ metadata.gz: f0802bf180226d3b443697ab502f09e1b13a23dd79105b246419de9a8e534cdc4db8351b6577953551ad3e8361c3a67a61e35c896509266c2309affbb9458f3a
7
+ data.tar.gz: 62565940d9f2025491f2a5d30d45990e1a2744afa2b411feb8c0bd1ebb5b766a4bd92b87b0127a22e098e6619686379318762f725dcabc8f163f86443316fc9b
@@ -1,41 +1,37 @@
1
1
  require 'active_support/concern'
2
2
 
3
- module NaranyaEcm
3
+ module NaranyaEcm::Behaviors
4
+ module Localizable
4
5
 
5
- module Behaviors
6
- module Localizable
6
+ extend ActiveSupport::Concern
7
7
 
8
- extend ActiveSupport::Concern
8
+ included do
9
+ # Delegar el acceso tipo "Enumerable":
10
+ delegate :any?, to: :@attributes
9
11
 
10
- included do
11
- # Delegar el acceso tipo "Enumerable":
12
- delegate :any?, to: :@attributes
12
+ # Re-establece el acceso tipo Hash:
13
+ delegate :[], to: :@attributes
14
+ delegate :[]=, to: :@attributes
15
+ self.site = "http://www.example.com"
13
16
 
14
- # Re-establece el acceso tipo Hash:
15
- delegate :[], to: :@attributes
16
- delegate :[]=, to: :@attributes
17
- self.site = "http://www.example.com"
18
-
19
- attribute_name = self.name.demodulize.underscore[0..-("_translations".length+1)]
20
- alias_method attribute_name.to_sym, :lookup
21
- end
17
+ attribute_name = self.name.demodulize.underscore[0..-("_translations".length+1)]
18
+ alias_method attribute_name.to_sym, :lookup
19
+ end
22
20
 
23
- def locales
24
- @attributes.keys
25
- end
26
- alias_method :available_locales, :locales
27
-
28
- def lookup
29
- locale = ::I18n.locale
30
- if ::I18n.respond_to?(:fallbacks)
31
- lookup_result = @attributes[::I18n.fallbacks[locale].map(&:to_s).find{ |loc| @attributes.has_key?(loc) }]
32
- else
33
- lookup_result = @attributes[locale.to_s]
34
- end
35
- lookup_result || @attributes.present? ? @attributes.first[1] : nil
21
+ def locales
22
+ @attributes.keys
23
+ end
24
+ alias_method :available_locales, :locales
25
+
26
+ def lookup
27
+ locale = ::I18n.locale
28
+ if ::I18n.respond_to?(:fallbacks)
29
+ lookup_result = @attributes[::I18n.fallbacks[locale].map(&:to_s).find{ |loc| @attributes.has_key?(loc) }]
30
+ else
31
+ lookup_result = @attributes[locale.to_s]
36
32
  end
37
-
33
+ lookup_result || @attributes.present? ? @attributes.first[1] : nil
38
34
  end
39
- end
40
35
 
41
- end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ module NaranyaEcm::Behaviors
2
+ module Mediable
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ def find_media_by_role(role_name)
7
+ mr = self.media_resources.nil? ? [] : self.media_resources
8
+ mr.detect { |mr| mr.roles.include? role_name }
9
+ end
10
+
11
+ def find_media_url_by_role(role_name)
12
+ mr = self.find_media_by_role role_name
13
+ mr.present? ? mr.downloadable_url : nil
14
+ end
15
+
16
+ def select_media_by_role(role_name)
17
+ self.media_resources.select { |mr| mr.roles.include? role_name }
18
+ end
19
+
20
+ def select_media_urls_by_role(role_name)
21
+ mr = self.select_media_by_role(role_name).map(&:downloadable_url)
22
+ mr.flatten.uniq
23
+ end
24
+ end
25
+ end
@@ -1,22 +1,25 @@
1
1
  require 'active_support/concern'
2
- module NaranyaEcm
3
- module Behaviors
4
- module Timestampable
5
2
 
6
- extend ActiveSupport::Concern
3
+ module NaranyaEcm::Behaviors
4
+ module Timestampable
7
5
 
8
- included do
9
- %w(created_at updated_at).map(&:to_sym).each do |attr_sym|
10
- # getter:
11
- define_method(attr_sym) { @attributes[attr_sym].present? ? @attributes[attr_sym].to_datetime : nil }
12
- # setter:
13
- # define_method("#{attr_sym}=".to_sym) do |value|
14
- # self.send "#{attr_sym}_will_change!".to_sym unless value == @attributes[attr_sym]
15
- # @attributes[attr_sym] = value
16
- # end
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ [:created_at, :updated_at].each do |timestamp_name|
10
+ attr_accessor timestamp_name
11
+
12
+ define_method timestamp_name do
13
+ unless instance_variable_get("@#{timestamp_name}".to_sym).respond_to? :strftime
14
+ instance_variable_set(
15
+ "@#{timestamp_name}".to_sym,
16
+ instance_variable_get("@#{timestamp_name}".to_sym).to_s.to_datetime
17
+ )
18
+ end
19
+ instance_variable_get("@#{timestamp_name}".to_sym)
17
20
  end
18
21
  end
19
-
20
22
  end
23
+
21
24
  end
22
- end
25
+ end
@@ -1,73 +1,49 @@
1
1
  require 'active_support/hash_with_indifferent_access'
2
2
 
3
- module NaranyaEcm
4
- module Cache
5
- class Key < String
3
+ module NaranyaEcm::Cache
4
+ class Key < String
6
5
 
7
- TIMESTAMP_FORMAT = '%Y%m%d%H%M%S'.freeze
6
+ TIMESTAMP_FORMAT = '%Y%m%d%H%M%S'.freeze
8
7
 
9
- def initialize(segments={})
8
+ attr_reader :klass, :id, :timestamp
10
9
 
11
- @segments = ActiveSupport::HashWithIndifferentAccess.new
10
+ def initialize(given_class, given_id, given_timestamp = nil)
11
+ @klass, @id = given_class, given_id
12
12
 
13
- resource = segments.delete :resource
14
-
15
- @segments[:class_name] = case
16
- when resource.present? then resource.class.name
17
- when segments.has_key?(:class_name) then segments.delete(:class_name)
18
- when segments.has_key?(:resource_class) then segments.delete(:resource_class).name
19
- else nil
20
- end
21
-
22
- @segments[:id] = case
23
- when resource.present? then resource.id
24
- when segments.has_key?(:id) then segments.delete(:id)
25
- else nil
26
- end
27
-
28
- @segments[:timestamp] = case
29
- when resource.present? then resource.respond_to?(:updated_at) ? resource.updated_at : nil
30
- when segments.has_key?(:timestamp) then segments.delete(:timestamp)
31
- else nil
13
+ unless given_timestamp.blank?
14
+ @timestamp = if given_timestamp.is_a? String
15
+ given_timestamp.to_datetime
16
+ elsif given_timestamp.respond_to? :strftime
17
+ given_timestamp
18
+ else
19
+ raise ArgumentError, "Given timestamp is not a Date|Time like object"
32
20
  end
33
-
34
- @segments.freeze
35
-
36
- super self.class.join_segments(@segments).freeze
37
-
38
21
  end
39
22
 
40
- def class_name; @segments[:class_name]; end
41
- def id; @segments[:id]; end
42
- def timestamp; @segments[:timestamp]; end
23
+ super join_segments
24
+ end
43
25
 
44
- def timestamped?
45
- resource_timestamp.present?
46
- end
26
+ def timestamped?
27
+ timestamp.present?
28
+ end
47
29
 
48
- def any_timestamp
49
- self.class.join_segments(@segments.except(:timestamp)) + '-*'
50
- end
30
+ def exist?
31
+ NaranyaEcm.cache.exist? self
32
+ end
51
33
 
52
- def with_timestamp(datetime)
53
- raise "Not a valid timestamp" unless datetime.respond_to? :to_time
54
- self.class.new class_name: class_name, id: id, timestamp: datetime
55
- end
34
+ def read
35
+ NaranyaEcm.cache.read self
36
+ end
56
37
 
57
- class << self
58
- def join_segments(segments)
59
- segments = segments.with_indifferent_access
60
- str = segments[:class_name].tableize
61
- if segments[:id].present?
62
- str += "/#{segments[:id]}"
63
- if segments[:timestamp].present? and segments[:timestamp].respond_to?(:to_time)
64
- str += '-' + segments[:timestamp].strftime(TIMESTAMP_FORMAT)
65
- end
66
- end
67
- str
68
- end
38
+ def write(data)
39
+ NaranyaEcm.cache.write self, data
40
+ end
41
+
42
+ private
43
+ def join_segments
44
+ key = "#{klass.name.tableize}/#{id}"
45
+ timestamped? ? "#{key}-#{timestamp.strftime(TIMESTAMP_FORMAT)}" : key
69
46
  end
70
47
 
71
- end
72
48
  end
73
49
  end
@@ -1,82 +1,69 @@
1
1
  require 'active_support/concern'
2
- module NaranyaEcm
3
- module Cache
4
- module Methods
5
2
 
6
- extend ActiveSupport::Concern
3
+ module NaranyaEcm::Cache
4
+ module Methods
7
5
 
8
- included do
9
- alias_method_chain :load, :caching
6
+ extend ActiveSupport::Concern
10
7
 
11
- class << self
12
- alias_method_chain :find_single, :caching
13
- end
14
- end
15
-
16
- def cache_key
17
- @cache_key ||= NaranyaEcm.cache_key_for resource: self
18
- end
19
-
20
- def load_with_caching(attributes, remove_root = false, persisted = false)
21
- if self.new?
22
- load_without_caching(attributes, remove_root, persisted)
23
- else
24
- res = load_without_caching(attributes, remove_root = false, persisted = false)
25
-
26
- cache_options = {}
27
- cache_options[:expires_in] = 10.minutes unless self.updated_at.present? and self.updated_at.is_a? DateTime
28
-
29
- NaranyaEcm.cache.write cache_key, @attributes, cache_options
30
-
31
- res
32
- end
8
+ included do
9
+ class << self
10
+ alias_method_chain :find, :caching
11
+ alias_method_chain :find_one, :caching
33
12
  end
13
+ end
34
14
 
35
- module ClassMethods
15
+ def cache_key
16
+ self.new_resource? ? nil : self.class.cache_key_for(self.id, self.updated_at)
17
+ end
36
18
 
37
- def cache
38
- NaranyaEcm.cache
39
- end
19
+ module ClassMethods
40
20
 
41
- def cache_key_for(attributes)
42
- NaranyaEcm.cache_key_for attributes.merge(resource_class: self)
43
- end
21
+ def cache
22
+ NaranyaEcm.cache
23
+ end
44
24
 
45
- def find_cached(cache_key)
46
- cached_attributes = cache.read(cache_key)
47
- cached_attributes.present? ? instantiate_record(cached_attributes) : nil
48
- end
25
+ def cache_key_for(id, timestamp=nil)
26
+ Key.new self, id, timestamp
27
+ end
49
28
 
50
- def find_cached!(cache_key)
51
- found = find_cached(cache_key)
52
- raise "No record matched given attribute in cache" unless found
53
- found
54
- end
29
+ def find_with_caching(id, cache_options = {})
30
+ find_one_with_caching(id, cache_options)
31
+ end
55
32
 
56
- private
33
+ private
57
34
 
58
- # Find a single resource from the default URL
59
- def find_single_with_caching(scope, options)
60
-
35
+ # Find a single resource from the default URL
36
+ def find_one_with_caching(id, cache_options = {})
37
+ fetched_data = nil
38
+ missed = true
39
+
40
+ # Ver primero si lo podemos obtener del cache:
41
+ cache_timestamp = cache_options.delete(:timestamp)
42
+ if cache_timestamp.present?
61
43
  # Try to load the record from cache:
62
- cache_key = cache_key_for id: scope, timestamp: options.delete(:timestamp)
63
-
64
- record = find_cached cache_key
65
-
66
- unless record.present?
44
+ cache_key = cache_key_for(id, cache_timestamp)
45
+ missed = (fetched_data = cache_key.read).nil?
46
+ puts "===== CACHE #{(missed ? 'MISS: ' : 'HIT: ')} '#{cache_key}'"
47
+ end
67
48
 
68
- # Load the record from the ECM server:
69
- record = find_single_without_caching(scope, options)
49
+ # Si no lo obtuvimos del caché, traer uno del server:
70
50
 
71
- # Cache the record by writing the record's attributes to the cache store,
72
- # IF the attributes have not been written before:
73
- cache.write(record.cache_key, record.attributes) unless cache.exist? record.cache_key
74
- end
75
-
76
- record
51
+ unless fetched_data.present?
52
+ fetched_data = fetch_one(id)
53
+ end
54
+
55
+ # Inicializar el recurso con los datos obtenidos:
56
+ resource = self.load fetched_data
57
+
58
+ # Write unless data exists:
59
+ if missed
60
+ puts "===== Cache WRITE: '#{resource.cache_key}'"
61
+ cache.write(resource.cache_key, fetched_data)
77
62
  end
78
- end
79
63
 
64
+ resource
65
+ end
80
66
  end
67
+
81
68
  end
82
- end
69
+ end
@@ -2,35 +2,58 @@ require 'active_support/concern'
2
2
  require 'state_machine'
3
3
 
4
4
  module NaranyaEcm
5
- module Lifecycles
6
5
 
7
- module ContentLifecycle
8
- extend ActiveSupport::Concern
6
+ module ContentLifecycle
7
+ extend ActiveSupport::Concern
9
8
 
10
- included do
9
+ included do
11
10
 
12
- include NaranyaEcm::Lifecycles::Lifecycleable
11
+ state_machine :lifecycle_state, initial: :draft do
12
+ state :draft
13
+ state :awaiting_validation
14
+ state :accepted
15
+ state :rejected
16
+ state :published
17
+ state :inactive
13
18
 
14
- ##################################################################
15
- # StateMachine:
16
- state_machine :lifecycle_state, initial: :draft do
19
+ event :send_to_validation do
20
+ transition :draft => :awaiting_validation
21
+ end
17
22
 
18
- state :draft
23
+ event :accept do
24
+ transition :awaiting_validation => :accepted
25
+ end
19
26
 
20
- state :awaiting_validation
27
+ event :reject do
28
+ transition [:awaiting_validation, :published] => :rejected
29
+ end
21
30
 
22
- state :rejected
31
+ event :publish do
32
+ transition :draft => :published, if: :simple_lifecycle?
33
+ transition :accepted => :published, if: :validation_lifecycle?
34
+ end
23
35
 
24
- state :validated
36
+ event :deactivate do
37
+ transition any => :inactive
38
+ end
25
39
 
26
- state :published
40
+ ######
41
+ after_transition :on => any, do: :commit_lifecycle_state_change!
42
+ end
27
43
 
28
- state :deactivated
44
+
45
+ end
29
46
 
30
- end
31
- end
47
+ def simple_lifecycle?; self.lifecycle_name == 'simple'; end
48
+ def validation_lifecycle?; self.lifecycle_name == 'validation'; end
32
49
 
50
+ def commit_lifecycle_state_change!(transition)
51
+ off_band_changes["#{transition.attribute}_event"] = transition.event
52
+ self.send "reset_#{transition.attribute}!".to_sym
53
+ self.save
33
54
  end
34
55
 
56
+
35
57
  end
58
+
36
59
  end
@@ -1,40 +1,21 @@
1
- require 'active_resource'
2
1
 
3
- module NaranyaEcm::Models
4
- class Category < ::ActiveResource::Base
5
-
6
- include NaranyaEcm::Behaviors::Resourceable
2
+ module NaranyaEcm
3
+ class Category
7
4
 
5
+ include NaranyaEcm.document_module
8
6
  include NaranyaEcm::Behaviors::Timestampable
9
-
10
- include NaranyaEcm::Search::Methods
11
7
  include NaranyaEcm::Cache::Methods
8
+ include NaranyaEcm::Search::Methods
9
+ include NaranyaEcm::Behaviors::Mediable
12
10
 
13
- class NameTranslations < ::ActiveResource::Base
14
- include NaranyaEcm::Behaviors::Localizable
15
- end
16
-
17
- self.include_root_in_json = true
18
-
19
- # Definir los atributos conocidos:
20
- schema do
21
- # define each attribute separately
22
- string :id, :code, :created_at, :updated_at
23
-
24
- # unsupported types should be left as strings
25
- # overload the accessor methods if you need to convert them
26
- #attribute 'created_at', 'string'
27
- attribute 'name_translations', 'string'
28
- attribute 'description_translations', 'string'
29
-
30
- end
11
+ field :code, type: String
12
+ validates :code, presence: true
31
13
 
32
- delegate :name, to: :name_translations
33
- delegate :description, to: :title_translations
14
+ field :name, type: String, localize: true
15
+
16
+ has_many :media_resources
34
17
 
35
- def contents
36
- Content.find :all, params: { category_id: self.id }
37
- end
18
+ has_many :contents
38
19
 
39
20
  end
40
21
  end
@@ -1,84 +1,84 @@
1
- require 'active_resource'
2
1
 
3
- module NaranyaEcm::Models
4
- class Content < ::ActiveResource::Base
2
+ module NaranyaEcm
3
+ class Content
5
4
 
6
- include ActiveModel::Dirty
7
-
8
- include NaranyaEcm::Behaviors::Resourceable
9
-
10
- include NaranyaEcm::Search::Methods
5
+ include NaranyaEcm.document_module
6
+ include NaranyaEcm::Behaviors::Timestampable
11
7
  include NaranyaEcm::Cache::Methods
8
+ include NaranyaEcm::Search::Methods
9
+ include NaranyaEcm::Behaviors::Mediable
10
+
11
+ # Type:
12
+ # Describes the main type of the content - App, Note, etc.
13
+ field :type, type: String
14
+
15
+ # Content Lifecycle Name:
16
+ # Determines the lifecycle for the specific content:
17
+ # - simple: draft -> published -> inactive
18
+ # - validatable: draft -> awaiting_validation -> validated -> published -> inactive
19
+ # - expirable: draft -> published -> expired/inactive
20
+ field :lifecycle_name, type: String, default: -> { 'simple' }
21
+ validates :lifecycle_name, presence: true
22
+
23
+ # Content Lifecycle State:
24
+ # A managed string that describes the current state of this particular content.
25
+ # Depending on the Content's lifecycle, it changes upon several events.
26
+ # - draft:
27
+ # - awaiting_validation:
28
+ # - validated:
29
+ # - invalidated:
30
+ # - published:
31
+ field :lifecycle_state, type: String, default: -> { :draft }
32
+ validates :lifecycle_state, presence: true
33
+
34
+ # Title (Localized):
35
+ # The content title that can be displayed as header, result, etc.
36
+ field :title, type: String, localize: true
37
+ validate :at_least_one_title_translation_must_exist
38
+
39
+ # Description (Localized):
40
+ # The content title that can be displayed as header, result, etc.
41
+ field :description, type: String, localize: true
12
42
 
13
- class TitleTranslations < EmbeddedLocalizedHash; end
14
- class DescriptionTranslations < EmbeddedLocalizedHash; end
15
- class ContentRating < EmbeddedHash; end
16
-
17
- self.include_root_in_json = true
18
-
19
- has_many :versions, class_name: "naranya_ecm/models/content_version"
20
- belongs_to :current_version, class_name: "naranya_ecm/models/content_version"
21
-
22
- belongs_to :category, class_name: "naranya_ecm/models/category"
23
-
24
- has_many :media_resources, class_name: "naranya_ecm/models/media_resource"
25
-
26
- # Definir los atributos conocidos:
27
- schema do
28
- # define each attribute separately
29
- string :id, :type, :lifecycle_name, :lifecycle_state, :content_rating, :created_at, :updated_at
30
- string :category_id
31
- string :author
32
- string :main_url
33
-
34
- # unsupported types should be left as strings
35
- # overload the accessor methods if you need to convert them
36
- #attribute 'created_at', 'string'
37
- attribute 'title_translations', 'string'
38
- attribute 'description_translations', 'string'
39
- attribute 'keywords', 'string'
40
-
41
- if NaranyaEcm.options[:extra_attributes] && NaranyaEcm.options[:extra_attributes][:content]
42
- NaranyaEcm.options[:extra_attributes][:content].each { |key, val| attribute key, val }
43
- end
44
-
45
- end
46
-
47
- schema_attrs = self.schema.keys.map(&:to_sym)
48
- define_attribute_methods(*schema_attrs)
49
- schema_attrs.each do |attr_sym|
50
- # getter:
51
- define_method(attr_sym) { @attributes[attr_sym] }
52
- # setter:
53
- define_method("#{attr_sym}=".to_sym) do |value|
54
- self.send "#{attr_sym}_will_change!".to_sym unless value == @attributes[attr_sym]
55
- @attributes[attr_sym] = value
56
- end
57
- end
58
-
59
- delegate :title, to: :title_translations
60
- delegate :description, to: :description_translations
61
-
62
- def initialize(attributes = {}, persisted = false)
63
- super
64
- attributes[:title_translations] = TitleTranslations.new unless attributes[:title_translations].present?
65
- attributes[:description_translations] = DescriptionTranslations.new unless attributes[:description_translations].present?
66
- attributes[:content_rating] = ContentRating.new unless attributes[:content_rating].present?
67
- end
43
+ # Content Rating:
44
+ field :content_rating, type: Hash
45
+
46
+ # Keywords:
47
+ field :keywords, type: Array
48
+
49
+ # Author:
50
+ # The name of the user who created this content.
51
+ field :author, type: String
52
+ validates :author,
53
+ presence: true
54
+
55
+ # Main URL:
56
+ # The URL that should be used to render or display the content.
57
+ field :main_url, type: String
58
+ validates :main_url,
59
+ format: { with: URI.regexp },
60
+ allow_nil: true,
61
+ allow_blank: true
62
+
63
+ belongs_to :category
64
+
65
+ has_many :versions,
66
+ class_name: :ContentVersion
68
67
 
69
- include NaranyaEcm::Behaviors::Timestampable
68
+ belongs_to :current_version,
69
+ class_name: :ContentVersion
70
70
 
71
- before_save :keywords_array!
71
+ has_many :media_resources,
72
+ class_name: :MediaResource,
73
+ inverse_of: :content
72
74
 
73
- def keywords_array!
74
- unless self.attributes[:keywords].is_a?(Array)
75
- self.attributes[:keywords] = if self.attributes[:keywords]=='' then []
76
- else [self.attributes[:keywords]]
77
- end
78
- end
79
- end
75
+ include NaranyaEcm::ContentLifecycle
80
76
 
81
- #include NaranyaEcm::Lifecycles::ContentLifecycle
77
+ private
78
+
79
+ def at_least_one_title_translation_must_exist
80
+ errors.add :title_translations, "must have at least one translation" unless title_translations.keys.any?
81
+ end
82
82
 
83
83
  end
84
84
  end