From 76e29aed97e98044fede7f4a280abc96b80d58a6 Mon Sep 17 00:00:00 2001 From: Braulio Bhavamitra Date: Sat, 16 Jul 2016 12:04:06 -0300 Subject: [PATCH] concerns: move most lib files models concerns --- app/mailers/mailing.rb | 3 ++- app/models/article.rb | 6 +++++- app/models/block.rb | 1 + app/models/blog.rb | 2 ++ app/models/category.rb | 2 ++ app/models/comment.rb | 1 + app/models/concerns/acts_as_filesystem.rb | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/acts_as_having_boxes.rb | 37 +++++++++++++++++++++++++++++++++++++ app/models/concerns/acts_as_having_image.rb | 25 +++++++++++++++++++++++++ app/models/concerns/acts_as_having_posts.rb | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/acts_as_having_settings.rb | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/code_numbering.rb | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/customizable.rb | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/delayed_attachment_fu.rb | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/set_profile_region_from_city_state.rb | 44 ++++++++++++++++++++++++++++++++++++++++++++ app/models/concerns/translatable_content.rb | 8 ++++++++ app/models/concerns/white_list_filter.rb | 37 +++++++++++++++++++++++++++++++++++++ app/models/create_community.rb | 1 + app/models/environment.rb | 4 +++- app/models/event.rb | 3 +-- app/models/folder.rb | 3 ++- app/models/forum.rb | 2 ++ app/models/image.rb | 1 + app/models/profile.rb | 7 ++++++- app/models/profile_suggestion.rb | 3 ++- app/models/task.rb | 3 ++- app/models/text_article.rb | 4 +--- app/models/tiny_mce_article.rb | 2 -- app/models/uploaded_file.rb | 1 + config/initializers/00_dependencies.rb | 8 -------- config/initializers/delayed_attachment_fu.rb | 1 - db/migrate/20160422163123_enable_products_plugin_on_environments.rb | 1 + lib/acts_as_customizable.rb | 125 ----------------------------------------------------------------------------------------------------------------------------- lib/acts_as_filesystem.rb | 267 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- lib/acts_as_having_boxes.rb | 38 -------------------------------------- lib/acts_as_having_image.rb | 27 --------------------------- lib/acts_as_having_posts.rb | 51 --------------------------------------------------- lib/acts_as_having_settings.rb | 91 ------------------------------------------------------------------------------------------- lib/code_numbering.rb | 58 ---------------------------------------------------------- lib/delayed_attachment_fu.rb | 56 -------------------------------------------------------- lib/noosfero/translatable_content.rb | 7 ------- lib/set_profile_region_from_city_state.rb | 44 -------------------------------------------- lib/white_list_filter.rb | 37 ------------------------------------- plugins/analytics/models/analytics_plugin/page_view.rb | 1 + plugins/fb_app/models/fb_app_plugin/page_tab.rb | 1 + plugins/newsletter/lib/newsletter_plugin/newsletter.rb | 1 + plugins/oauth_client/models/oauth_client_plugin/auth.rb | 1 + plugins/oauth_client/models/oauth_client_plugin/provider.rb | 5 +++-- plugins/products/models/products_plugin/product.rb | 2 ++ plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb | 1 + plugins/video/lib/video_plugin/video.rb | 1 - plugins/video/lib/video_plugin/video_gallery.rb | 3 ++- test/unit/event_test.rb | 2 +- test/unit/text_article_test.rb | 2 +- test/unit/translatable_content_test.rb | 2 +- 55 files changed, 841 insertions(+), 831 deletions(-) create mode 100644 app/models/concerns/acts_as_filesystem.rb create mode 100644 app/models/concerns/acts_as_having_boxes.rb create mode 100644 app/models/concerns/acts_as_having_image.rb create mode 100644 app/models/concerns/acts_as_having_posts.rb create mode 100644 app/models/concerns/acts_as_having_settings.rb create mode 100644 app/models/concerns/code_numbering.rb create mode 100644 app/models/concerns/customizable.rb create mode 100644 app/models/concerns/delayed_attachment_fu.rb create mode 100644 app/models/concerns/set_profile_region_from_city_state.rb create mode 100644 app/models/concerns/translatable_content.rb create mode 100644 app/models/concerns/white_list_filter.rb delete mode 100644 config/initializers/delayed_attachment_fu.rb delete mode 100644 lib/acts_as_customizable.rb delete mode 100644 lib/acts_as_filesystem.rb delete mode 100644 lib/acts_as_having_boxes.rb delete mode 100644 lib/acts_as_having_image.rb delete mode 100644 lib/acts_as_having_posts.rb delete mode 100644 lib/acts_as_having_settings.rb delete mode 100644 lib/code_numbering.rb delete mode 100644 lib/delayed_attachment_fu.rb delete mode 100644 lib/noosfero/translatable_content.rb delete mode 100644 lib/set_profile_region_from_city_state.rb delete mode 100644 lib/white_list_filter.rb diff --git a/app/mailers/mailing.rb b/app/mailers/mailing.rb index 2c13be8..09df5c9 100644 --- a/app/mailers/mailing.rb +++ b/app/mailers/mailing.rb @@ -2,7 +2,8 @@ require_dependency 'mailing_job' class Mailing < ApplicationRecord - acts_as_having_settings :field => :data + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :data attr_accessible :subject, :body, :data diff --git a/app/models/article.rb b/app/models/article.rb index e5898f2..a7bbcd8 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -13,7 +13,9 @@ class Article < ApplicationRecord :image_builder, :show_to_followers, :archived, :author, :display_preview, :published_at, :person_followers + extend ActsAsHavingImage::ClassMethods acts_as_having_image + include Noosfero::Plugin::HotSpot SEARCHABLE_FIELDS = { @@ -91,7 +93,8 @@ class Article < ApplicationRecord has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization' has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category - acts_as_having_settings :field => :setting + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :setting settings_items :display_hits, :type => :boolean, :default => true settings_items :author_name, :type => :string, :default => "" @@ -242,6 +245,7 @@ class Article < ApplicationRecord acts_as_taggable N_('Tag list') + extend ActsAsFilesystem::ActsMethods acts_as_filesystem acts_as_versioned diff --git a/app/models/block.rb b/app/models/block.rb index a32bfbb..f3379c7 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -17,6 +17,7 @@ class Block < ApplicationRecord belongs_to :mirror_block, :class_name => "Block" has_many :observers, :class_name => "Block", :foreign_key => "mirror_block_id" + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings scope :enabled, -> { where :enabled => true } diff --git a/app/models/blog.rb b/app/models/blog.rb index cb4722e..20d858c 100644 --- a/app/models/blog.rb +++ b/app/models/blog.rb @@ -2,7 +2,9 @@ class Blog < Folder attr_accessible :visualization_format + extend ActsAsHavingPosts::ClassMethods acts_as_having_posts + include PostsLimit #FIXME This should be used until there is a migration to fix all blogs that diff --git a/app/models/category.rb b/app/models/category.rb index 37e859d..1a83d90 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -21,6 +21,7 @@ class Category < ApplicationRecord scope :on_level, -> parent { where :parent_id => parent } + extend ActsAsFilesystem::ActsMethods acts_as_filesystem has_many :article_categorizations @@ -35,6 +36,7 @@ class Category < ApplicationRecord has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' + extend ActsAsHavingImage::ClassMethods acts_as_having_image before_save :normalize_display_color diff --git a/app/models/comment.rb b/app/models/comment.rb index b79be4d..94c44f3 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -38,6 +38,7 @@ class Comment < ApplicationRecord validate :article_archived? + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings xss_terminate :only => [ :body, :title, :name ], :on => 'validation' diff --git a/app/models/concerns/acts_as_filesystem.rb b/app/models/concerns/acts_as_filesystem.rb new file mode 100644 index 0000000..b3bcb52 --- /dev/null +++ b/app/models/concerns/acts_as_filesystem.rb @@ -0,0 +1,265 @@ +module ActsAsFilesystem + + module ActsMethods + + # Declares the ActiveRecord model to acts like a filesystem: objects are + # arranged in a tree (liks acts_as_tree), and . The underlying table must + # have the following fields: + # + # * name (+:string+) - the title of the object + # * slug (+:string+)- the title turned in a URL-friendly string (downcased, + # non-ascii chars transliterated into ascii, all sequences of + # non-alphanumericd characters changed into dashed) + # * path (+:text+)- stores the full path of the object (the full path of + # the parent, a "/" and the slug of the object) + # * children_count - a cache of the number of children elements. + def acts_as_filesystem + # a filesystem is a tree + acts_as_tree :counter_cache => :children_count + + extend ClassMethods + include InstanceMethods + if self.has_path? + after_update :update_children_path + before_create :set_path + include InstanceMethods::PathMethods + end + + before_save :set_ancestry + end + + end + + module ClassMethods + + def build_ancestry(parent_id = nil, ancestry = '') + ActiveRecord::Base.transaction do + self.base_class.where(parent_id: parent_id).each do |node| + node.update_column :ancestry, ancestry + + build_ancestry node.id, (ancestry.empty? ? "#{node.formatted_ancestry_id}" : + "#{ancestry}#{node.ancestry_sep}#{node.formatted_ancestry_id}") + end + end + + #raise "Couldn't reach and set ancestry on every record" if self.base_class.where('ancestry is null').count != 0 + end + + def has_path? + (['name', 'slug', 'path'] - self.column_names).blank? + end + + end + + module InstanceMethods + + def ancestry_column + 'ancestry' + end + def ancestry_sep + '.' + end + def has_ancestry? + self.class.column_names.include? self.ancestry_column + end + + def formatted_ancestry_id + "%010d" % self.id if self.id + end + + def ancestry + self[ancestry_column] + end + def ancestor_ids + return nil if !has_ancestry? or ancestry.nil? + @ancestor_ids ||= ancestry.split(ancestry_sep).map{ |id| id.to_i } + end + + def ancestry=(value) + self[ancestry_column] = value + end + def set_ancestry + return unless self.has_ancestry? + if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path + self.ancestry = self.hierarchy(true)[0...-1].map{ |p| p.formatted_ancestry_id }.join(ancestry_sep) + end + end + + def descendents_options + ["#{self.ancestry_column} LIKE ?", "%#{self.formatted_ancestry_id}%"] + end + def descendents + self.class.where descendents_options + end + + # calculates the level of the record in the records hierarchy. Top-level + # records have level 0; the children of the top-level records have + # level 1; the children of records with level 1 have level 2, and so on. + # + # A level 0 + # / \ + # B C level 1 + # / \ / \ + # E F G H level 2 + # ... + def level + self.hierarchy.size - 1 + end + + # Is this record a top-level record? + def top_level? + self.parent.nil? + end + + # Is this record a leaf in the hierarchy tree of records? + # + # Being a leaf means that this record has no subrecord. + def leaf? + self.children.empty? + end + + def top_ancestor + if has_ancestry? and !ancestry.blank? + self.class.base_class.find_by id: self.top_ancestor_id + else + self.hierarchy.first + end + end + def top_ancestor_id + if has_ancestry? and !ancestry.nil? + self.ancestor_ids.first + else + self.hierarchy.first.id + end + end + + # returns the full hierarchy from the top-level item to this one. For + # example, if item1 has a children item2 and item2 has a children item3, + # then item3's hierarchy would be [item1, item2, item3]. + # + # If +reload+ is passed as +true+, then the hierarchy is reload (usefull + # when the ActiveRecord object was modified in some way, or just after + # changing parent) + def hierarchy(reload = false) + @hierarchy = nil if reload or recalculate_path + + if @hierarchy.nil? + @hierarchy = [] + + if !reload and !recalculate_path and ancestor_ids + objects = self.class.base_class.where(id: ancestor_ids) + ancestor_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } } + @hierarchy << self + else + item = self + while item + @hierarchy.unshift(item) + item = item.parent + end + end + end + + @hierarchy + end + + def map_traversal(&block) + result = [] + current_level = [self] + + while !current_level.empty? + result += current_level + ids = current_level.select {|item| item.children_count > 0}.map(&:id) + break if ids.empty? + current_level = self.class.base_class.where(parent_id: ids) + end + block ||= (lambda { |x| x }) + result.map(&block) + end + + def all_children + res = map_traversal + res.shift + res + end + + ##### + # Path methods + # These methods are used when _path_, _name_ and _slug_ attributes exist + # and should be calculated based on the tree + ##### + module PathMethods + # used to know when to trigger batch renaming + attr_accessor :recalculate_path + + # calculates the full path to this record using parent's path. + def calculate_path + self.hierarchy.map{ |obj| obj.slug }.join('/') + end + def set_path + if self.path == self.slug && !self.top_level? + self.path = self.calculate_path + end + end + def explode_path + path.split(/\//) + end + + def update_children_path + if self.recalculate_path + self.children.each do |child| + child.path = child.calculate_path + child.recalculate_path = true + child.save! + end + end + self.recalculate_path = false + end + + # calculates the full name of a record by accessing the name of all its + # ancestors. + # + # If you have this record hierarchy: + # Record "A" + # Record "B" + # Record "C" + # + # Then Record "C" will have "A/B/C" as its full name. + def full_name(sep = '/') + self.hierarchy.map {|item| item.name || '?' }.join(sep) + end + + # gets the name without leading parents. Useful when dividing records + # in top-level groups and full names must not include the top-level + # record which is already a emphasized label + def full_name_without_leading(count, sep = '/') + parts = self.full_name(sep).split(sep) + count.times { parts.shift } + parts.join(sep) + end + + def set_name(value) + if self.name != value + self.recalculate_path = true + end + self[:name] = value + end + + # sets the name of the record. Also sets #slug accordingly. + def name=(value) + self.set_name(value) + unless self.name.blank? + self.slug = self.name.to_slug + end + end + + # sets the slug of the record. Also sets the path with the new slug value. + def slug=(value) + self[:slug] = value + unless self.slug.blank? + self.path = self.calculate_path + end + end + end + end +end + diff --git a/app/models/concerns/acts_as_having_boxes.rb b/app/models/concerns/acts_as_having_boxes.rb new file mode 100644 index 0000000..687a1a4 --- /dev/null +++ b/app/models/concerns/acts_as_having_boxes.rb @@ -0,0 +1,37 @@ +module ActsAsHavingBoxes + + module ClassMethods + def acts_as_having_boxes + has_many :boxes, -> { order :position }, as: :owner, dependent: :destroy + self.send(:include, ActsAsHavingBoxes) + end + end + + module BlockArray + def find(id) + select { |item| item.id == id.to_i }.first + end + end + + def blocks(reload = false) + if (reload) + @blocks = nil + end + if @blocks.nil? + @blocks = boxes.includes(:blocks).inject([]) do |acc,obj| + acc.concat(obj.blocks) + end + @blocks.send(:extend, BlockArray) + end + @blocks + end + + # returns 3 unless the class table has a boxes_limit column. In that case + # return the value of the column. + def boxes_limit layout_template = nil + layout_template ||= self.layout_template + @boxes_limit ||= LayoutTemplate.find(layout_template).number_of_boxes || 3 + end + +end + diff --git a/app/models/concerns/acts_as_having_image.rb b/app/models/concerns/acts_as_having_image.rb new file mode 100644 index 0000000..da1b2da --- /dev/null +++ b/app/models/concerns/acts_as_having_image.rb @@ -0,0 +1,25 @@ +module ActsAsHavingImage + + module ClassMethods + def acts_as_having_image + belongs_to :image, dependent: :destroy + scope :with_image, -> { where "#{table_name}.image_id IS NOT NULL" } + scope :without_image, -> { where "#{table_name}.image_id IS NULL" } + attr_accessible :image_builder + include ActsAsHavingImage + end + end + + def image_builder=(img) + if image && image.id == img[:id] + image.attributes = img + else + build_image(img) + end unless img[:uploaded_data].blank? + if img[:remove_image] == 'true' + self.image_id = nil + end + end + +end + diff --git a/app/models/concerns/acts_as_having_posts.rb b/app/models/concerns/acts_as_having_posts.rb new file mode 100644 index 0000000..0ed1781 --- /dev/null +++ b/app/models/concerns/acts_as_having_posts.rb @@ -0,0 +1,49 @@ +module ActsAsHavingPosts + + module ClassMethods + def acts_as_having_posts(scope = nil) + has_many :posts, -> { + s = order('published_at DESC, id DESC').where('articles.type != ?', 'RssFeed') + s = s.instance_exec(&scope) if scope + s + }, class_name: 'Article', foreign_key: 'parent_id', source: :children + + attr_accessor :feed_attrs + + after_create do |blog| + blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile) + blog.feed = blog.feed_attrs + end + + settings_items :posts_per_page, :type => :integer, :default => 5 + + self.send(:include, ActsAsHavingPosts) + end + end + + def has_posts? + true + end + + def feed + children.where(:type => 'RssFeed').first + end + + def feed=(attrs) + if attrs + if self.feed + self.feed.update(attrs) + else + self.feed_attrs = attrs + end + end + self.feed + end + + def name=(value) + self.set_name(value) + self.slug = self.slug.blank? ? self.name.to_slug : self.slug.to_slug + end + +end + diff --git a/app/models/concerns/acts_as_having_settings.rb b/app/models/concerns/acts_as_having_settings.rb new file mode 100644 index 0000000..ff727f3 --- /dev/null +++ b/app/models/concerns/acts_as_having_settings.rb @@ -0,0 +1,89 @@ +# declare missing types +module ActiveRecord + module Type + class Symbol < Value + def cast_value value + value.to_sym + end + end + class Array < Value + def cast_value value + ::Array.wrap(value) + end + end + class Hash < Value + def cast_value value + h = ::Hash[value] + h.symbolize_keys! + h + end + end + end +end + +module ActsAsHavingSettings + + def self.type_cast value, type + # do not cast nil + return value if value.nil? + type.send :cast_value, value + end + + module ClassMethods + + def acts_as_having_settings(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + field = (options[:field] || :settings).to_sym + + serialize field, Hash + class_attribute :settings_field + self.settings_field = field + + class_eval do + def settings_field + self[self.class.settings_field] ||= Hash.new + end + + def setting_changed? setting_field + setting_field = setting_field.to_sym + changed_settings = self.changes[self.class.settings_field] + return false if changed_settings.nil? + + old_setting_value = changed_settings.first.nil? ? nil : changed_settings.first[setting_field] + new_setting_value = changed_settings.last[setting_field] + old_setting_value != new_setting_value + end + end + + settings_items *args + end + + def settings_items *names + + options = names.extract_options! + default = options[:default] + type = options[:type] + type = if type.present? then ActiveRecord::Type.const_get(type.to_s.camelize.to_sym).new else nil end + + names.each do |setting| + # symbolize key + setting = setting.to_sym + + define_method setting do + h = send self.class.settings_field + val = h[setting] + # translate default value if it is used + if not val.nil? then val elsif default.is_a? String then gettext default else default end + end + + define_method "#{setting}=" do |value| + h = send self.class.settings_field + h[setting] = if type then ActsAsHavingSettings.type_cast value, type else value end + end + end + end + + end + +end + diff --git a/app/models/concerns/code_numbering.rb b/app/models/concerns/code_numbering.rb new file mode 100644 index 0000000..5b72829 --- /dev/null +++ b/app/models/concerns/code_numbering.rb @@ -0,0 +1,57 @@ +module CodeNumbering + module ClassMethods + def code_numbering field, options = {} + class_attribute :code_numbering_field + class_attribute :code_numbering_options + + self.code_numbering_field = field + self.code_numbering_options = options + + before_create :create_code_numbering + + include CodeNumbering::InstanceMethods + end + end + + module InstanceMethods + + def code + self.attributes[self.code_numbering_field.to_s] + end + + def code_scope + scope = self.code_numbering_options[:scope] + case scope + when Symbol + self.send scope + when Proc + instance_exec &scope + else + self.class + end + end + + def code_maximum + self.code_scope.maximum(self.code_numbering_field) || 0 + end + + def create_code_numbering + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] + max = self.code_maximum + self.send "#{self.code_numbering_field}=", max+1 + end + + def reset_scope_code_numbering + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] + max ||= 1 + + self.code_scope.order(:created_at).each do |record| + record.update_column self.code_numbering_field, max + max += 1 + end + self.reload + end + + end +end + diff --git a/app/models/concerns/customizable.rb b/app/models/concerns/customizable.rb new file mode 100644 index 0000000..a64a68d --- /dev/null +++ b/app/models/concerns/customizable.rb @@ -0,0 +1,124 @@ +module Customizable + + def self.included(base) + base.attr_accessible :custom_values + base.extend ClassMethods + end + + module ClassMethods + def acts_as_customizable(options = {}) + attr_accessor :custom_values + has_many :custom_field_values, :dependent => :delete_all, :as => :customized + send :include, Customizable::InstanceMethods + after_save :save_custom_values + validate :valid_custom_values? + end + + def active_custom_fields environment + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.active} + end + + def required_custom_fields environment + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.required} + end + + def signup_custom_fields environment + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.signup} + end + + def custom_fields environment + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type)} + end + + def customized_ancestors_list + current=self + result=[] + while current.instance_methods.include? :custom_value do + result << current.name + current=current.superclass + end + result + end + + end + + module InstanceMethods + + def valid_custom_values? + is_valid = true + parse_custom_values.each do |cv| + unless cv.valid? + name = cv.custom_field.name + errors.add(name, cv.errors.messages[name.to_sym].first) + is_valid = false + end + end + is_valid + end + + def customized_class + current=self.class + while current.instance_methods.include? :custom_fields do + result=current + current=current.superclass + end + result.name + end + + def is_public(field_name) + cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} + cv.nil? ? false : cv.public + end + + def public_values + self.custom_field_values.select{|cv| cv.public} + end + + def custom_value(field_name) + cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} + cv.nil? ? default_value_for(field_name) : cv.value + end + + def default_value_for(field_name) + field=self.class.custom_fields(environment).detect {|c| c.name == field_name} + field.nil? ? nil : field.default_value + end + + def parse_custom_values + return_list = [] + return return_list if custom_values.blank? + custom_values.each_pair do |key, value| + custom_field = environment.custom_fields.detect{|cf|cf.name==key} + next if custom_field.blank? + custom_field_value = self.custom_field_values(true).detect{|cv| cv.custom_field.name==key} + + if custom_field_value.nil? + custom_field_value = CustomFieldValue.new + custom_field_value.custom_field = custom_field + custom_field_value.customized = self + end + + if value.is_a?(Hash) + custom_field_value.value = value['value'].to_s + if value.has_key?('public') + is_public = value['public']=="true" || value['public']==true + custom_field_value.public = is_public + else + custom_field_value.public = false + end + else + custom_field_value.value = value.to_s + custom_field_value.public = false + end + return_list << custom_field_value + end + return_list + end + + def save_custom_values + parse_custom_values.each(&:save) + end + + end +end + diff --git a/app/models/concerns/delayed_attachment_fu.rb b/app/models/concerns/delayed_attachment_fu.rb new file mode 100644 index 0000000..aa345a4 --- /dev/null +++ b/app/models/concerns/delayed_attachment_fu.rb @@ -0,0 +1,55 @@ +module DelayedAttachmentFu + + module ClassMethods + def delay_attachment_fu_thumbnails + include DelayedAttachmentFu::InstanceMethods + after_create do |file| + if file.thumbnailable? + Delayed::Job.enqueue CreateThumbnailsJob.new(file.class.name, file.id) + end + end + end + end + + module InstanceMethods + # skip processing with RMagick + def process_attachment + end + + def after_process_attachment + save_to_storage + @temp_paths.clear + @saved_attachment = nil + run_callbacks :after_attachment_saved + end + + def create_thumbnails + if thumbnailable? + self.class.with_image(full_filename) do |img| + self.width = img.columns + self.height = img.rows + self.save! + end + self.class.attachment_options[:thumbnails].each do |suffix, size| + self.create_or_update_thumbnail(self.full_filename, suffix, size) + end + self.thumbnails_processed = true + self.save! + end + end + + def public_filename(size=nil) + force, size = true, nil if size == :uploaded + if !self.thumbnailable? || self.thumbnails_processed || force + super size + else + size ||= :thumb + '/images/icons-app/image-loading-%s.png' % size + end + end + + + end +end + + diff --git a/app/models/concerns/set_profile_region_from_city_state.rb b/app/models/concerns/set_profile_region_from_city_state.rb new file mode 100644 index 0000000..586f56b --- /dev/null +++ b/app/models/concerns/set_profile_region_from_city_state.rb @@ -0,0 +1,44 @@ +module SetProfileRegionFromCityState + + module ClassMethods + def set_profile_region_from_city_state + before_save :region_from_city_and_state + + include InstanceMethods + alias_method_chain :city=, :region + alias_method_chain :state=, :region + end + end + + module InstanceMethods + include Noosfero::Plugin::HotSpot + + def city_with_region=(value) + self.city_without_region = value + @change_region = true + end + + def state_with_region=(value) + self.state_without_region = value + @change_region = true + end + + def region_from_city_and_state + if @change_region + self.region = nil + state = search_region(State, self.state) + self.region = search_region(City.where(:parent_id => state.id), self.city) if state + end + end + + private + + def search_region(scope, query) + return nil if !query + query = query.downcase.strip + scope.where(['lower(name)=? OR lower(abbreviation)=? OR lower(acronym)=?', query, query, query]).first + end + + end + +end diff --git a/app/models/concerns/translatable_content.rb b/app/models/concerns/translatable_content.rb new file mode 100644 index 0000000..2f360a9 --- /dev/null +++ b/app/models/concerns/translatable_content.rb @@ -0,0 +1,8 @@ +module TranslatableContent + + def translatable? + return false if self.profile && !self.profile.environment.languages.present? + parent.nil? || !parent.forum? + end + +end diff --git a/app/models/concerns/white_list_filter.rb b/app/models/concerns/white_list_filter.rb new file mode 100644 index 0000000..8218ba1 --- /dev/null +++ b/app/models/concerns/white_list_filter.rb @@ -0,0 +1,37 @@ +module WhiteListFilter + + def check_iframe_on_content(content, trusted_sites) + if content.blank? || !content.include?('iframe') + return content + end + content.gsub!(/]*>\s*<\/iframe>/i) do |iframe| + result = '' + unless iframe =~ /src=['"].*src=['"]/ + trusted_sites.each do |trusted_site| + re_dom = trusted_site.gsub('.', '\.') + if iframe =~ /src=["'](https?:)?\/\/(www\.)?#{re_dom}\// + result = iframe + end + end + end + result + end + content + end + + module ClassMethods + def filter_iframes(*opts) + options = opts.last.is_a?(Hash) && opts.pop || {} + white_list_method = options[:whitelist] || :iframe_whitelist + opts.each do |field| + before_validation do |obj| + obj.check_iframe_on_content(obj.send(field), obj.send(white_list_method)) + end + end + end + end + + def self.included(c) + c.send(:extend, WhiteListFilter::ClassMethods) + end +end diff --git a/app/models/create_community.rb b/app/models/create_community.rb index f273655..e8ec209 100644 --- a/app/models/create_community.rb +++ b/app/models/create_community.rb @@ -12,6 +12,7 @@ class CreateCommunity < Task attr_accessible :environment, :requestor, :target attr_accessible :reject_explanation, :template_id + extend ActsAsHavingImage::ClassMethods acts_as_having_image DATA_FIELDS = Community.fields + ['name', 'closed', 'description'] diff --git a/app/models/environment.rb b/app/models/environment.rb index 6d54e6d..d4bbd09 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -200,6 +200,7 @@ class Environment < ApplicationRecord # Relationships and applied behaviour # ################################################# + extend ActsAsHavingBoxes::ClassMethods acts_as_having_boxes after_create do |env| @@ -251,7 +252,8 @@ class Environment < ApplicationRecord # ################################################# # store the Environment settings as YAML-serialized Hash. - acts_as_having_settings :field => :settings + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :settings # introduce and explain to users something about the signup settings_items :signup_intro, :type => String diff --git a/app/models/event.rb b/app/models/event.rb index eef64fd..9731d93 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,4 +1,3 @@ -require 'noosfero/translatable_content' require 'builder' class Event < Article @@ -138,7 +137,7 @@ class Event < Article false end - include Noosfero::TranslatableContent + include TranslatableContent include MaybeAddHttp end diff --git a/app/models/folder.rb b/app/models/folder.rb index 26229ac..5951064 100644 --- a/app/models/folder.rb +++ b/app/models/folder.rb @@ -10,7 +10,8 @@ class Folder < Article errors.add(:parent, "A folder should not belong to a blog.") if parent && parent.blog? end - acts_as_having_settings :field => :setting + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :setting xss_terminate :only => [ :name, :body ], :with => 'white_list', :on => 'validation' diff --git a/app/models/forum.rb b/app/models/forum.rb index 07eb334..91098a9 100644 --- a/app/models/forum.rb +++ b/app/models/forum.rb @@ -1,6 +1,8 @@ class Forum < Folder + extend ActsAsHavingPosts::ClassMethods acts_as_having_posts -> { reorder 'updated_at DESC' } + include PostsLimit attr_accessible :has_terms_of_use, :terms_of_use, :topic_creation diff --git a/app/models/image.rb b/app/models/image.rb index c5bab5c..c991ebc 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -23,6 +23,7 @@ class Image < ApplicationRecord validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n + extend DelayedAttachmentFu::ClassMethods delay_attachment_fu_thumbnails postgresql_attachment_fu diff --git a/app/models/profile.rb b/app/models/profile.rb index 1c392d3..8c59a9f 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -88,6 +88,8 @@ class Profile < ApplicationRecord } acts_as_accessible + + include Customizable acts_as_customizable include Noosfero::Plugin::HotSpot @@ -185,6 +187,7 @@ class Profile < ApplicationRecord Person.members_of(self).by_role(roles) end + extend ActsAsHavingBoxes::ClassMethods acts_as_having_boxes acts_as_taggable @@ -231,7 +234,8 @@ class Profile < ApplicationRecord scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) end - acts_as_having_settings :field => :data + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :data def settings data @@ -285,6 +289,7 @@ class Profile < ApplicationRecord has_many :files, :class_name => 'UploadedFile' + extend ActsAsHavingImage::ClassMethods acts_as_having_image has_many :tasks, :dependent => :destroy, :as => 'target' diff --git a/app/models/profile_suggestion.rb b/app/models/profile_suggestion.rb index f91dc41..cab1247 100644 --- a/app/models/profile_suggestion.rb +++ b/app/models/profile_suggestion.rb @@ -17,7 +17,8 @@ class ProfileSuggestion < ApplicationRecord self.class.generate_profile_suggestions(profile_suggestion.person) end - acts_as_having_settings :field => :categories + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :categories validate :must_be_a_valid_category, :on => :create def must_be_a_valid_category diff --git a/app/models/task.rb b/app/models/task.rb index 308b37b..4bd1a71 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -11,7 +11,8 @@ # will need to declare itself). class Task < ApplicationRecord - acts_as_having_settings :field => :data + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :data module Status # the status of tasks just created diff --git a/app/models/text_article.rb b/app/models/text_article.rb index 73ff983..805cc50 100644 --- a/app/models/text_article.rb +++ b/app/models/text_article.rb @@ -1,5 +1,3 @@ -require 'noosfero/translatable_content' - # a base class for all text article types. class TextArticle < Article @@ -9,7 +7,7 @@ class TextArticle < Article _('Article') end - include Noosfero::TranslatableContent + include TranslatableContent def self.icon_name(article = nil) if article && !article.parent.nil? && article.parent.kind_of?(Blog) diff --git a/app/models/tiny_mce_article.rb b/app/models/tiny_mce_article.rb index 536c6c6..53a4b23 100644 --- a/app/models/tiny_mce_article.rb +++ b/app/models/tiny_mce_article.rb @@ -1,5 +1,3 @@ -require 'white_list_filter' - class TinyMceArticle < TextArticle def self.short_description diff --git a/app/models/uploaded_file.rb b/app/models/uploaded_file.rb index 2d3a380..abae67a 100644 --- a/app/models/uploaded_file.rb +++ b/app/models/uploaded_file.rb @@ -84,6 +84,7 @@ class UploadedFile < Article validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n + extend DelayedAttachmentFu::ClassMethods delay_attachment_fu_thumbnails postgresql_attachment_fu diff --git a/config/initializers/00_dependencies.rb b/config/initializers/00_dependencies.rb index f69ee43..c1b84b2 100644 --- a/config/initializers/00_dependencies.rb +++ b/config/initializers/00_dependencies.rb @@ -16,14 +16,6 @@ end require 'extensions' # locally-developed modules -require 'acts_as_filesystem' -require 'acts_as_having_settings' -require 'acts_as_having_boxes' -require 'acts_as_having_image' -require 'acts_as_having_posts' -require 'acts_as_customizable' require 'route_if' require 'maybe_add_http' -require 'set_profile_region_from_city_state' -require 'white_list_filter' diff --git a/config/initializers/delayed_attachment_fu.rb b/config/initializers/delayed_attachment_fu.rb deleted file mode 100644 index 650338a..0000000 --- a/config/initializers/delayed_attachment_fu.rb +++ /dev/null @@ -1 +0,0 @@ -require 'delayed_attachment_fu' diff --git a/db/migrate/20160422163123_enable_products_plugin_on_environments.rb b/db/migrate/20160422163123_enable_products_plugin_on_environments.rb index a1f3156..e8f2e4e 100644 --- a/db/migrate/20160422163123_enable_products_plugin_on_environments.rb +++ b/db/migrate/20160422163123_enable_products_plugin_on_environments.rb @@ -7,6 +7,7 @@ class Environment < ApplicationRecord has_many :profiles has_many :products, through: :profiles + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :settings settings_items :enabled_plugins, type: Array end diff --git a/lib/acts_as_customizable.rb b/lib/acts_as_customizable.rb deleted file mode 100644 index c9c58b3..0000000 --- a/lib/acts_as_customizable.rb +++ /dev/null @@ -1,125 +0,0 @@ -module Customizable - - def self.included(base) - base.attr_accessible :custom_values - base.extend ClassMethods - end - - module ClassMethods - def acts_as_customizable(options = {}) - attr_accessor :custom_values - has_many :custom_field_values, :dependent => :delete_all, :as => :customized - send :include, Customizable::InstanceMethods - after_save :save_custom_values - validate :valid_custom_values? - end - - def active_custom_fields environment - environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.active} - end - - def required_custom_fields environment - environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.required} - end - - def signup_custom_fields environment - environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.signup} - end - - def custom_fields environment - environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type)} - end - - def customized_ancestors_list - current=self - result=[] - while current.instance_methods.include? :custom_value do - result << current.name - current=current.superclass - end - result - end - - end - - module InstanceMethods - - def valid_custom_values? - is_valid = true - parse_custom_values.each do |cv| - unless cv.valid? - name = cv.custom_field.name - errors.add(name, cv.errors.messages[name.to_sym].first) - is_valid = false - end - end - is_valid - end - - def customized_class - current=self.class - while current.instance_methods.include? :custom_fields do - result=current - current=current.superclass - end - result.name - end - - def is_public(field_name) - cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} - cv.nil? ? false : cv.public - end - - def public_values - self.custom_field_values.select{|cv| cv.public} - end - - def custom_value(field_name) - cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} - cv.nil? ? default_value_for(field_name) : cv.value - end - - def default_value_for(field_name) - field=self.class.custom_fields(environment).detect {|c| c.name == field_name} - field.nil? ? nil : field.default_value - end - - def parse_custom_values - return_list = [] - return return_list if custom_values.blank? - custom_values.each_pair do |key, value| - custom_field = environment.custom_fields.detect{|cf|cf.name==key} - next if custom_field.blank? - custom_field_value = self.custom_field_values(true).detect{|cv| cv.custom_field.name==key} - - if custom_field_value.nil? - custom_field_value = CustomFieldValue.new - custom_field_value.custom_field = custom_field - custom_field_value.customized = self - end - - if value.is_a?(Hash) - custom_field_value.value = value['value'].to_s - if value.has_key?('public') - is_public = value['public']=="true" || value['public']==true - custom_field_value.public = is_public - else - custom_field_value.public = false - end - else - custom_field_value.value = value.to_s - custom_field_value.public = false - end - return_list << custom_field_value - end - return_list - end - - def save_custom_values - parse_custom_values.each(&:save) - end - - end -end - -ActiveRecord::Base.include Customizable diff --git a/lib/acts_as_filesystem.rb b/lib/acts_as_filesystem.rb deleted file mode 100644 index 77d022f..0000000 --- a/lib/acts_as_filesystem.rb +++ /dev/null @@ -1,267 +0,0 @@ -module ActsAsFileSystem - - module ActsMethods - - # Declares the ActiveRecord model to acts like a filesystem: objects are - # arranged in a tree (liks acts_as_tree), and . The underlying table must - # have the following fields: - # - # * name (+:string+) - the title of the object - # * slug (+:string+)- the title turned in a URL-friendly string (downcased, - # non-ascii chars transliterated into ascii, all sequences of - # non-alphanumericd characters changed into dashed) - # * path (+:text+)- stores the full path of the object (the full path of - # the parent, a "/" and the slug of the object) - # * children_count - a cache of the number of children elements. - def acts_as_filesystem - # a filesystem is a tree - acts_as_tree :counter_cache => :children_count - - extend ClassMethods - include InstanceMethods - if self.has_path? - after_update :update_children_path - before_create :set_path - include InstanceMethods::PathMethods - end - - before_save :set_ancestry - end - - end - - module ClassMethods - - def build_ancestry(parent_id = nil, ancestry = '') - ActiveRecord::Base.transaction do - self.base_class.where(parent_id: parent_id).each do |node| - node.update_column :ancestry, ancestry - - build_ancestry node.id, (ancestry.empty? ? "#{node.formatted_ancestry_id}" : - "#{ancestry}#{node.ancestry_sep}#{node.formatted_ancestry_id}") - end - end - - #raise "Couldn't reach and set ancestry on every record" if self.base_class.where('ancestry is null').count != 0 - end - - def has_path? - (['name', 'slug', 'path'] - self.column_names).blank? - end - - end - - module InstanceMethods - - def ancestry_column - 'ancestry' - end - def ancestry_sep - '.' - end - def has_ancestry? - self.class.column_names.include? self.ancestry_column - end - - def formatted_ancestry_id - "%010d" % self.id if self.id - end - - def ancestry - self[ancestry_column] - end - def ancestor_ids - return nil if !has_ancestry? or ancestry.nil? - @ancestor_ids ||= ancestry.split(ancestry_sep).map{ |id| id.to_i } - end - - def ancestry=(value) - self[ancestry_column] = value - end - def set_ancestry - return unless self.has_ancestry? - if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path - self.ancestry = self.hierarchy(true)[0...-1].map{ |p| p.formatted_ancestry_id }.join(ancestry_sep) - end - end - - def descendents_options - ["#{self.ancestry_column} LIKE ?", "%#{self.formatted_ancestry_id}%"] - end - def descendents - self.class.where descendents_options - end - - # calculates the level of the record in the records hierarchy. Top-level - # records have level 0; the children of the top-level records have - # level 1; the children of records with level 1 have level 2, and so on. - # - # A level 0 - # / \ - # B C level 1 - # / \ / \ - # E F G H level 2 - # ... - def level - self.hierarchy.size - 1 - end - - # Is this record a top-level record? - def top_level? - self.parent.nil? - end - - # Is this record a leaf in the hierarchy tree of records? - # - # Being a leaf means that this record has no subrecord. - def leaf? - self.children.empty? - end - - def top_ancestor - if has_ancestry? and !ancestry.blank? - self.class.base_class.find_by id: self.top_ancestor_id - else - self.hierarchy.first - end - end - def top_ancestor_id - if has_ancestry? and !ancestry.nil? - self.ancestor_ids.first - else - self.hierarchy.first.id - end - end - - # returns the full hierarchy from the top-level item to this one. For - # example, if item1 has a children item2 and item2 has a children item3, - # then item3's hierarchy would be [item1, item2, item3]. - # - # If +reload+ is passed as +true+, then the hierarchy is reload (usefull - # when the ActiveRecord object was modified in some way, or just after - # changing parent) - def hierarchy(reload = false) - @hierarchy = nil if reload or recalculate_path - - if @hierarchy.nil? - @hierarchy = [] - - if !reload and !recalculate_path and ancestor_ids - objects = self.class.base_class.where(id: ancestor_ids) - ancestor_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } } - @hierarchy << self - else - item = self - while item - @hierarchy.unshift(item) - item = item.parent - end - end - end - - @hierarchy - end - - def map_traversal(&block) - result = [] - current_level = [self] - - while !current_level.empty? - result += current_level - ids = current_level.select {|item| item.children_count > 0}.map(&:id) - break if ids.empty? - current_level = self.class.base_class.where(parent_id: ids) - end - block ||= (lambda { |x| x }) - result.map(&block) - end - - def all_children - res = map_traversal - res.shift - res - end - - ##### - # Path methods - # These methods are used when _path_, _name_ and _slug_ attributes exist - # and should be calculated based on the tree - ##### - module PathMethods - # used to know when to trigger batch renaming - attr_accessor :recalculate_path - - # calculates the full path to this record using parent's path. - def calculate_path - self.hierarchy.map{ |obj| obj.slug }.join('/') - end - def set_path - if self.path == self.slug && !self.top_level? - self.path = self.calculate_path - end - end - def explode_path - path.split(/\//) - end - - def update_children_path - if self.recalculate_path - self.children.each do |child| - child.path = child.calculate_path - child.recalculate_path = true - child.save! - end - end - self.recalculate_path = false - end - - # calculates the full name of a record by accessing the name of all its - # ancestors. - # - # If you have this record hierarchy: - # Record "A" - # Record "B" - # Record "C" - # - # Then Record "C" will have "A/B/C" as its full name. - def full_name(sep = '/') - self.hierarchy.map {|item| item.name || '?' }.join(sep) - end - - # gets the name without leading parents. Useful when dividing records - # in top-level groups and full names must not include the top-level - # record which is already a emphasized label - def full_name_without_leading(count, sep = '/') - parts = self.full_name(sep).split(sep) - count.times { parts.shift } - parts.join(sep) - end - - def set_name(value) - if self.name != value - self.recalculate_path = true - end - self[:name] = value - end - - # sets the name of the record. Also sets #slug accordingly. - def name=(value) - self.set_name(value) - unless self.name.blank? - self.slug = self.name.to_slug - end - end - - # sets the slug of the record. Also sets the path with the new slug value. - def slug=(value) - self[:slug] = value - unless self.slug.blank? - self.path = self.calculate_path - end - end - end - end -end - -ActiveRecord::Base.extend ActsAsFileSystem::ActsMethods - diff --git a/lib/acts_as_having_boxes.rb b/lib/acts_as_having_boxes.rb deleted file mode 100644 index 10b3ee6..0000000 --- a/lib/acts_as_having_boxes.rb +++ /dev/null @@ -1,38 +0,0 @@ -module ActsAsHavingBoxes - - module ClassMethods - def acts_as_having_boxes - has_many :boxes, -> { order :position }, as: :owner, dependent: :destroy - self.send(:include, ActsAsHavingBoxes) - end - end - - module BlockArray - def find(id) - select { |item| item.id == id.to_i }.first - end - end - - def blocks(reload = false) - if (reload) - @blocks = nil - end - if @blocks.nil? - @blocks = boxes.includes(:blocks).inject([]) do |acc,obj| - acc.concat(obj.blocks) - end - @blocks.send(:extend, BlockArray) - end - @blocks - end - - # returns 3 unless the class table has a boxes_limit column. In that case - # return the value of the column. - def boxes_limit layout_template = nil - layout_template ||= self.layout_template - @boxes_limit ||= LayoutTemplate.find(layout_template).number_of_boxes || 3 - end - -end - -ActiveRecord::Base.extend ActsAsHavingBoxes::ClassMethods diff --git a/lib/acts_as_having_image.rb b/lib/acts_as_having_image.rb deleted file mode 100644 index d6eaf68..0000000 --- a/lib/acts_as_having_image.rb +++ /dev/null @@ -1,27 +0,0 @@ -module ActsAsHavingImage - - module ClassMethods - def acts_as_having_image - belongs_to :image, dependent: :destroy - scope :with_image, -> { where "#{table_name}.image_id IS NOT NULL" } - scope :without_image, -> { where "#{table_name}.image_id IS NULL" } - attr_accessible :image_builder - include ActsAsHavingImage - end - end - - def image_builder=(img) - if image && image.id == img[:id] - image.attributes = img - else - build_image(img) - end unless img[:uploaded_data].blank? - if img[:remove_image] == 'true' - self.image_id = nil - end - end - -end - -ActiveRecord::Base.extend ActsAsHavingImage::ClassMethods - diff --git a/lib/acts_as_having_posts.rb b/lib/acts_as_having_posts.rb deleted file mode 100644 index f34df3c..0000000 --- a/lib/acts_as_having_posts.rb +++ /dev/null @@ -1,51 +0,0 @@ -module ActsAsHavingPosts - - module ClassMethods - def acts_as_having_posts(scope = nil) - has_many :posts, -> { - s = order('published_at DESC, id DESC').where('articles.type != ?', 'RssFeed') - s = s.instance_exec(&scope) if scope - s - }, class_name: 'Article', foreign_key: 'parent_id', source: :children - - attr_accessor :feed_attrs - - after_create do |blog| - blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile) - blog.feed = blog.feed_attrs - end - - settings_items :posts_per_page, :type => :integer, :default => 5 - - self.send(:include, ActsAsHavingPosts) - end - end - - def has_posts? - true - end - - def feed - children.where(:type => 'RssFeed').first - end - - def feed=(attrs) - if attrs - if self.feed - self.feed.update(attrs) - else - self.feed_attrs = attrs - end - end - self.feed - end - - def name=(value) - self.set_name(value) - self.slug = self.slug.blank? ? self.name.to_slug : self.slug.to_slug - end - -end - -ActiveRecord::Base.extend ActsAsHavingPosts::ClassMethods - diff --git a/lib/acts_as_having_settings.rb b/lib/acts_as_having_settings.rb deleted file mode 100644 index c43a53f..0000000 --- a/lib/acts_as_having_settings.rb +++ /dev/null @@ -1,91 +0,0 @@ -# declare missing types -module ActiveRecord - module Type - class Symbol < Value - def cast_value value - value.to_sym - end - end - class Array < Value - def cast_value value - ::Array.wrap(value) - end - end - class Hash < Value - def cast_value value - h = ::Hash[value] - h.symbolize_keys! - h - end - end - end -end - -module ActsAsHavingSettings - - def self.type_cast value, type - # do not cast nil - return value if value.nil? - type.send :cast_value, value - end - - module ClassMethods - - def acts_as_having_settings(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - field = (options[:field] || :settings).to_sym - - serialize field, Hash - class_attribute :settings_field - self.settings_field = field - - class_eval do - def settings_field - self[self.class.settings_field] ||= Hash.new - end - - def setting_changed? setting_field - setting_field = setting_field.to_sym - changed_settings = self.changes[self.class.settings_field] - return false if changed_settings.nil? - - old_setting_value = changed_settings.first.nil? ? nil : changed_settings.first[setting_field] - new_setting_value = changed_settings.last[setting_field] - old_setting_value != new_setting_value - end - end - - settings_items *args - end - - def settings_items *names - - options = names.extract_options! - default = options[:default] - type = options[:type] - type = if type.present? then ActiveRecord::Type.const_get(type.to_s.camelize.to_sym).new else nil end - - names.each do |setting| - # symbolize key - setting = setting.to_sym - - define_method setting do - h = send self.class.settings_field - val = h[setting] - # translate default value if it is used - if not val.nil? then val elsif default.is_a? String then gettext default else default end - end - - define_method "#{setting}=" do |value| - h = send self.class.settings_field - h[setting] = if type then ActsAsHavingSettings.type_cast value, type else value end - end - end - end - - end - -end - -ActiveRecord::Base.extend ActsAsHavingSettings::ClassMethods - diff --git a/lib/code_numbering.rb b/lib/code_numbering.rb deleted file mode 100644 index 843cc33..0000000 --- a/lib/code_numbering.rb +++ /dev/null @@ -1,58 +0,0 @@ -module CodeNumbering - module ClassMethods - def code_numbering field, options = {} - class_attribute :code_numbering_field - class_attribute :code_numbering_options - - self.code_numbering_field = field - self.code_numbering_options = options - - before_create :create_code_numbering - - include CodeNumbering::InstanceMethods - end - end - - module InstanceMethods - - def code - self.attributes[self.code_numbering_field.to_s] - end - - def code_scope - scope = self.code_numbering_options[:scope] - case scope - when Symbol - self.send scope - when Proc - instance_exec &scope - else - self.class - end - end - - def code_maximum - self.code_scope.maximum(self.code_numbering_field) || 0 - end - - def create_code_numbering - max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] - max = self.code_maximum - self.send "#{self.code_numbering_field}=", max+1 - end - - def reset_scope_code_numbering - max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] - max ||= 1 - - self.code_scope.order(:created_at).each do |record| - record.update_column self.code_numbering_field, max - max += 1 - end - self.reload - end - - end -end - -ActiveRecord::Base.extend CodeNumbering::ClassMethods diff --git a/lib/delayed_attachment_fu.rb b/lib/delayed_attachment_fu.rb deleted file mode 100644 index 3e2c1a1..0000000 --- a/lib/delayed_attachment_fu.rb +++ /dev/null @@ -1,56 +0,0 @@ -module DelayedAttachmentFu - - module ClassMethods - def delay_attachment_fu_thumbnails - include DelayedAttachmentFu::InstanceMethods - after_create do |file| - if file.thumbnailable? - Delayed::Job.enqueue CreateThumbnailsJob.new(file.class.name, file.id) - end - end - end - end - - module InstanceMethods - # skip processing with RMagick - def process_attachment - end - - def after_process_attachment - save_to_storage - @temp_paths.clear - @saved_attachment = nil - run_callbacks :after_attachment_saved - end - - def create_thumbnails - if thumbnailable? - self.class.with_image(full_filename) do |img| - self.width = img.columns - self.height = img.rows - self.save! - end - self.class.attachment_options[:thumbnails].each do |suffix, size| - self.create_or_update_thumbnail(self.full_filename, suffix, size) - end - self.thumbnails_processed = true - self.save! - end - end - - def public_filename(size=nil) - force, size = true, nil if size == :uploaded - if !self.thumbnailable? || self.thumbnails_processed || force - super size - else - size ||= :thumb - '/images/icons-app/image-loading-%s.png' % size - end - end - - - end -end - -ActiveRecord::Base.extend DelayedAttachmentFu::ClassMethods - diff --git a/lib/noosfero/translatable_content.rb b/lib/noosfero/translatable_content.rb deleted file mode 100644 index d3bbc5a..0000000 --- a/lib/noosfero/translatable_content.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Noosfero::TranslatableContent - - def translatable? - return false if self.profile && !self.profile.environment.languages.present? - parent.nil? || !parent.forum? - end -end diff --git a/lib/set_profile_region_from_city_state.rb b/lib/set_profile_region_from_city_state.rb deleted file mode 100644 index 586f56b..0000000 --- a/lib/set_profile_region_from_city_state.rb +++ /dev/null @@ -1,44 +0,0 @@ -module SetProfileRegionFromCityState - - module ClassMethods - def set_profile_region_from_city_state - before_save :region_from_city_and_state - - include InstanceMethods - alias_method_chain :city=, :region - alias_method_chain :state=, :region - end - end - - module InstanceMethods - include Noosfero::Plugin::HotSpot - - def city_with_region=(value) - self.city_without_region = value - @change_region = true - end - - def state_with_region=(value) - self.state_without_region = value - @change_region = true - end - - def region_from_city_and_state - if @change_region - self.region = nil - state = search_region(State, self.state) - self.region = search_region(City.where(:parent_id => state.id), self.city) if state - end - end - - private - - def search_region(scope, query) - return nil if !query - query = query.downcase.strip - scope.where(['lower(name)=? OR lower(abbreviation)=? OR lower(acronym)=?', query, query, query]).first - end - - end - -end diff --git a/lib/white_list_filter.rb b/lib/white_list_filter.rb deleted file mode 100644 index 8218ba1..0000000 --- a/lib/white_list_filter.rb +++ /dev/null @@ -1,37 +0,0 @@ -module WhiteListFilter - - def check_iframe_on_content(content, trusted_sites) - if content.blank? || !content.include?('iframe') - return content - end - content.gsub!(/]*>\s*<\/iframe>/i) do |iframe| - result = '' - unless iframe =~ /src=['"].*src=['"]/ - trusted_sites.each do |trusted_site| - re_dom = trusted_site.gsub('.', '\.') - if iframe =~ /src=["'](https?:)?\/\/(www\.)?#{re_dom}\// - result = iframe - end - end - end - result - end - content - end - - module ClassMethods - def filter_iframes(*opts) - options = opts.last.is_a?(Hash) && opts.pop || {} - white_list_method = options[:whitelist] || :iframe_whitelist - opts.each do |field| - before_validation do |obj| - obj.check_iframe_on_content(obj.send(field), obj.send(white_list_method)) - end - end - end - end - - def self.included(c) - c.send(:extend, WhiteListFilter::ClassMethods) - end -end diff --git a/plugins/analytics/models/analytics_plugin/page_view.rb b/plugins/analytics/models/analytics_plugin/page_view.rb index 4d4680b..594cd8e 100644 --- a/plugins/analytics/models/analytics_plugin/page_view.rb +++ b/plugins/analytics/models/analytics_plugin/page_view.rb @@ -8,6 +8,7 @@ class AnalyticsPlugin::PageView < ApplicationRecord attr_accessor :request attr_accessible :request + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :options belongs_to :profile, validate: true diff --git a/plugins/fb_app/models/fb_app_plugin/page_tab.rb b/plugins/fb_app/models/fb_app_plugin/page_tab.rb index fc704ee..b50b7a6 100644 --- a/plugins/fb_app/models/fb_app_plugin/page_tab.rb +++ b/plugins/fb_app/models/fb_app_plugin/page_tab.rb @@ -9,6 +9,7 @@ class FbAppPlugin::PageTab < ApplicationRecord belongs_to :owner_profile, foreign_key: :profile_id, class_name: 'Profile' + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :config ConfigTypes = [:profile, :profiles, :query] diff --git a/plugins/newsletter/lib/newsletter_plugin/newsletter.rb b/plugins/newsletter/lib/newsletter_plugin/newsletter.rb index 0b5267a..1d53d78 100644 --- a/plugins/newsletter/lib/newsletter_plugin/newsletter.rb +++ b/plugins/newsletter/lib/newsletter_plugin/newsletter.rb @@ -167,6 +167,7 @@ class NewsletterPlugin::Newsletter < ApplicationRecord end end + extend ActsAsHavingImage::ClassMethods acts_as_having_image def last_send_at diff --git a/plugins/oauth_client/models/oauth_client_plugin/auth.rb b/plugins/oauth_client/models/oauth_client_plugin/auth.rb index 6fdb53c..3260909 100644 --- a/plugins/oauth_client/models/oauth_client_plugin/auth.rb +++ b/plugins/oauth_client/models/oauth_client_plugin/auth.rb @@ -10,6 +10,7 @@ class OauthClientPlugin::Auth < ApplicationRecord validates_presence_of :provider validates_uniqueness_of :profile_id, scope: :provider_id + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :data def expires_in diff --git a/plugins/oauth_client/models/oauth_client_plugin/provider.rb b/plugins/oauth_client/models/oauth_client_plugin/provider.rb index a678012..38f7256 100644 --- a/plugins/oauth_client/models/oauth_client_plugin/provider.rb +++ b/plugins/oauth_client/models/oauth_client_plugin/provider.rb @@ -4,7 +4,10 @@ class OauthClientPlugin::Provider < ApplicationRecord validates_presence_of :name, :strategy + extend ActsAsHavingImage::ClassMethods acts_as_having_image + + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :options settings_items :site, type: String @@ -16,6 +19,4 @@ class OauthClientPlugin::Provider < ApplicationRecord scope :enabled, -> { where enabled: true } - acts_as_having_image - end diff --git a/plugins/products/models/products_plugin/product.rb b/plugins/products/models/products_plugin/product.rb index 6aecb43..0f5113e 100644 --- a/plugins/products/models/products_plugin/product.rb +++ b/plugins/products/models/products_plugin/product.rb @@ -45,6 +45,7 @@ class ProductsPlugin::Product < ApplicationRecord has_many :qualifiers, through: :product_qualifiers has_many :certifiers, through: :product_qualifiers + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :data track_actions :create_product, :after_create, keep_params: [:name, :url ], if: Proc.new { |a| a.is_trackable? }, custom_user: :action_tracker_user @@ -129,6 +130,7 @@ class ProductsPlugin::Product < ApplicationRecord image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size end + extend ActsAsHavingImage::ClassMethods acts_as_having_image def save_image diff --git a/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb b/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb index 2c2d2ed..0a5be0e 100644 --- a/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb +++ b/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb @@ -2,6 +2,7 @@ OrdersPlugin.send :remove_const, :Item if defined? OrdersPlugin::Item OrdersPlugin.send :remove_const, :Order if defined? OrdersPlugin::Order class ShoppingCartPlugin::PurchaseOrder < ApplicationRecord + extend ActsAsHavingSettings::ClassMethods acts_as_having_settings field: :data module Status diff --git a/plugins/video/lib/video_plugin/video.rb b/plugins/video/lib/video_plugin/video.rb index 2a9f4c2..909ed5e 100644 --- a/plugins/video/lib/video_plugin/video.rb +++ b/plugins/video/lib/video_plugin/video.rb @@ -1,4 +1,3 @@ -require 'noosfero/translatable_content' require 'application_helper' require 'net/http' diff --git a/plugins/video/lib/video_plugin/video_gallery.rb b/plugins/video/lib/video_plugin/video_gallery.rb index 2159550..a3a4575 100644 --- a/plugins/video/lib/video_plugin/video_gallery.rb +++ b/plugins/video/lib/video_plugin/video_gallery.rb @@ -14,7 +14,8 @@ class VideoPlugin::VideoGallery < Folder errors.add(:parent, "A video gallery should not belong to a blog.") if parent && parent.blog? end - acts_as_having_settings :field => :setting + extend ActsAsHavingSettings::ClassMethods + acts_as_having_settings field: :setting xss_terminate :only => [ :body ], :with => 'white_list', :on => 'validation' diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb index 3fade78..eb91810 100644 --- a/test/unit/event_test.rb +++ b/test/unit/event_test.rb @@ -282,7 +282,7 @@ class EventTest < ActiveSupport::TestCase end should 'be translatable' do - assert_kind_of Noosfero::TranslatableContent, Event.new + assert_kind_of TranslatableContent, Event.new end should 'tiny mce editor is enabled' do diff --git a/test/unit/text_article_test.rb b/test/unit/text_article_test.rb index 6b0d424..d397b2b 100644 --- a/test/unit/text_article_test.rb +++ b/test/unit/text_article_test.rb @@ -15,7 +15,7 @@ class TextArticleTest < ActiveSupport::TestCase end should 'be translatable' do - assert_kind_of Noosfero::TranslatableContent, TextArticle.new + assert_kind_of TranslatableContent, TextArticle.new end should 'return article icon name' do diff --git a/test/unit/translatable_content_test.rb b/test/unit/translatable_content_test.rb index 89e461c..ae1906a 100644 --- a/test/unit/translatable_content_test.rb +++ b/test/unit/translatable_content_test.rb @@ -4,7 +4,7 @@ class TranslatableContentTest < ActiveSupport::TestCase class Content attr_accessor :parent, :profile - include Noosfero::TranslatableContent + include TranslatableContent end def setup -- libgit2 0.21.2