2011-10-30 23:02:41 +00:00
|
|
|
module Locomotive
|
|
|
|
class ContentType
|
|
|
|
|
|
|
|
include Locomotive::Mongoid::Document
|
|
|
|
|
|
|
|
## extensions ##
|
2011-12-19 13:15:11 +00:00
|
|
|
include CustomFields::Source
|
2012-03-12 02:09:20 +00:00
|
|
|
include Extensions::ContentType::DefaultValues
|
2011-10-30 23:02:41 +00:00
|
|
|
include Extensions::ContentType::ItemTemplate
|
2012-03-12 02:09:20 +00:00
|
|
|
include Extensions::ContentType::Sync
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## fields ##
|
|
|
|
field :name
|
|
|
|
field :description
|
|
|
|
field :slug
|
2012-01-09 14:49:59 +00:00
|
|
|
field :label_field_id, :type => BSON::ObjectId
|
2012-01-02 13:54:01 +00:00
|
|
|
field :label_field_name
|
2012-01-09 14:49:59 +00:00
|
|
|
field :group_by_field_id, :type => BSON::ObjectId
|
2011-10-30 23:02:41 +00:00
|
|
|
field :order_by
|
2012-01-09 14:49:59 +00:00
|
|
|
field :order_direction, :default => 'asc'
|
|
|
|
field :public_submission_enabled, :type => Boolean, :default => false
|
|
|
|
field :public_submission_accounts, :type => Array
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## associations ##
|
2011-12-16 12:02:10 +00:00
|
|
|
belongs_to :site, :class_name => 'Locomotive::Site'
|
2011-12-22 23:45:32 +00:00
|
|
|
has_many :entries, :class_name => 'Locomotive::ContentEntry', :dependent => :destroy
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## named scopes ##
|
|
|
|
scope :ordered, :order_by => :updated_at.desc
|
|
|
|
|
|
|
|
## indexes ##
|
|
|
|
index [[:site_id, Mongo::ASCENDING], [:slug, Mongo::ASCENDING]]
|
|
|
|
|
|
|
|
## callbacks ##
|
2011-11-03 13:01:08 +00:00
|
|
|
before_validation :normalize_slug
|
2011-12-21 14:24:39 +00:00
|
|
|
after_validation :bubble_fields_errors_up
|
2012-02-01 01:01:42 +00:00
|
|
|
before_update :update_label_field_name_in_entries
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## validations ##
|
2011-11-03 13:01:08 +00:00
|
|
|
validates_presence_of :site, :name, :slug
|
2011-10-30 23:02:41 +00:00
|
|
|
validates_uniqueness_of :slug, :scope => :site_id
|
2012-01-18 00:43:01 +00:00
|
|
|
validates_size_of :entries_custom_fields, :minimum => 1, :message => :too_few_custom_fields
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## behaviours ##
|
2011-12-22 23:45:32 +00:00
|
|
|
custom_fields_for :entries
|
2011-10-30 23:02:41 +00:00
|
|
|
|
|
|
|
## methods ##
|
|
|
|
|
2012-01-04 01:07:53 +00:00
|
|
|
def order_manually?
|
|
|
|
self.order_by == '_position'
|
|
|
|
end
|
2011-10-30 23:02:41 +00:00
|
|
|
|
2012-01-04 01:07:53 +00:00
|
|
|
def order_by_definition
|
|
|
|
direction = self.order_manually? ? 'asc' : self.order_direction || 'asc'
|
|
|
|
[order_by_attribute, direction]
|
2011-12-22 00:31:33 +00:00
|
|
|
end
|
|
|
|
|
2012-01-09 14:49:59 +00:00
|
|
|
def ordered_entries(conditions = {})
|
2012-03-09 00:01:09 +00:00
|
|
|
_order_by_definition = (conditions || {}).delete(:order_by).try(:split) || self.order_by_definition
|
|
|
|
self.entries.order_by([_order_by_definition]).where(conditions)
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
|
|
|
|
2012-01-04 01:07:53 +00:00
|
|
|
def groupable?
|
2012-03-07 00:39:24 +00:00
|
|
|
!!self.group_by_field && %w(select belongs_to).include?(group_by_field.type)
|
2012-01-04 01:07:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def group_by_field
|
|
|
|
self.entries_custom_fields.find(self.group_by_field_id) rescue nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def list_or_group_entries
|
|
|
|
if self.groupable?
|
2012-03-07 00:39:24 +00:00
|
|
|
if group_by_field.type == 'select'
|
|
|
|
self.entries.group_by_select_option(self.group_by_field.name, self.order_by_definition)
|
|
|
|
else
|
|
|
|
group_by_belongs_to_field(self.group_by_field)
|
|
|
|
end
|
2012-01-04 01:07:53 +00:00
|
|
|
else
|
|
|
|
self.ordered_entries
|
|
|
|
end
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
|
|
|
|
2012-02-02 15:53:26 +00:00
|
|
|
def class_name_to_content_type(class_name)
|
|
|
|
self.class.class_name_to_content_type(class_name, self.site)
|
|
|
|
end
|
|
|
|
|
2012-02-20 15:16:59 +00:00
|
|
|
def label_field_name=(value)
|
|
|
|
# mandatory if we allow the API to set the label field name without an id of the field
|
|
|
|
@new_label_field_name = value unless value.blank?
|
|
|
|
super(value)
|
|
|
|
end
|
|
|
|
|
2012-02-02 15:53:26 +00:00
|
|
|
# Retrieve from a class name the associated content type within the scope of a site.
|
|
|
|
# If no content type is found, the method returns nil
|
|
|
|
#
|
|
|
|
# @param [ String ] class_name The class name
|
|
|
|
# @param [ Locomotive::Site ] site The Locomotive site
|
|
|
|
#
|
|
|
|
# @return [ Locomotive::ContentType ] The content type matching the class_name
|
|
|
|
#
|
|
|
|
def self.class_name_to_content_type(class_name, site)
|
|
|
|
if class_name =~ /^Locomotive::Entry(.*)/
|
|
|
|
site.content_types.find($1)
|
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-12-21 14:24:39 +00:00
|
|
|
def to_presenter
|
|
|
|
Locomotive::ContentTypePresenter.new(self)
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
|
|
|
|
2011-12-21 14:24:39 +00:00
|
|
|
def as_json(options = {})
|
|
|
|
self.to_presenter.as_json
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
2012-03-07 00:39:24 +00:00
|
|
|
def group_by_belongs_to_field(field)
|
|
|
|
grouped_entries = self.ordered_entries.group_by(&:"#{field.name}_id")
|
|
|
|
columns = grouped_entries.keys
|
|
|
|
target_content_type = self.class_name_to_content_type(field.class_name)
|
|
|
|
all_columns = target_content_type.ordered_entries
|
|
|
|
|
|
|
|
all_columns.map do |column|
|
|
|
|
if columns.include?(column._id)
|
|
|
|
{
|
|
|
|
:name => column._label(target_content_type),
|
|
|
|
:entries => grouped_entries.delete(column._id)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end.compact.tap do |groups|
|
|
|
|
unless grouped_entries.empty? # "orphans" ?
|
|
|
|
groups << { :name => nil, :entries => grouped_entries.values.flatten }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-04 01:07:53 +00:00
|
|
|
def order_by_attribute
|
|
|
|
return self.order_by if %w(created_at updated_at _position).include?(self.order_by)
|
|
|
|
self.entries_custom_fields.find(self.order_by).name rescue 'created_at'
|
|
|
|
end
|
|
|
|
|
2011-10-30 23:02:41 +00:00
|
|
|
def normalize_slug
|
|
|
|
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
|
|
|
self.slug.permalink! if self.slug.present?
|
|
|
|
end
|
|
|
|
|
2011-12-21 14:24:39 +00:00
|
|
|
def bubble_fields_errors_up
|
2011-12-22 23:45:32 +00:00
|
|
|
return if self.errors[:entries_custom_fields].empty?
|
2011-12-21 14:24:39 +00:00
|
|
|
|
2012-01-18 00:43:01 +00:00
|
|
|
hash = { :base => self.errors[:entries_custom_fields] }
|
2011-12-21 14:24:39 +00:00
|
|
|
|
2011-12-22 23:45:32 +00:00
|
|
|
self.entries_custom_fields.each do |field|
|
2011-12-21 14:24:39 +00:00
|
|
|
next if field.valid?
|
2012-01-18 00:43:01 +00:00
|
|
|
key = field.persisted? ? field._id.to_s : field.position.to_i
|
|
|
|
hash[key] = field.errors.to_a
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
2012-01-18 00:43:01 +00:00
|
|
|
|
|
|
|
self.errors.set(:entries_custom_fields, hash)
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
|
|
|
|
2012-02-01 01:01:42 +00:00
|
|
|
def update_label_field_name_in_entries
|
|
|
|
self.klass_with_custom_fields(:entries).update_all :_label_field_name => self.label_field_name
|
|
|
|
end
|
|
|
|
|
|
|
|
# Makes sure the class_name filled in a belongs_to or has_many field
|
|
|
|
# does not belong to another site. Adds an error if it presents a
|
|
|
|
# security problem.
|
|
|
|
#
|
|
|
|
# @param [ CustomFields::Field ] field The field to check
|
|
|
|
#
|
|
|
|
def ensure_class_name_security(field)
|
|
|
|
if field.class_name =~ /^Locomotive::Entry([a-z0-9]+)$/
|
|
|
|
content_type = Locomotive::ContentType.find($1)
|
|
|
|
|
|
|
|
if content_type.site_id != self.site_id
|
2012-02-03 00:50:45 +00:00
|
|
|
field.errors.add :class_name, :security
|
2012-02-01 01:01:42 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
# for now, does not allow external classes
|
2012-02-03 00:50:45 +00:00
|
|
|
field.errors.add :class_name, :security
|
2012-02-01 01:01:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-30 23:02:41 +00:00
|
|
|
end
|
2011-11-20 10:59:12 +00:00
|
|
|
end
|
2012-01-09 14:49:59 +00:00
|
|
|
|