Commit e77ff7f178fb7f21b2a9994a2df04fe2d1f9c9f7

Authored by Victor Costa
2 parents 419fe2e5 ba1e746f

Merge branch 'rails3' into rails3_stable

Showing 77 changed files with 2666 additions and 480 deletions   Show diff stats
app/controllers/admin/environment_design_controller.rb
... ... @@ -11,7 +11,7 @@ class EnvironmentDesignController < BoxOrganizerController
11 11 def available_blocks
12 12 # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
13 13 # the Noosfero core soon, see ActionItem3045
14   - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
  14 + @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
15 15 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
16 16 end
17 17  
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -144,6 +144,7 @@ class CmsController < MyProfileController
144 144  
145 145 @article.profile = profile
146 146 @article.last_changed_by = user
  147 + @article.created_by = user
147 148  
148 149 translations if @article.translatable?
149 150  
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -15,14 +15,8 @@ class ProfileDesignController < BoxOrganizerController
15 15  
16 16 blocks += plugins.dispatch(:extra_blocks)
17 17  
18   - # blocks exclusive for organizations
19   - if profile.has_members?
20   - blocks << MembersBlock
21   - end
22   -
23 18 # blocks exclusive to people
24 19 if profile.person?
25   - blocks << FriendsBlock
26 20 blocks << FavoriteEnterprisesBlock
27 21 blocks << CommunitiesBlock
28 22 blocks << EnterprisesBlock
... ...
app/helpers/sweeper_helper.rb
... ... @@ -18,9 +18,7 @@ module SweeperHelper
18 18 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
19 19 end
20 20  
21   - # friends blocks
22   - blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}
23   - BlockSweeper.expire_blocks(blocks)
  21 + expire_blocks_cache(profile, [:profile])
24 22 end
25 23  
26 24 def expire_communities(profile)
... ...
app/models/approve_article.rb
... ... @@ -48,7 +48,7 @@ class ApproveArticle &lt; Task
48 48 end
49 49  
50 50 def perform
51   - article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source, :last_changed_by_id => article.author_id)
  51 + article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source, :last_changed_by_id => article.last_changed_by_id, :created_by_id => article.created_by_id)
52 52 end
53 53  
54 54 def title
... ...
app/models/article.rb
... ... @@ -40,12 +40,6 @@ class Article &lt; ActiveRecord::Base
40 40 # xss_terminate plugin can't sanitize array fields
41 41 before_save :sanitize_tag_list
42 42  
43   - before_create do |article|
44   - if article.last_changed_by_id
45   - article.author_name = Person.find(article.last_changed_by_id).name
46   - end
47   - end
48   -
49 43 belongs_to :profile
50 44 validates_presence_of :profile_id, :name
51 45 validates_presence_of :slug, :path, :if => lambda { |article| !article.name.blank? }
... ... @@ -55,6 +49,7 @@ class Article &lt; ActiveRecord::Base
55 49 validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? }
56 50  
57 51 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
  52 + belongs_to :created_by, :class_name => 'Person', :foreign_key => 'created_by_id'
58 53  
59 54 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
60 55  
... ... @@ -89,6 +84,11 @@ class Article &lt; ActiveRecord::Base
89 84 article.parent = article.profile.blog
90 85 end
91 86 end
  87 +
  88 + if article.created_by
  89 + article.author_name = article.created_by.name
  90 + end
  91 +
92 92 end
93 93  
94 94 after_destroy :destroy_activity
... ... @@ -215,6 +215,10 @@ class Article &lt; ActiveRecord::Base
215 215 acts_as_versioned
216 216 self.non_versioned_columns << 'setting'
217 217  
  218 + def version_condition_met?
  219 + (['name', 'body', 'abstract', 'filename', 'start_date', 'end_date', 'image_id', 'license_id'] & changed).length > 0
  220 + end
  221 +
218 222 def comment_data
219 223 comments.map {|item| [item.title, item.body].join(' ') }.join(' ')
220 224 end
... ... @@ -640,17 +644,13 @@ class Article &lt; ActiveRecord::Base
640 644  
641 645 def author(version_number = nil)
642 646 if version_number
643   - version = versions.find_by_version(version_number)
  647 + version = self.versions.find_by_version(version_number)
644 648 author_id = version.last_changed_by_id if version
645   - Person.exists?(author_id) ? Person.find(author_id) : nil
646 649 else
647   - if versions.empty?
648   - last_changed_by
649   - else
650   - author_id = versions.first.last_changed_by_id
651   - Person.exists?(author_id) ? Person.find(author_id) : nil
652   - end
  650 + author_id = self.created_by_id
653 651 end
  652 +
  653 + environment.people.find_by_id(author_id)
654 654 end
655 655  
656 656 def author_name(version_number = nil)
... ...
app/models/box.rb
... ... @@ -34,14 +34,11 @@ class Box &lt; ActiveRecord::Base
34 34 FansBlock,
35 35 FavoriteEnterprisesBlock,
36 36 FeedReaderBlock,
37   - FriendsBlock,
38 37 HighlightsBlock,
39 38 LinkListBlock,
40 39 LoginBlock,
41 40 MainBlock,
42   - MembersBlock,
43 41 MyNetworkBlock,
44   - PeopleBlock,
45 42 ProfileImageBlock,
46 43 RawHTMLBlock,
47 44 RecentDocumentsBlock,
... ... @@ -63,14 +60,11 @@ class Box &lt; ActiveRecord::Base
63 60 FavoriteEnterprisesBlock,
64 61 FeaturedProductsBlock,
65 62 FeedReaderBlock,
66   - FriendsBlock,
67 63 HighlightsBlock,
68 64 LinkListBlock,
69 65 LocationBlock,
70 66 LoginBlock,
71   - MembersBlock,
72 67 MyNetworkBlock,
73   - PeopleBlock,
74 68 ProductsBlock,
75 69 ProductCategoriesBlock,
76 70 ProfileImageBlock,
... ...
app/models/community.rb
... ... @@ -85,10 +85,6 @@ class Community &lt; Organization
85 85 recent_documents(limit, ["articles.type != ? AND articles.highlighted = ?", 'Folder', highlight])
86 86 end
87 87  
88   - def blocks_to_expire_cache
89   - [MembersBlock]
90   - end
91   -
92 88 def each_member(offset=0)
93 89 while member = self.members.first(:order => :id, :offset => offset)
94 90 yield member
... ...
app/models/environment.rb
... ... @@ -182,7 +182,6 @@ class Environment &lt; ActiveRecord::Base
182 182  
183 183 # "right" area
184 184 env.boxes[2].blocks << CommunitiesBlock.new(:limit => 6)
185   - env.boxes[2].blocks << PeopleBlock.new(:limit => 6)
186 185 end
187 186  
188 187 # One Environment can be reached by many domains
... ...
app/models/environment.rb.orig 0 → 100644
... ... @@ -0,0 +1,938 @@
  1 +# A Environment is like a website to be hosted in the platform. It may
  2 +# contain multiple Profile's and can be identified by several different
  3 +# domains.
  4 +class Environment < ActiveRecord::Base
  5 +
  6 +<<<<<<< HEAD
  7 + attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :enabled_blocks, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body
  8 +=======
  9 + attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :disabled_blocks, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound
  10 +>>>>>>> rails3_AI3163-enable_disable_blocks
  11 +
  12 + has_many :users
  13 +
  14 + self.partial_updates = false
  15 +
  16 + has_many :tasks, :dependent => :destroy, :as => 'target'
  17 +
  18 + IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
  19 +
  20 + def self.verify_filename(filename)
  21 + filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
  22 + filename
  23 + end
  24 +
  25 + PERMISSIONS['Environment'] = {
  26 + 'view_environment_admin_panel' => N_('View environment admin panel'),
  27 + 'edit_environment_features' => N_('Edit environment features'),
  28 + 'edit_environment_design' => N_('Edit environment design'),
  29 + 'manage_environment_categories' => N_('Manage environment categories'),
  30 + 'manage_environment_roles' => N_('Manage environment roles'),
  31 + 'manage_environment_validators' => N_('Manage environment validators'),
  32 + 'manage_environment_users' => N_('Manage environment users'),
  33 + 'manage_environment_templates' => N_('Manage environment templates'),
  34 + 'manage_environment_licenses' => N_('Manage environment licenses'),
  35 + 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'),
  36 + 'edit_appearance' => N_('Edit appearance'),
  37 + }
  38 +
  39 + module Roles
  40 + def self.admin(env_id)
  41 + Role.find_by_key_and_environment_id('environment_administrator', env_id)
  42 + end
  43 + end
  44 +
  45 + after_create :create_roles
  46 + def create_roles
  47 + Role.create!(
  48 + :key => 'environment_administrator',
  49 + :name => N_('Environment Administrator'),
  50 + :environment => self,
  51 + :permissions => PERMISSIONS[Environment.name].keys + PERMISSIONS[Profile.name].keys
  52 + )
  53 + Role.create!(
  54 + :key => 'profile_admin',
  55 + :name => N_('Profile Administrator'),
  56 + :environment => self,
  57 + :permissions => PERMISSIONS[Profile.name].keys
  58 + )
  59 + # members for enterprises, communities etc
  60 + Role.create!(
  61 + :key => "profile_member",
  62 + :name => N_('Member'),
  63 + :environment => self,
  64 + :permissions => [
  65 + 'invite_members',
  66 + ]
  67 + )
  68 + # moderators for enterprises, communities etc
  69 + Role.create!(
  70 + :key => 'profile_moderator',
  71 + :name => N_('Moderator'),
  72 + :environment => self,
  73 + :permissions => [
  74 + 'manage_memberships',
  75 + 'edit_profile_design',
  76 + 'manage_products',
  77 + 'manage_friends',
  78 + 'perform_task'
  79 + ]
  80 + )
  81 + end
  82 +
  83 + def add_admin(user)
  84 + self.affiliate(user, Environment::Roles.admin(self.id))
  85 + end
  86 +
  87 + def remove_admin(user)
  88 + self.disaffiliate(user, Environment::Roles.admin(self.id))
  89 + end
  90 +
  91 + def admins
  92 + Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', Environment::Roles.admin(self).id])
  93 + end
  94 +
  95 + # returns the available features for a Environment, in the form of a
  96 + # hash, with pairs in the form <tt>'feature_name' => 'Feature name'</tt>.
  97 + def self.available_features
  98 + {
  99 + 'disable_asset_articles' => _('Disable search for articles '),
  100 + 'disable_asset_enterprises' => _('Disable search for enterprises'),
  101 + 'disable_asset_people' => _('Disable search for people'),
  102 + 'disable_asset_communities' => _('Disable search for communities'),
  103 + 'disable_asset_products' => _('Disable search for products'),
  104 + 'disable_asset_events' => _('Disable search for events'),
  105 + 'disable_categories' => _('Disable categories'),
  106 + 'disable_header_and_footer' => _('Disable header/footer editing by users'),
  107 + 'disable_gender_icon' => _('Disable gender icon'),
  108 + 'disable_categories_menu' => _('Disable the categories menu'),
  109 + 'disable_select_city_for_contact' => _('Disable state/city select for contact form'),
  110 + 'disable_contact_person' => _('Disable contact for people'),
  111 + 'disable_contact_community' => _('Disable contact for groups/communities'),
  112 +
  113 + 'products_for_enterprises' => _('Enable products for enterprises'),
  114 + 'enterprise_registration' => _('Enterprise registration'),
  115 + 'enterprise_activation' => _('Enable activation of enterprises'),
  116 + 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'),
  117 + 'enterprises_are_validated_when_created' => _('Enterprises are validated when created'),
  118 +
  119 + 'media_panel' => _('Media panel in WYSIWYG editor'),
  120 + 'select_preferred_domain' => _('Select preferred domains per profile'),
  121 + 'use_portal_community' => _('Use the portal as news source for front page'),
  122 + 'user_themes' => _('Allow users to create their own themes'),
  123 + 'search_in_home' => _("Display search form in home page"),
  124 +
  125 + 'cant_change_homepage' => _("Don't allow users to change which article to use as homepage"),
  126 + 'display_header_footer_explanation' => _("Display explanation about header and footer"),
  127 + 'articles_dont_accept_comments_by_default' => _("Articles don't accept comments by default"),
  128 + 'organizations_are_moderated_by_default' => _("Organizations have moderated publication by default"),
  129 + 'enable_organization_url_change' => _("Allow organizations to change their URL"),
  130 + 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"),
  131 + 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
  132 + 'xmpp_chat' => _('XMPP/Jabber based chat'),
  133 + 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'),
  134 + 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'),
  135 + 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'),
  136 + 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
  137 + 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'),
  138 + 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'),
  139 + 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage')
  140 + }
  141 + end
  142 +
  143 + def self.login_redirection_options
  144 + {
  145 + 'keep_on_same_page' => _('Stays on the same page the user was before login.'),
  146 + 'site_homepage' => _('Redirects the user to the environment homepage.'),
  147 + 'user_profile_page' => _('Redirects the user to his profile page.'),
  148 + 'user_homepage' => _('Redirects the user to his homepage.'),
  149 + 'user_control_panel' => _('Redirects the user to his control panel.')
  150 + }
  151 + end
  152 + validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
  153 +
  154 + def self.signup_redirection_options
  155 + {
  156 + 'keep_on_same_page' => _('Stays on the same page the user was before signup.'),
  157 + 'site_homepage' => _('Redirects the user to the environment homepage.'),
  158 + 'user_profile_page' => _('Redirects the user to his profile page.'),
  159 + 'user_homepage' => _('Redirects the user to his homepage.'),
  160 + 'user_control_panel' => _('Redirects the user to his control panel.')
  161 + }
  162 + end
  163 + validates_inclusion_of :redirection_after_signup, :in => Environment.signup_redirection_options.keys, :allow_nil => true
  164 +
  165 +
  166 + # #################################################
  167 + # Relationships and applied behaviour
  168 + # #################################################
  169 +
  170 + acts_as_having_boxes
  171 +
  172 + after_create do |env|
  173 + 3.times do
  174 + env.boxes << Box.new
  175 + end
  176 +
  177 + # main area
  178 + env.boxes[0].blocks << MainBlock.new
  179 +
  180 + # "left" area
  181 + env.boxes[1].blocks << LoginBlock.new
  182 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  183 + # the Noosfero core soon, see ActionItem3045
  184 + env.boxes[1].blocks << EnvironmentStatisticsBlock.new
  185 + env.boxes[1].blocks << RecentDocumentsBlock.new
  186 +
  187 + # "right" area
  188 + env.boxes[2].blocks << CommunitiesBlock.new(:limit => 6)
  189 + env.boxes[2].blocks << PeopleBlock.new(:limit => 6)
  190 + end
  191 +
  192 + # One Environment can be reached by many domains
  193 + has_many :domains, :as => :owner
  194 + has_many :profiles, :dependent => :destroy
  195 +
  196 + has_many :organizations
  197 + has_many :enterprises
  198 + has_many :products, :through => :enterprises
  199 + has_many :people
  200 + has_many :communities
  201 + has_many :licenses
  202 +
  203 + has_many :categories
  204 + has_many :display_categories, :class_name => 'Category', :conditions => 'display_color is not null and parent_id is null', :order => 'display_color'
  205 +
  206 + has_many :product_categories, :conditions => { :type => 'ProductCategory'}
  207 + has_many :regions
  208 + has_many :states
  209 + has_many :cities
  210 +
  211 + has_many :roles, :dependent => :destroy
  212 +
  213 + has_many :qualifiers
  214 + has_many :certifiers
  215 +
  216 + has_many :mailings, :class_name => 'EnvironmentMailing', :foreign_key => :source_id, :as => 'source'
  217 +
  218 + acts_as_accessible
  219 +
  220 + has_many :units, :order => 'position'
  221 + has_many :production_costs, :as => :owner
  222 +
  223 + def superior_intances
  224 + [self, nil]
  225 + end
  226 + # #################################################
  227 + # Attributes
  228 + # #################################################
  229 +
  230 + # store the Environment settings as YAML-serialized Hash.
  231 + acts_as_having_settings :field => :settings
  232 +
  233 + # the environment's terms of use: every user must accept them before registering.
  234 + settings_items :terms_of_use, :type => String
  235 +
  236 + # the environment's terms of enterprise use: every enterprise member must accept them before
  237 + # registering or activating enterprises.
  238 + settings_items :terms_of_enterprise_use, :type => String
  239 +
  240 + # returns the approval method used for this environment. Possible values are:
  241 + #
  242 + # Defaults to <tt>:admim</tt>.
  243 + settings_items :organization_approval_method, :type => Symbol, :default => :admin
  244 +
  245 + # Whether this environment should force having 'www.' in its domain name or
  246 + # not. Defauls to false.
  247 + #
  248 + # Sets the value of #force_www. <tt>value</tt> must be a boolean.
  249 + #
  250 + # See also #default_hostname
  251 + settings_items :force_www, :default => false
  252 +
  253 + settings_items :message_for_friend_invitation, :type => String
  254 + def message_for_friend_invitation
  255 + settings[:message_for_member_invitation] || InviteFriend.mail_template
  256 + end
  257 +
  258 + settings_items :message_for_member_invitation, :type => String
  259 + def message_for_member_invitation
  260 + settings[:message_for_member_invitation] || InviteMember.mail_template
  261 + end
  262 +
  263 + settings_items :min_signup_delay, :type => Integer, :default => 3 #seconds
  264 + settings_items :activation_blocked_text, :type => String
  265 + settings_items :message_for_disabled_enterprise, :type => String,
  266 + :default => _('This enterprise needs to be enabled.')
  267 + settings_items :location, :type => String
  268 + settings_items :layout_template, :type => String, :default => 'default'
  269 + settings_items :homepage, :type => String
  270 + settings_items :description, :type => String, :default => '<div style="text-align: center"><a href="http://noosfero.org/"><img src="/images/noosfero-network.png" alt="Noosfero"/></a></div>'
  271 + settings_items :local_docs, :type => Array, :default => []
  272 + settings_items :news_amount_by_folder, :type => Integer, :default => 4
  273 + settings_items :help_message_to_add_enterprise, :type => String, :default => ''
  274 + settings_items :tip_message_enterprise_activation_question, :type => String, :default => ''
  275 +
  276 + settings_items :currency_unit, :type => String, :default => '$'
  277 + settings_items :currency_separator, :type => String, :default => '.'
  278 + settings_items :currency_delimiter, :type => String, :default => ','
  279 +
  280 + settings_items :trusted_sites_for_iframe, :type => Array, :default => %w[
  281 + developer.myspace.com
  282 + itheora.org
  283 + maps.google.com
  284 + platform.twitter.com
  285 + player.vimeo.com
  286 + stream.softwarelivre.org
  287 + tv.softwarelivre.org
  288 + www.facebook.com
  289 + www.flickr.com
  290 + www.gmodules.com
  291 + www.youtube.com
  292 + ] + ('a' .. 'z').map{|i| "#{i}.yimg.com"}
  293 +
  294 + settings_items :enabled_plugins, :type => Array, :default => []
  295 +
  296 + settings_items :disabled_blocks, :type => Array, :default => []
  297 +
  298 + settings_items :search_hints, :type => Hash, :default => {}
  299 +
  300 + # Set to return http forbidden to host not on the allow origin list bellow
  301 + settings_items :restrict_to_access_control_origins, :default => false
  302 + # Set this according to http://www.w3.org/TR/cors/. Headers are set at every response
  303 + # For multiple domains acts as suggested in http://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains
  304 + settings_items :access_control_allow_origin, :type => Array, :default => []
  305 + settings_items :access_control_allow_methods, :type => String
  306 +
  307 + settings_items :signup_welcome_screen_body, :type => String
  308 +
  309 + def has_custom_welcome_screen?
  310 + settings[:signup_welcome_screen_body].present?
  311 + end
  312 +
  313 + def news_amount_by_folder=(amount)
  314 + settings[:news_amount_by_folder] = amount.to_i
  315 + end
  316 +
  317 + # Enables a feature identified by its name
  318 + def enable(feature, must_save=true)
  319 + self.settings["#{feature}_enabled".to_sym] = true
  320 + self.save! if must_save
  321 + end
  322 +
  323 + def enable_plugin(plugin)
  324 + self.enabled_plugins += [plugin.to_s]
  325 + self.enabled_plugins.uniq!
  326 + self.save!
  327 + end
  328 +
  329 + # Disables a feature identified by its name
  330 + def disable(feature, must_save=true)
  331 + self.settings["#{feature}_enabled".to_sym] = false
  332 + self.save! if must_save
  333 + end
  334 +
  335 + def disable_plugin(plugin)
  336 + self.enabled_plugins.delete(plugin.to_s)
  337 + self.save!
  338 + end
  339 +
  340 + # Tells if a feature, identified by its name, is enabled
  341 + def enabled?(feature)
  342 + self.settings["#{feature}_enabled".to_sym] == true
  343 + end
  344 + def disabled?(feature)
  345 + !self.enabled?(feature)
  346 + end
  347 +
  348 + def plugin_enabled?(plugin)
  349 + enabled_plugins.include?(plugin.to_s)
  350 + end
  351 +
  352 + def block_disabled?(block)
  353 + disabled_blocks.include?(block.to_s)
  354 + end
  355 +
  356 + # enables the features identified by <tt>features</tt>, which is expected to
  357 + # be an Enumarable object containing the identifiers of the desired features.
  358 + # Passing <tt>nil</tt> is the same as passing an empty Array.
  359 + def enabled_features=(features)
  360 + features ||= []
  361 + self.class.available_features.keys.each do |feature|
  362 + if features.include? feature
  363 + self.enable(feature)
  364 + else
  365 + self.disable(feature)
  366 + end
  367 + end
  368 + end
  369 +
  370 + def enabled_features
  371 + features = self.class.available_features
  372 + features.delete_if{ |k, v| !self.enabled?(k) }
  373 + end
  374 +
  375 + DEFAULT_FEATURES = %w(
  376 + disable_asset_products
  377 + disable_gender_icon
  378 + products_for_enterprises
  379 + disable_select_city_for_contact
  380 + enterprise_registration
  381 + media_panel
  382 + organizations_are_moderated_by_default
  383 + show_balloon_with_profile_links_when_clicked
  384 + show_zoom_button_on_article_images
  385 + use_portal_community
  386 + )
  387 +
  388 + before_create :enable_default_features
  389 + def enable_default_features
  390 + DEFAULT_FEATURES.each do |feature|
  391 + enable(feature, false)
  392 + end
  393 + end
  394 +
  395 + # returns <tt>true</tt> if this Environment has terms of use to be
  396 + # accepted by users before registration.
  397 + def has_terms_of_use?
  398 + ! self.terms_of_use.blank?
  399 + end
  400 +
  401 + # returns <tt>true</tt> if this Environment has terms of enterprise use to be
  402 + # accepted by users before registration or activation of enterprises.
  403 + def has_terms_of_enterprise_use?
  404 + ! self.terms_of_enterprise_use.blank?
  405 + end
  406 +
  407 + # Sets the organization_approval_method. Only accepts the following values:
  408 + #
  409 + # * <tt>:admin</tt>: organization registration must be approved by the
  410 + # environment administrator.
  411 + # * <tt>:region</tt>: organization registering must be approved by some other
  412 + # organization asssigned as validator to the Region the new organization
  413 + # belongs to.
  414 + # * <tt>:none</tt>: organization registration is approved by default.
  415 + #
  416 + # Trying to set organization_approval_method to any other value will raise an
  417 + # ArgumentError.
  418 + #
  419 + # The value passed as argument is converted to a Symbol before being actually
  420 + # set to this setting.
  421 + def organization_approval_method=(value)
  422 + actual_value = value.to_sym
  423 +
  424 + accepted_values = %w[
  425 + admin
  426 + region
  427 + none
  428 + ].map(&:to_sym)
  429 + raise ArgumentError unless accepted_values.include?(actual_value)
  430 +
  431 + self.settings[:organization_approval_method] = actual_value
  432 + end
  433 +
  434 + def custom_person_fields
  435 + self.settings[:custom_person_fields].nil? ? {} : self.settings[:custom_person_fields]
  436 + end
  437 +
  438 + def custom_person_fields=(values)
  439 + if values['schooling'] && values['schooling']['active'] == 'true'
  440 + schooling_status = values['schooling']
  441 + end
  442 +
  443 + self.settings[:custom_person_fields] = values.delete_if { |key, value| ! Person.fields.include?(key)}
  444 + self.settings[:custom_person_fields].each_pair do |key, value|
  445 + if value['required'] == 'true'
  446 + self.settings[:custom_person_fields][key]['active'] = 'true'
  447 + self.settings[:custom_person_fields][key]['signup'] = 'true'
  448 + end
  449 + if value['signup'] == 'true'
  450 + self.settings[:custom_person_fields][key]['active'] = 'true'
  451 + end
  452 + end
  453 +
  454 + if schooling_status
  455 + self.settings[:custom_person_fields]['schooling_status'] = schooling_status
  456 + end
  457 + end
  458 +
  459 + def custom_person_field(field, status)
  460 + if (custom_person_fields[field] && custom_person_fields[field][status] == 'true')
  461 + return true
  462 + end
  463 + false
  464 + end
  465 +
  466 + def active_person_fields
  467 + (custom_person_fields.delete_if { |key, value| !custom_person_field(key, 'active')}).keys || []
  468 + end
  469 +
  470 + def required_person_fields
  471 + required_fields = []
  472 + active_person_fields.each do |field|
  473 + required_fields << field if custom_person_fields[field]['required'] == 'true'
  474 + end
  475 + required_fields
  476 + end
  477 +
  478 + def signup_person_fields
  479 + signup_fields = []
  480 + active_person_fields.each do |field|
  481 + signup_fields << field if custom_person_fields[field]['signup'] == 'true'
  482 + end
  483 + signup_fields
  484 + end
  485 +
  486 + def invitation_mail_template(profile)
  487 + if profile.person?
  488 + message_for_friend_invitation
  489 + else
  490 + message_for_member_invitation
  491 + end
  492 + end
  493 +
  494 + def custom_enterprise_fields
  495 + self.settings[:custom_enterprise_fields].nil? ? {} : self.settings[:custom_enterprise_fields]
  496 + end
  497 +
  498 + def custom_enterprise_fields=(values)
  499 + self.settings[:custom_enterprise_fields] = values.delete_if { |key, value| ! Enterprise.fields.include?(key)}
  500 + self.settings[:custom_enterprise_fields].each_pair do |key, value|
  501 + if value['required'] == 'true'
  502 + self.settings[:custom_enterprise_fields][key]['active'] = 'true'
  503 + self.settings[:custom_enterprise_fields][key]['signup'] = 'true'
  504 + end
  505 + if value['signup'] == 'true'
  506 + self.settings[:custom_enterprise_fields][key]['active'] = 'true'
  507 + end
  508 + end
  509 + end
  510 +
  511 + def custom_enterprise_field(field, status)
  512 + if (custom_enterprise_fields[field] && custom_enterprise_fields[field][status] == 'true')
  513 + return true
  514 + end
  515 + false
  516 + end
  517 +
  518 + def active_enterprise_fields
  519 + (custom_enterprise_fields.delete_if { |key, value| !custom_enterprise_field(key, 'active')}).keys || []
  520 + end
  521 +
  522 + def required_enterprise_fields
  523 + required_fields = []
  524 + active_enterprise_fields.each do |field|
  525 + required_fields << field if custom_enterprise_fields[field]['required'] == 'true'
  526 + end
  527 + required_fields
  528 + end
  529 +
  530 + def signup_enterprise_fields
  531 + signup_fields = []
  532 + active_enterprise_fields.each do |field|
  533 + signup_fields << field if custom_enterprise_fields[field]['signup'] == 'true'
  534 + end
  535 + signup_fields
  536 + end
  537 +
  538 + def custom_community_fields
  539 + self.settings[:custom_community_fields].nil? ? {} : self.settings[:custom_community_fields]
  540 + end
  541 + def custom_community_fields=(values)
  542 + self.settings[:custom_community_fields] = values.delete_if { |key, value| ! Community.fields.include?(key) }
  543 + self.settings[:custom_community_fields].each_pair do |key, value|
  544 + if value['required'] == 'true'
  545 + self.settings[:custom_community_fields][key]['active'] = 'true'
  546 + self.settings[:custom_community_fields][key]['signup'] = 'true'
  547 + end
  548 + if value['signup'] == 'true'
  549 + self.settings[:custom_community_fields][key]['active'] = 'true'
  550 + end
  551 + end
  552 + end
  553 +
  554 + def custom_community_field(field, status)
  555 + if (custom_community_fields[field] && custom_community_fields[field][status] == 'true')
  556 + return true
  557 + end
  558 + false
  559 + end
  560 +
  561 + def active_community_fields
  562 + (custom_community_fields.delete_if { |key, value| !custom_community_field(key, 'active')}).keys
  563 + end
  564 +
  565 + def required_community_fields
  566 + required_fields = []
  567 + active_community_fields.each do |field|
  568 + required_fields << field if custom_community_fields[field]['required'] == 'true'
  569 + end
  570 + required_fields
  571 + end
  572 +
  573 + def signup_community_fields
  574 + signup_fields = []
  575 + active_community_fields.each do |field|
  576 + signup_fields << field if custom_community_fields[field]['signup'] == 'true'
  577 + end
  578 + signup_fields
  579 + end
  580 +
  581 + serialize :signup_welcome_text, Hash
  582 + def signup_welcome_text
  583 + self[:signup_welcome_text] ||= {}
  584 + end
  585 +
  586 + def signup_welcome_text_subject
  587 + self.signup_welcome_text[:subject]
  588 + end
  589 +
  590 + def signup_welcome_text_subject=(subject)
  591 + self.signup_welcome_text[:subject] = subject
  592 + end
  593 +
  594 + def signup_welcome_text_body
  595 + self.signup_welcome_text[:body]
  596 + end
  597 +
  598 + def signup_welcome_text_body=(body)
  599 + self.signup_welcome_text[:body] = body
  600 + end
  601 +
  602 + def has_signup_welcome_text?
  603 + signup_welcome_text && !signup_welcome_text_body.blank?
  604 + end
  605 +
  606 + # #################################################
  607 + # Validations
  608 + # #################################################
  609 +
  610 + # <tt>name</tt> is mandatory
  611 + validates_presence_of :name
  612 +
  613 + # only one environment can be the default one
  614 + validates_uniqueness_of :is_default, :if => (lambda do |environment| environment.is_default? end), :message => N_('Only one Virtual Community can be the default one')
  615 +
  616 + validates_format_of :contact_email, :noreply_email, :with => Noosfero::Constants::EMAIL_FORMAT, :allow_blank => true
  617 +
  618 + xss_terminate :only => [ :message_for_disabled_enterprise ], :with => 'white_list', :on => 'validation'
  619 +
  620 + validates_presence_of :theme
  621 + validates_numericality_of :reports_lower_bound, :allow_nil => false, :only_integer => true, :greater_than_or_equal_to => 0
  622 +
  623 + include WhiteListFilter
  624 + filter_iframes :message_for_disabled_enterprise
  625 + def iframe_whitelist
  626 + trusted_sites_for_iframe
  627 + end
  628 +
  629 + # #################################################
  630 + # Business logic in general
  631 + # #################################################
  632 +
  633 + # the default Environment.
  634 + def self.default
  635 + self.find(:first, :conditions => [ 'is_default = ?', true ] )
  636 + end
  637 +
  638 + # returns an array with the top level categories for this environment.
  639 + def top_level_categories
  640 + Category.top_level_for(self)
  641 + end
  642 +
  643 + # Returns the hostname of the first domain associated to this environment.
  644 + #
  645 + # If #force_www is true, adds 'www.' at the beginning of the hostname. If the
  646 + # environment has not associated domains, returns 'localhost'.
  647 + def default_hostname(email_hostname = false)
  648 + domain = 'localhost'
  649 + unless self.domains(true).empty?
  650 + domain = (self.domains.find_by_is_default(true) || self.domains.find(:first, :order => 'id')).name
  651 + domain = email_hostname ? domain : (force_www ? ('www.' + domain) : domain)
  652 + end
  653 + domain
  654 + end
  655 +
  656 + def admin_url
  657 + { :controller => 'admin_panel', :action => 'index' }
  658 + end
  659 +
  660 + def top_url
  661 + url = 'http://'
  662 + url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
  663 + url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
  664 + url
  665 + end
  666 +
  667 + def to_s
  668 + self.name || '?'
  669 + end
  670 +
  671 + has_many :articles, :through => :profiles
  672 + def recent_documents(limit = 10, options = {}, pagination = true)
  673 + self.articles.recent(limit, options, pagination)
  674 + end
  675 +
  676 + has_many :events, :through => :profiles, :source => :articles, :class_name => 'Event'
  677 +
  678 + has_many :tags, :through => :articles
  679 +
  680 + def tag_counts
  681 + articles.tag_counts.inject({}) do |memo,tag|
  682 + memo[tag.name] = tag.count
  683 + memo
  684 + end
  685 + end
  686 +
  687 + def themes
  688 + if settings[:themes]
  689 + Theme.system_themes.select { |theme| settings[:themes].include?(theme.id) }
  690 + else
  691 + []
  692 + end
  693 + end
  694 +
  695 + def themes=(values)
  696 + settings[:themes] = values
  697 + end
  698 +
  699 + def add_themes(values)
  700 + if settings[:themes].nil?
  701 + self.themes = values
  702 + else
  703 + settings[:themes] += values
  704 + end
  705 + end
  706 +
  707 + def update_theme(theme)
  708 + self.theme = theme
  709 + self.save!
  710 + end
  711 +
  712 + def update_layout_template(template)
  713 + self.layout_template = template
  714 + self.save!
  715 + end
  716 +
  717 + before_create do |env|
  718 + env.settings[:themes] ||= %w[
  719 + aluminium
  720 + butter
  721 + chameleon
  722 + chocolate
  723 + noosfero
  724 + orange
  725 + plum
  726 + scarletred
  727 + skyblue
  728 + ]
  729 + end
  730 +
  731 + def community_template
  732 + template = Community.find_by_id settings[:community_template_id]
  733 + template if template && template.is_template
  734 + end
  735 +
  736 + def community_template=(value)
  737 + settings[:community_template_id] = value.id
  738 + end
  739 +
  740 + def person_template
  741 + template = Person.find_by_id settings[:person_template_id]
  742 + template if template && template.is_template
  743 + end
  744 +
  745 + def person_template=(value)
  746 + settings[:person_template_id] = value.id
  747 + end
  748 +
  749 + def enterprise_template
  750 + template = Enterprise.find_by_id settings[:enterprise_template_id]
  751 + template if template && template.is_template
  752 + end
  753 +
  754 + def enterprise_template=(value)
  755 + settings[:enterprise_template_id] = value.id
  756 + end
  757 +
  758 + def inactive_enterprise_template
  759 + template = Enterprise.find_by_id settings[:inactive_enterprise_template_id]
  760 + template if template && template.is_template
  761 + end
  762 +
  763 + def inactive_enterprise_template=(value)
  764 + settings[:inactive_enterprise_template_id] = value.id
  765 + end
  766 +
  767 + def replace_enterprise_template_when_enable
  768 + settings[:replace_enterprise_template_when_enable] || false
  769 + end
  770 +
  771 + def replace_enterprise_template_when_enable=(value)
  772 + settings[:replace_enterprise_template_when_enable] = value
  773 + end
  774 +
  775 + def portal_community
  776 + Community[settings[:portal_community_identifier]]
  777 + end
  778 +
  779 + def portal_community=(value)
  780 + settings[:portal_community_identifier] = value.nil? ? nil : value.identifier
  781 + end
  782 +
  783 + def unset_portal_community!
  784 + self.portal_community=nil
  785 + self.portal_folders=nil
  786 + self.news_amount_by_folder=nil
  787 + self.disable('use_portal_community')
  788 + self.save
  789 + end
  790 +
  791 + def is_portal_community?(profile)
  792 + portal_community == profile
  793 + end
  794 +
  795 + def portal_folders
  796 + (settings[:portal_folders] || []).map{|fid| portal_community.articles.find(:first, :conditions => { :id => fid }) }.compact
  797 + end
  798 +
  799 + def portal_folders=(folders)
  800 + settings[:portal_folders] = folders ? folders.map(&:id) : nil
  801 + end
  802 +
  803 + def portal_news_cache_key(language='en')
  804 + "home-page-news/#{cache_key}-#{language}"
  805 + end
  806 +
  807 + def notification_emails
  808 + [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email)
  809 + end
  810 +
  811 + after_create :create_templates
  812 +
  813 + def create_templates
  814 + prefix = self.name.to_slug + '_'
  815 +
  816 + enterprise_template = Enterprise.new(
  817 + :name => 'Enterprise template',
  818 + :identifier => prefix + 'enterprise_template'
  819 + )
  820 +
  821 + inactive_enterprise_template = Enterprise.new(
  822 + :name => 'Inactive Enterprise template',
  823 + :identifier => prefix + 'inactive_enterprise_template'
  824 + )
  825 +
  826 + community_template = Community.new(
  827 + :name => 'Community template',
  828 + :identifier => prefix + 'community_template'
  829 + )
  830 +
  831 + [
  832 + enterprise_template,
  833 + inactive_enterprise_template,
  834 + community_template
  835 + ].each do |profile|
  836 + profile.is_template = true
  837 + profile.visible = false
  838 + profile.environment = self
  839 + profile.save!
  840 + end
  841 +
  842 + pass = Digest::MD5.hexdigest rand.to_s
  843 + user = User.new(:login => (prefix + 'person_template'), :email => (prefix + 'template@template.noo'), :password => pass, :password_confirmation => pass)
  844 + user.environment = self
  845 + user.save!
  846 +
  847 + person_template = user.person
  848 + person_template.name = "Person template"
  849 + person_template.is_template = true
  850 + person_template.visible = false
  851 + person_template.save!
  852 +
  853 + self.enterprise_template = enterprise_template
  854 + self.inactive_enterprise_template = inactive_enterprise_template
  855 + self.community_template = community_template
  856 + self.person_template = person_template
  857 + self.save!
  858 + end
  859 +
  860 + after_create :create_default_licenses
  861 + def create_default_licenses
  862 + [
  863 + { :name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode'},
  864 + { :name => 'CC (by-nd)', :url => 'http://creativecommons.org/licenses/by-nd/3.0/legalcode'},
  865 + { :name => 'CC (by-sa)', :url => 'http://creativecommons.org/licenses/by-sa/3.0/legalcode'},
  866 + { :name => 'CC (by-nc)', :url => 'http://creativecommons.org/licenses/by-nc/3.0/legalcode'},
  867 + { :name => 'CC (by-nc-nd)', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode'},
  868 + { :name => 'CC (by-nc-sa)', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode'},
  869 + { :name => 'Free Art', :url => 'http://artlibre.org/licence/lal/en'},
  870 + { :name => 'GNU FDL', :url => 'http://www.gnu.org/licenses/fdl-1.3.txt'},
  871 + ].each do |data|
  872 + license = License.new(data)
  873 + license.environment = self
  874 + license.save!
  875 + end
  876 + end
  877 +
  878 + def highlighted_products_with_image(options = {})
  879 + Product.find(:all, {:conditions => {:highlighted => true, :profile_id => self.enterprises.find(:all, :select => :id) }, :joins => :image}.merge(options))
  880 + end
  881 +
  882 + settings_items :home_cache_in_minutes, :type => :integer, :default => 5
  883 + settings_items :general_cache_in_minutes, :type => :integer, :default => 15
  884 + settings_items :profile_cache_in_minutes, :type => :integer, :default => 15
  885 +
  886 + def image_galleries
  887 + portal_community ? portal_community.image_galleries : []
  888 + end
  889 +
  890 + serialize :languages
  891 +
  892 + before_validation do |environment|
  893 + environment.default_language = nil if environment.default_language.blank?
  894 + end
  895 +
  896 + validate :default_language_available
  897 + validate :languages_available
  898 +
  899 + def locales
  900 + if languages.present?
  901 + languages.inject({}) {|r, l| r.merge({l => Noosfero.locales[l]})}
  902 + else
  903 + Noosfero.locales
  904 + end
  905 + end
  906 +
  907 + def default_locale
  908 + default_language || Noosfero.default_locale
  909 + end
  910 +
  911 + def available_locales
  912 + locales_list = locales.keys
  913 + # move English to the beginning
  914 + if locales_list.include?('en')
  915 + locales_list = ['en'] + (locales_list - ['en']).sort
  916 + end
  917 + locales_list
  918 + end
  919 +
  920 + private
  921 +
  922 + def default_language_available
  923 + if default_language.present? && !available_locales.include?(default_language)
  924 + errors.add(:default_language, _('is not available.'))
  925 + end
  926 + end
  927 +
  928 + def languages_available
  929 + if languages.present?
  930 + languages.each do |language|
  931 + if !Noosfero.available_locales.include?(language)
  932 + errors.add(:languages, _('have unsupported languages.'))
  933 + break
  934 + end
  935 + end
  936 + end
  937 + end
  938 +end
... ...
app/models/friends_block.rb
... ... @@ -1,26 +0,0 @@
1   -class FriendsBlock < ProfileListBlock
2   -
3   - def self.description
4   - _('Friends')
5   - end
6   -
7   - def default_title
8   - n_('{#} friend', '{#} friends', profile_count)
9   - end
10   -
11   - def help
12   - _('This block displays your friends.')
13   - end
14   -
15   - def footer
16   - owner_id = owner.identifier
17   - proc do
18   - link_to s_('friends|View all'), :profile => owner_id, :controller => 'profile', :action => 'friends'
19   - end
20   - end
21   -
22   - def profiles
23   - owner.friends
24   - end
25   -
26   -end
app/models/members_block.rb
... ... @@ -1,52 +0,0 @@
1   -class MembersBlock < ProfileListBlock
2   - settings_items :show_join_leave_button, :type => :boolean, :default => false
3   -
4   - attr_accessible :show_join_leave_button
5   -
6   - def self.description
7   - _('Members')
8   - end
9   -
10   - def default_title
11   - _('{#} members')
12   - end
13   -
14   - def help
15   - _('This block presents the members of a collective.')
16   - end
17   -
18   - def footer
19   - profile = self.owner
20   - s = show_join_leave_button
21   -
22   - proc do
23   - render :file => 'blocks/members', :locals => { :profile => profile, :show_join_leave_button => s}
24   - end
25   - end
26   -
27   - def profiles
28   - owner.members
29   - end
30   -
31   - def extra_option
32   - data = {
33   - :human_name => _("Show join leave button"),
34   - :name => 'block[show_join_leave_button]',
35   - :value => true,
36   - :checked => show_join_leave_button,
37   - :options => {}
38   - }
39   - end
40   -
41   - def cache_key(language='en', user=nil)
42   - logged = ''
43   - if user
44   - logged += '-logged-in'
45   - if user.is_member_of? self.owner
46   - logged += '-member'
47   - end
48   - end
49   - super + logged
50   - end
51   -
52   -end
app/models/organization.rb
... ... @@ -123,7 +123,7 @@ class Organization &lt; Profile
123 123 [
124 124 [MainBlock.new],
125 125 [ProfileImageBlock.new, LinkListBlock.new(:links => links)],
126   - [MembersBlock.new, RecentDocumentsBlock.new]
  126 + [RecentDocumentsBlock.new]
127 127 ]
128 128 end
129 129  
... ...
app/models/people_block.rb
... ... @@ -1,25 +0,0 @@
1   -class PeopleBlock < ProfileListBlock
2   -
3   - def default_title
4   - _('People')
5   - end
6   -
7   - def help
8   - _('Clicking a person takes you to his/her homepage')
9   - end
10   -
11   - def self.description
12   - _('Random people')
13   - end
14   -
15   - def profiles
16   - owner.people
17   - end
18   -
19   - def footer
20   - lambda do |context|
21   - link_to _('View all'), :controller => 'search', :action => 'people'
22   - end
23   - end
24   -
25   -end
app/models/person.rb
... ... @@ -269,7 +269,7 @@ class Person &lt; Profile
269 269 [
270 270 [MainBlock.new],
271 271 [ProfileImageBlock.new(:show_name => true), LinkListBlock.new(:links => links), RecentDocumentsBlock.new],
272   - [FriendsBlock.new, CommunitiesBlock.new]
  272 + [CommunitiesBlock.new]
273 273 ]
274 274 end
275 275  
... ...
app/sweepers/friendship_sweeper.rb
... ... @@ -34,8 +34,7 @@ protected
34 34 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
35 35 end
36 36  
37   - blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}
38   - BlockSweeper.expire_blocks(blocks)
  37 + expire_blocks_cache(profile, [:profile])
39 38 end
40 39  
41 40 end
... ...
app/views/blocks/members.html.erb
... ... @@ -1,5 +0,0 @@
1   -<%= link_to _('View all'), :profile => profile.identifier, :controller => 'profile', :action => 'members' %>
2   -
3   -<% if show_join_leave_button %>
4   - <%= render :partial => 'blocks/profile_info_actions/join_leave_community' %>
5   -<% end %>
app/views/layouts/application-ng.html.erb
... ... @@ -83,5 +83,10 @@
83 83 <%= noosfero_layout_features %>
84 84 <%= theme_javascript_ng %>
85 85 <%= addthis_javascript %>
  86 + <%=
  87 + @plugins.dispatch(:body_ending).map do |content|
  88 + if content.respond_to?(:call) then instance_exec(&content).html_safe else content.html_safe end
  89 + end.join("\n")
  90 + %>
86 91 </body>
87 92 </html>
... ...
app/views/profile_members/_members_list.html.erb
... ... @@ -17,9 +17,9 @@
17 17 <%= button_without_text :edit, _('Edit'), :action => 'change_role', :id => m %>
18 18 <%= button_to_remote_without_text(:remove, _('Remove'),
19 19 :update => 'members-list',
20   - :loading => j('$("members-list").addClassName("loading")'),
21   - :success => j("$('tr-#{m.identifier}').show()"),
22   - :complete => j('$("members-list").removeClassName("loading")'),
  20 + :loading => "$('members-list').addClassName('loading')",
  21 + :success => "$('tr-#{m.identifier}').show()",
  22 + :complete => "$('members-list').removeClassName('loading')",
23 23 :url => { :id => m }.merge(remove_action)) if m != user %>
24 24 </div>
25 25 </td>
... ...
config/application.rb
... ... @@ -20,7 +20,7 @@ module Noosfero
20 20 require 'noosfero/plugin'
21 21  
22 22 # Adds custom attributes to the Set of allowed html attributes for the #sanitize helper
23   - config.action_view.sanitized_allowed_attributes = 'align', 'border', 'alt', 'vspace', 'hspace', 'width', 'heigth', 'value', 'type', 'data', 'style', 'target', 'codebase', 'archive', 'classid', 'code', 'flashvars', 'scrolling', 'frameborder', 'controls', 'autoplay'
  23 + config.action_view.sanitized_allowed_attributes = 'align', 'border', 'alt', 'vspace', 'hspace', 'width', 'heigth', 'value', 'type', 'data', 'style', 'target', 'codebase', 'archive', 'classid', 'code', 'flashvars', 'scrolling', 'frameborder', 'controls', 'autoplay', 'colspan', 'rowspan'
24 24  
25 25 # Adds custom tags to the Set of allowed html tags for the #sanitize helper
26 26 config.action_view.sanitized_allowed_tags = 'object', 'embed', 'param', 'table', 'tr', 'th', 'td', 'applet', 'comment', 'iframe', 'audio', 'video', 'source'
... ...
config/plugins/people_block 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../../plugins/people_block
0 2 \ No newline at end of file
... ...
db/migrate/20140415125414_add_created_by_to_article.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class AddCreatedByToArticle < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :articles, :created_by_id, :integer
  4 + add_column :article_versions, :created_by_id, :integer
  5 +
  6 + execute("UPDATE article_versions SET created_by_id = last_changed_by_id")
  7 +
  8 + execute("UPDATE articles SET created_by_id = article_versions.created_by_id
  9 +FROM article_versions WHERE article_versions.article_id = articles.id AND
  10 +article_versions.version = 1")
  11 + end
  12 +
  13 + def self.down
  14 + remove_column :articles, :created_by_id
  15 + remove_column :article_versions, :created_by_id
  16 + end
  17 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20140408172149) do
  14 +ActiveRecord::Schema.define(:version => 20140415125414) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -95,6 +95,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140408172149) do
95 95 t.integer "license_id"
96 96 t.integer "image_id"
97 97 t.integer "position"
  98 + t.integer "created_by_id"
98 99 end
99 100  
100 101 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id"
... ... @@ -140,6 +141,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140408172149) do
140 141 t.integer "license_id"
141 142 t.integer "image_id"
142 143 t.integer "position"
  144 + t.integer "created_by_id"
143 145 end
144 146  
145 147 add_index "articles", ["comments_count"], :name => "index_articles_on_comments_count"
... ...
features/my_network_block.feature
... ... @@ -9,9 +9,11 @@ Feature: my_network_block
9 9 And the following blocks
10 10 | owner | type |
11 11 | joaosilva | MyNetworkBlock |
  12 + | joaosilva | FriendsBlock |
12 13 And the following communities
13 14 | identifier | name | public_profile |
14 15 | public-community | Public Community | true |
  16 + And plugin FriendsBlock is enabled on environment
15 17  
16 18 @selenium
17 19 Scenario: display how many public/private communities I am member
... ... @@ -46,6 +48,10 @@ Feature: my_network_block
46 48 | login | name | public_profile |
47 49 | mariasilva | Maria Silva | true |
48 50 | josesilva | Jose Silva | false |
  51 + And the following blocks
  52 + | owner | type |
  53 + | mariasilva | FriendsBlock |
  54 + | josesilva | FriendsBlock |
49 55 And "joaosilva" is friend of "mariasilva"
50 56 And I am logged in as "joaosilva"
51 57 And I am on joaosilva's homepage
... ... @@ -59,6 +65,10 @@ Feature: my_network_block
59 65 | login | name |
60 66 | mariasilva | Maria Silva |
61 67 | josesilva | Jose Silva |
  68 + And the following blocks
  69 + | owner | type |
  70 + | mariasilva | FriendsBlock |
  71 + | josesilva | FriendsBlock |
62 72 And "josesilva" is invisible
63 73 And "joaosilva" is friend of "mariasilva"
64 74 And I am logged in as "joaosilva"
... ...
lib/noosfero/plugin.rb
... ... @@ -277,6 +277,12 @@ class Noosfero::Plugin
277 277 nil
278 278 end
279 279  
  280 + # -> Adds content to the ending of the page
  281 + # returns = lambda block that creates html code or raw rhtml/html.erb
  282 + def body_ending
  283 + nil
  284 + end
  285 +
280 286 # -> Adds content to the ending of the page head
281 287 # returns = lambda block that creates html code or raw rhtml/html.erb
282 288 def head_ending
... ...
plugins/display_content/lib/display_content_block.rb
... ... @@ -102,7 +102,7 @@ class DisplayContentBlock &lt; Block
102 102 end
103 103  
104 104 def parent_nodes
105   - @parent_nodes ||= self.holder.articles.find(nodes).map { |article| get_parent(article) }.compact.flatten
  105 + @parent_nodes ||= self.holder.articles.where(:id => nodes).map { |article| get_parent(article) }.compact.flatten
106 106 end
107 107  
108 108 VALID_CONTENT = ['RawHTMLArticle', 'TextArticle', 'TextileArticle', 'TinyMceArticle', 'Folder', 'Blog', 'Forum']
... ...
plugins/display_content/test/unit/display_content_block_test.rb
... ... @@ -549,7 +549,7 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
549 549 a1 = fast_create(PluginArticle, :name => 'test article 1', :profile_id => profile.id)
550 550 Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
551 551 env = fast_create(Environment)
552   - env.enable_plugin(Plugin1)
  552 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([Plugin1.new])
553 553  
554 554 block = DisplayContentBlock.new
555 555 box = mock()
... ... @@ -632,4 +632,19 @@ class DisplayContentBlockTest &lt; ActiveSupport::TestCase
632 632 assert_equal [UploadedFile, Event, TinyMceArticle, TextileArticle, RawHTMLArticle, Folder, Blog, Forum, Gallery, RssFeed, SomePluginContent], block.available_content_types
633 633 end
634 634  
  635 + should 'do not fail if a selected article was removed' do
  636 + profile = create_user('testuser').person
  637 + Article.delete_all
  638 + f1 = fast_create(Folder, :name => 'test folder 1', :profile_id => profile.id)
  639 + a1 = fast_create(TextileArticle, :name => 'test article 1', :profile_id => profile.id, :parent_id => f1.id)
  640 +
  641 + checked_articles= {a1.id => true}
  642 +
  643 + block = DisplayContentBlock.new
  644 + block.stubs(:holder).returns(profile)
  645 + block.checked_nodes= checked_articles
  646 + a1.destroy
  647 + assert_equal [], block.parent_nodes
  648 + end
  649 +
635 650 end
... ...
plugins/people_block/before_disable.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +raise "\nPeopleBlockPlugin shouldn't be enabled/disabled by hand, Noosfero" +
  2 + "\ninstallation already comes with it enabled by default!\n"
... ...
plugins/people_block/controllers/people_block_plugin_profile_controller.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class PeopleBlockPluginProfileController < ProfileController
  2 +
  3 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  4 +
  5 + def members
  6 + if is_cache_expired?(profile.members_cache_key(params))
  7 + if(params[:role_key])
  8 + role = Role.find_by_key_and_environment_id(params[:role_key], profile.environment)
  9 + @members = profile.members.with_role(role.id).includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage])
  10 + @members_title = role.name
  11 + else
  12 + @members = profile.members.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage])
  13 + @members_title = 'members'
  14 + end
  15 + end
  16 + render "profile/members"
  17 + end
  18 +
  19 +end
... ...
plugins/people_block/db/migrate/20140605222753_enable_people_block_plugin.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class EnablePeopleBlockPlugin < ActiveRecord::Migration
  2 + def up
  3 + Environment.all.each do |env|
  4 + env.enabled_plugins << 'PeopleBlockPlugin'
  5 + env.enabled_plugins.uniq!
  6 + env.save!
  7 + end
  8 + end
  9 +
  10 + def down
  11 + Environment.all.each do |env|
  12 + env.enabled_plugins.delete_if {|i| i== 'PeopleBlockPlugin'}
  13 + env.save!
  14 + end
  15 + end
  16 +end
... ...
plugins/people_block/lib/ext/person.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +require_dependency 'person'
  2 +
  3 +class Person
  4 +
  5 + scope :with_role, lambda { |role_id|
  6 + { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ["role_assignments.role_id = #{role_id}"] }
  7 + }
  8 +
  9 +end
... ...
plugins/people_block/lib/friends_block.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +class FriendsBlock < PeopleBlockBase
  2 +
  3 + def self.description
  4 + _('Friends')
  5 + end
  6 +
  7 + def help
  8 + _('Clicking a friend takes you to his/her homepage')
  9 + end
  10 +
  11 + def default_title
  12 + n_('{#} friend', '{#} friends', profile_count)
  13 + end
  14 +
  15 + def profiles
  16 + owner.friends
  17 + end
  18 +
  19 + def footer
  20 + profile = self.owner
  21 + proc do
  22 + render :file => 'blocks/friends', :locals => { :profile => profile }
  23 + end
  24 + end
  25 +
  26 + def self.expire_on
  27 + { :profile => [:profile] }
  28 + end
  29 +
  30 +end
... ...
plugins/people_block/lib/members_block.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +class MembersBlock < PeopleBlockBase
  2 + settings_items :show_join_leave_button, :type => :boolean, :default => false
  3 + settings_items :visible_role, :type => :string, :default => nil
  4 + attr_accessible :show_join_leave_button, :visible_role
  5 +
  6 + def self.description
  7 + _('Members')
  8 + end
  9 +
  10 + def help
  11 + _('Clicking a member takes you to his/her homepage')
  12 + end
  13 +
  14 + def default_title
  15 + title = role ? role.name : n_('members')
  16 + _('{#} %s') % title
  17 + end
  18 +
  19 + def profiles
  20 + role ? owner.members.with_role(role.id) : owner.members
  21 + end
  22 +
  23 + def footer
  24 + profile = self.owner
  25 + role_key = visible_role
  26 + s = show_join_leave_button
  27 + proc do
  28 + render :file => 'blocks/members', :locals => { :profile => profile, :show_join_leave_button => s, :role_key => role_key}
  29 + end
  30 + end
  31 +
  32 + def role
  33 + visible_role && !visible_role.empty? ? Role.find_by_key_and_environment_id(visible_role, owner.environment) : nil
  34 + end
  35 +
  36 + def roles
  37 + Profile::Roles.organization_member_roles(owner.environment)
  38 + end
  39 +
  40 + def extra_option
  41 + data = {
  42 + :human_name => _("Show join leave button"),
  43 + :name => 'block[show_join_leave_button]',
  44 + :value => true,
  45 + :checked => show_join_leave_button,
  46 + :options => {}
  47 + }
  48 + end
  49 +
  50 +end
... ...
plugins/people_block/lib/people_block.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +class PeopleBlock < PeopleBlockBase
  2 +
  3 + def self.description
  4 + _('People')
  5 + end
  6 +
  7 + def help
  8 + _('Clicking a person takes you to his/her homepage')
  9 + end
  10 +
  11 + def default_title
  12 + _('{#} People')
  13 + end
  14 +
  15 + def profiles
  16 + owner.people
  17 + end
  18 +
  19 + def footer
  20 + proc do
  21 + render :file => 'blocks/people'
  22 + end
  23 + end
  24 +
  25 +end
... ...
plugins/people_block/lib/people_block_base.rb 0 → 100644
... ... @@ -0,0 +1,100 @@
  1 +class PeopleBlockBase < Block
  2 + settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true
  3 + settings_items :limit, :type => :integer, :default => 6
  4 + settings_items :name, :type => String, :default => ""
  5 + settings_items :address, :type => String, :default => ""
  6 + attr_accessible :name, :address, :prioritize_profiles_with_image
  7 +
  8 + def self.description
  9 + _('Random people')
  10 + end
  11 +
  12 + def help
  13 + _('Clicking on the people or groups will take you to their home page.')
  14 + end
  15 +
  16 + def default_title
  17 + _('{#} People')
  18 + end
  19 +
  20 + def view_title
  21 + title.gsub('{#}', profile_count.to_s)
  22 + end
  23 +
  24 + def profiles
  25 + owner.profiles
  26 + end
  27 +
  28 + def profile_list
  29 + result = nil
  30 + visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment])
  31 + if !prioritize_profiles_with_image
  32 + result = visible_profiles.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand }
  33 + elsif visible_profiles.with_image.count >= limit
  34 + result = visible_profiles.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
  35 + else
  36 + result = visible_profiles.with_image.sort_by{ rand } + visible_profiles.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
  37 + end
  38 + result.slice(0..limit-1)
  39 + end
  40 +
  41 + def profile_count
  42 + profiles.visible.count
  43 + end
  44 +
  45 + def content(args={})
  46 + profiles = self.profile_list
  47 + title = self.view_title
  48 +
  49 + if !self.name.blank? && !self.address.blank?
  50 + name = self.name
  51 + expanded_address = expand_address(self.address)
  52 + end
  53 +
  54 + proc do
  55 + count = 0
  56 + list = profiles.map {|item|
  57 + count += 1
  58 + send(:profile_image_link, item, :minor )
  59 + }.join("\n")
  60 + if list.empty?
  61 + list = content_tag 'div', _('None'), :class => 'common-profile-list-block-none'
  62 + else
  63 + if !name.blank? && !expanded_address.blank?
  64 + list << content_tag(
  65 + 'div',
  66 + content_tag(
  67 + 'li',
  68 + content_tag(
  69 + 'div',
  70 + link_to(
  71 + content_tag('span', name, :class => 'banner-span' ),
  72 + expanded_address,
  73 + :title => name
  74 + ),
  75 + :class => 'banner-div'
  76 + ),
  77 + :class => 'vcard'
  78 + ),
  79 + :class => 'common-profile-list-block'
  80 + )
  81 + end
  82 + list = content_tag 'ul', list
  83 + end
  84 + block_title(title) + content_tag('div', list + tag('br', :style => 'clear:both'))
  85 + end
  86 + end
  87 +
  88 + def expand_address(address)
  89 + if address !~ /^[a-z]+:\/\// && address !~ /^\//
  90 + 'http://' + address
  91 + else
  92 + address
  93 + end
  94 + end
  95 +
  96 + def extra_option
  97 + { }
  98 + end
  99 +
  100 +end
... ...
plugins/people_block/lib/people_block_plugin.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class PeopleBlockPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + "People Block Plugin"
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("A plugin that adds a people block")
  9 + end
  10 +
  11 + def self.extra_blocks
  12 + {
  13 + PeopleBlock => {:type => Environment},
  14 + MembersBlock => {:type => Community},
  15 + FriendsBlock => {:type => Person}
  16 + }
  17 + end
  18 +
  19 + def self.has_admin_url?
  20 + false
  21 + end
  22 +
  23 + def stylesheet?
  24 + true
  25 + end
  26 +
  27 +end
... ...
plugins/people_block/public/style.css 0 → 100644
... ... @@ -0,0 +1,104 @@
  1 +/*******************************************************************
  2 + * COMMON *
  3 + *******************************************************************/
  4 +.people-block .block-footer-content a {
  5 + position: absolute;
  6 + top: 2px;
  7 + right: 0px;
  8 + font-size: 11px;
  9 + color: #000;
  10 + text-decoration: none;
  11 + padding-right: 15px;
  12 +}
  13 +
  14 +.people-block .banner-span {
  15 + color: #000;
  16 + font-size: 14pt;
  17 + font-weight: bold;
  18 + background-color: #EEE;
  19 +}
  20 +
  21 +
  22 +/*******************************************************************
  23 + * MAIN BOX - 1 *
  24 + *******************************************************************/
  25 +.box-1 .people-block .banner-div {
  26 + line-height: 112px;
  27 +}
  28 +
  29 +.box-1 .people-block .banner-span {
  30 + width: 204px;
  31 +}
  32 +
  33 +
  34 +/*******************************************************************
  35 + * LEFT/RIGHT BOXES *
  36 + *******************************************************************/
  37 +.box-2 .people-block .banner-div,
  38 +.box-3 .people-block .banner-div {
  39 + line-height: 78px;
  40 +}
  41 +
  42 +.box-2 .people-block .banner-div a,
  43 +.box-3 .people-block .banner-div a {
  44 + height: 78px;
  45 +}
  46 +
  47 +.box-2 .people-block .banner-span,
  48 +.box-3 .people-block .banner-span {
  49 + width: 116px;
  50 +}
  51 +
  52 +.box-2 .people-block ul,
  53 +.box-3 .people-block ul {
  54 + min-width: 196px;
  55 + width: 192px;
  56 + margin: 0px 0px 0px -3px;
  57 + padding: 0px;
  58 +}
  59 +
  60 +/*******************************************************************
  61 + * BLOCKs *
  62 + *******************************************************************/
  63 +#content .friends-block ul,
  64 +#content .members-block ul {
  65 + min-width: 196px;
  66 + width: 192px;
  67 + margin: 0px 0px 0px -3px;
  68 + padding: 0px;
  69 +}
  70 +#content .box-1 .people-block ul,
  71 +#content .box-1 .friends-block ul,
  72 +#content .box-1 .members-block ul {
  73 + width: auto;
  74 + display: block;
  75 +}
  76 +#content .people-block .block-footer-content a,
  77 +#content .friends-block .block-footer-content a,
  78 +#content .members-block .block-footer-content a {
  79 + position: absolute;
  80 + top: 2px;
  81 + right: 0px;
  82 + font-size: 11px;
  83 + color: #000;
  84 + text-decoration: none;
  85 + padding-right: 15px;
  86 +}
  87 +#content .members-block .block-footer-content .join-leave-button a {
  88 + position: relative;
  89 + background-color: #EEE;
  90 + border: 1px solid #CCC;
  91 + color: #555;
  92 + padding-right: inherit;
  93 +}
  94 +#content .members-block .block-footer-content .join-leave-button a:hover {
  95 + color: #FFF;
  96 + background-color: #555;
  97 + border: 1px solid #2e3436;
  98 + text-decoration: none;
  99 +}
  100 +#content .people-block .block-footer-content a.view-all,
  101 +#content .friends-block .block-footer-content a.view-all,
  102 +#content .members-block .block-footer-content a.view-all {
  103 + background: url(/designs/themes/base/imgs/arrow-right-p.png) 100% 50% no-repeat;
  104 +}
... ...
plugins/people_block/test/functional/people_block_plugin_environment_design_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class EnvironmentDesignController; def rescue_action(e) raise e end; end
  5 +
  6 +class EnvironmentDesignControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @controller = EnvironmentDesignController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([PeopleBlockPlugin.new])
  13 + end
  14 +
  15 + should 'be able to edit PeopleBlock' do
  16 + login_as(create_admin_user(Environment.default))
  17 + b = PeopleBlock.create!
  18 + e = Environment.default
  19 + e.boxes.create!
  20 + e.boxes.first.blocks << b
  21 + get :edit, :id => b.id
  22 + assert_tag :tag => 'input', :attributes => { :id => 'block_limit' }
  23 + end
  24 +
  25 +end
... ...
plugins/people_block/test/functional/people_block_plugin_profile_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,76 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/people_block_plugin_profile_controller'
  3 +
  4 +
  5 +# Re-raise errors caught by the controller.
  6 +class PeopleBlockPluginProfileController; def rescue_action(e) raise e end; end
  7 +
  8 +class PeopleBlockPluginProfileControllerTest < ActionController::TestCase
  9 +
  10 + def setup
  11 + @controller = PeopleBlockPluginProfileController.new
  12 + @request = ActionController::TestRequest.new
  13 + @response = ActionController::TestResponse.new
  14 +
  15 + @profile = fast_create(Community)
  16 +
  17 + @environment = @profile.environment
  18 + @environment.enabled_plugins = ['PeopleBlockPlugin']
  19 + @environment.save!
  20 +
  21 + MembersBlock.delete_all
  22 + @block = MembersBlock.new
  23 + @block.box = @profile.boxes.first
  24 + @block.save!
  25 +
  26 + @admin = create_user('adminprofile').person
  27 + @member = create_user('memberprofile').person
  28 + @moderator = create_user('moderatorprofile').person
  29 + @profile.add_moderator(@moderator)
  30 + @profile.add_member(@member)
  31 + @profile.add_admin(@admin)
  32 + end
  33 +
  34 + attr_accessor :profile, :block, :admin, :member, :moderator
  35 +
  36 + should 'list members without role_key' do
  37 + get :members, :profile => profile.identifier
  38 + assert_response :success
  39 + assert_template 'members'
  40 + assert_equivalent [@admin, @member, @moderator], assigns(:members)
  41 + assert_match /adminprofile/, @response.body
  42 + assert_match /memberprofile/, @response.body
  43 + assert_match /moderatorprofile/, @response.body
  44 + end
  45 +
  46 + should 'list members with role_key=nil' do
  47 + get :members, :profile => profile.identifier, :role_key => nil
  48 + assert_response :success
  49 + assert_template 'members'
  50 + assert_equivalent [@admin, @member, @moderator], assigns(:members)
  51 + assert_match /adminprofile/, @response.body
  52 + assert_match /memberprofile/, @response.body
  53 + assert_match /moderatorprofile/, @response.body
  54 + end
  55 +
  56 + should 'list members only' do
  57 + get :members, :profile => profile.identifier, :role_key => Profile::Roles.member(profile.environment.id).key
  58 + assert_response :success
  59 + assert_template 'members'
  60 + assert_equal [@member], assigns(:members)
  61 + assert_no_match /adminprofile/, @response.body
  62 + assert_match /memberprofile/, @response.body
  63 + assert_no_match /moderatorprofile/, @response.body
  64 + end
  65 +
  66 + should 'list moderators only' do
  67 + get :members, :profile => profile.identifier, :role_key => Profile::Roles.moderator(profile.environment.id).key
  68 + assert_response :success
  69 + assert_template 'members'
  70 + assert_equal [@moderator], assigns(:members)
  71 + assert_no_match /adminprofile/, @response.body
  72 + assert_no_match /memberprofile/, @response.body
  73 + assert_match /moderatorprofile/, @response.body
  74 + end
  75 +
  76 +end
... ...
plugins/people_block/test/functional/people_block_plugin_profile_design_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,70 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class ProfileDesignController; def rescue_action(e) raise e end; end
  5 +
  6 +class ProfileDesignControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @controller = ProfileDesignController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([PeopleBlockPlugin.new])
  13 + end
  14 +
  15 + should 'display *block people-block* class at design blocks page' do
  16 + user = create_user('testinguser')
  17 + login_as(user.login)
  18 +
  19 + @profile = user.person
  20 + @environment = @profile.environment
  21 + @environment.save!
  22 +
  23 + FriendsBlock.delete_all
  24 + @box1 = Box.create!(:owner => @profile)
  25 + @profile.boxes = [@box1]
  26 +
  27 + @block = FriendsBlock.new
  28 + @block.box = @box1
  29 + @block.save!
  30 +
  31 + @profile.blocks<<@block
  32 + @profile.save!
  33 +
  34 + get :index, :profile => @profile.identifier
  35 + assert_tag :div, :attributes => {:class => 'block friends-block'}
  36 + end
  37 +
  38 + should 'the people block is available for person profile' do
  39 + profile = mock
  40 + profile.stubs(:has_members?).returns(false)
  41 + profile.stubs(:person?).returns(true)
  42 + profile.stubs(:community?).returns(false)
  43 + profile.stubs(:enterprise?).returns(false)
  44 + profile.stubs(:has_blog?).returns(false)
  45 + profile.stubs(:is_admin?).with(anything).returns(false)
  46 + environment = mock
  47 + profile.stubs(:environment).returns(environment)
  48 + environment.stubs(:enabled?).returns(false)
  49 + @controller.stubs(:profile).returns(profile)
  50 + @controller.stubs(:user).returns(profile)
  51 + assert_includes @controller.available_blocks, FriendsBlock
  52 + end
  53 +
  54 + should 'the people block is available for community profile' do
  55 + profile = mock
  56 + profile.stubs(:has_members?).returns(true)
  57 + profile.stubs(:person?).returns(false)
  58 + profile.stubs(:community?).returns(true)
  59 + profile.stubs(:enterprise?).returns(false)
  60 + profile.stubs(:has_blog?).returns(false)
  61 + profile.stubs(:is_admin?).with(anything).returns(false)
  62 + environment = mock
  63 + profile.stubs(:environment).returns(environment)
  64 + environment.stubs(:enabled?).returns(false)
  65 + @controller.stubs(:profile).returns(profile)
  66 + @controller.stubs(:user).returns(profile)
  67 + assert_includes @controller.available_blocks, MembersBlock
  68 + end
  69 +
  70 +end
... ...
plugins/people_block/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
... ...
plugins/people_block/test/unit/friends_block_test.rb 0 → 100644
... ... @@ -0,0 +1,156 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class FriendsBlockTest < ActiveSupport::TestCase
  4 +
  5 + should 'inherit from Block' do
  6 + assert_kind_of Block, FriendsBlock.new
  7 + end
  8 +
  9 +
  10 + should 'declare its default title' do
  11 + assert_not_equal Block.new.default_title, FriendsBlock.new.default_title
  12 + end
  13 +
  14 +
  15 + should 'describe itself' do
  16 + assert_not_equal Block.description, FriendsBlock.description
  17 + end
  18 +
  19 +
  20 + should 'is editable' do
  21 + block = FriendsBlock.new
  22 + assert block.editable?
  23 + end
  24 +
  25 +
  26 + should 'have field limit' do
  27 + block = FriendsBlock.new
  28 + assert_respond_to block, :limit
  29 + end
  30 +
  31 +
  32 + should 'default value of limit' do
  33 + block = FriendsBlock.new
  34 + assert_equal 6, block.limit
  35 + end
  36 +
  37 +
  38 + should 'have field name' do
  39 + block = FriendsBlock.new
  40 + assert_respond_to block, :name
  41 + end
  42 +
  43 +
  44 + should 'default value of name' do
  45 + block = FriendsBlock.new
  46 + assert_equal "", block.name
  47 + end
  48 +
  49 +
  50 + should 'have field address' do
  51 + block = FriendsBlock.new
  52 + assert_respond_to block, :address
  53 + end
  54 +
  55 +
  56 + should 'default value of address' do
  57 + block = FriendsBlock.new
  58 + assert_equal "", block.address
  59 + end
  60 +
  61 +
  62 + should 'prioritize profiles with image by default' do
  63 + assert FriendsBlock.new.prioritize_people_with_image
  64 + end
  65 +
  66 +
  67 + should 'accept a limit of people to be displayed' do
  68 + block = FriendsBlock.new
  69 + block.limit = 20
  70 + assert_equal 20, block.limit
  71 + end
  72 +
  73 +
  74 + should 'list friends from person' do
  75 + owner = fast_create(Person)
  76 + friend1 = fast_create(Person)
  77 + friend2 = fast_create(Person)
  78 + owner.add_friend(friend1)
  79 + owner.add_friend(friend2)
  80 +
  81 + block = FriendsBlock.new
  82 +
  83 + block.expects(:owner).returns(owner).at_least_once
  84 + expects(:profile_image_link).with(friend1, :minor).returns(friend1.name)
  85 + expects(:profile_image_link).with(friend2, :minor).returns(friend2.name)
  86 + expects(:block_title).with(anything).returns('')
  87 +
  88 + content = instance_eval(&block.content)
  89 +
  90 + assert_match(/#{friend1.name}/, content)
  91 + assert_match(/#{friend2.name}/, content)
  92 + end
  93 +
  94 +
  95 + should 'link to "all friends"' do
  96 + person1 = create_user('mytestperson').person
  97 +
  98 + block = FriendsBlock.new
  99 + block.expects(:owner).returns(person1).at_least_once
  100 +
  101 + expects(:_).with('View all').returns('View all')
  102 + expects(:link_to).with('View all', :profile => 'mytestperson', :controller => 'profile', :action => 'friends').returns('link-to-friends')
  103 +
  104 + assert_equal 'link-to-friends', instance_eval(&block.footer)
  105 + end
  106 +
  107 +
  108 + should 'count number of owner friends' do
  109 + owner = fast_create(Person)
  110 + friend1 = fast_create(Person)
  111 + friend2 = fast_create(Person)
  112 + friend3 = fast_create(Person)
  113 + owner.add_friend(friend1)
  114 + owner.add_friend(friend2)
  115 + owner.add_friend(friend3)
  116 +
  117 + block = FriendsBlock.new
  118 + block.expects(:owner).returns(owner).at_least_once
  119 +
  120 + assert_equal 3, block.profile_count
  121 + end
  122 +
  123 +
  124 + should 'count number of public and private friends' do
  125 + owner = fast_create(Person)
  126 + private_p = fast_create(Person, {:public_profile => false})
  127 + public_p = fast_create(Person, {:public_profile => true})
  128 +
  129 + owner.add_friend(private_p)
  130 + owner.add_friend(public_p)
  131 +
  132 + block = FriendsBlock.new
  133 + block.expects(:owner).returns(owner).at_least_once
  134 +
  135 + assert_equal 2, block.profile_count
  136 + end
  137 +
  138 +
  139 + should 'not count number of invisible friends' do
  140 + owner = fast_create(Person)
  141 + private_p = fast_create(Person, {:visible => false})
  142 + public_p = fast_create(Person, {:visible => true})
  143 +
  144 + owner.add_friend(private_p)
  145 + owner.add_friend(public_p)
  146 +
  147 + block = FriendsBlock.new
  148 + block.expects(:owner).returns(owner).at_least_once
  149 +
  150 + assert_equal 1, block.profile_count
  151 + end
  152 +
  153 + protected
  154 + include NoosferoTestHelper
  155 +
  156 +end
... ...
plugins/people_block/test/unit/members_block_test.rb 0 → 100644
... ... @@ -0,0 +1,252 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class MembersBlockTest < ActiveSupport::TestCase
  4 +
  5 + should 'inherit from Block' do
  6 + assert_kind_of Block, MembersBlock.new
  7 + end
  8 +
  9 +
  10 + should 'declare its default title' do
  11 + assert_not_equal Block.new.default_title, MembersBlock.new.default_title
  12 + end
  13 +
  14 +
  15 + should 'describe itself' do
  16 + assert_not_equal Block.description, MembersBlock.description
  17 + end
  18 +
  19 +
  20 + should 'is editable' do
  21 + block = MembersBlock.new
  22 + assert block.editable?
  23 + end
  24 +
  25 +
  26 + should 'have field limit' do
  27 + block = MembersBlock.new
  28 + assert_respond_to block, :limit
  29 + end
  30 +
  31 +
  32 + should 'default value of limit' do
  33 + block = MembersBlock.new
  34 + assert_equal 6, block.limit
  35 + end
  36 +
  37 +
  38 + should 'have field name' do
  39 + block = MembersBlock.new
  40 + assert_respond_to block, :name
  41 + end
  42 +
  43 +
  44 + should 'default value of name' do
  45 + block = MembersBlock.new
  46 + assert_equal "", block.name
  47 + end
  48 +
  49 +
  50 + should 'have field address' do
  51 + block = MembersBlock.new
  52 + assert_respond_to block, :address
  53 + end
  54 +
  55 +
  56 + should 'default value of address' do
  57 + block = MembersBlock.new
  58 + assert_equal "", block.address
  59 + end
  60 +
  61 +
  62 + should 'prioritize profiles with image by default' do
  63 + assert MembersBlock.new.prioritize_people_with_image
  64 + end
  65 +
  66 +
  67 + should 'respect limit when listing members' do
  68 + community = fast_create(Community)
  69 + p1 = fast_create(Person)
  70 + p2 = fast_create(Person)
  71 + p3 = fast_create(Person)
  72 + p4 = fast_create(Person)
  73 +
  74 + community.add_member(p1)
  75 + community.add_member(p2)
  76 + community.add_member(p3)
  77 + community.add_member(p4)
  78 +
  79 + block = MembersBlock.new(:limit => 3)
  80 + block.stubs(:owner).returns(community)
  81 +
  82 + assert_equal 3, block.profile_list.size
  83 + end
  84 +
  85 +
  86 + should 'accept a limit of members to be displayed' do
  87 + block = MembersBlock.new
  88 + block.limit = 20
  89 + assert_equal 20, block.limit
  90 + end
  91 +
  92 +
  93 + should 'list members from community' do
  94 + owner = fast_create(Community)
  95 + person1 = fast_create(Person)
  96 + person2 = fast_create(Person)
  97 + owner.add_member(person1)
  98 + owner.add_member(person2)
  99 +
  100 + block = MembersBlock.new
  101 +
  102 + block.expects(:owner).returns(owner).at_least_once
  103 + expects(:profile_image_link).with(person1, :minor).returns(person1.name)
  104 + expects(:profile_image_link).with(person2, :minor).returns(person2.name)
  105 + expects(:block_title).with(anything).returns('')
  106 +
  107 + content = instance_eval(&block.content)
  108 +
  109 + assert_match(/#{person1.name}/, content)
  110 + assert_match(/#{person2.name}/, content)
  111 + end
  112 +
  113 + should 'count number of public and private members' do
  114 + owner = fast_create(Community)
  115 + private_p = fast_create(Person, {:public_profile => false})
  116 + public_p = fast_create(Person, {:public_profile => true})
  117 +
  118 + owner.add_member(private_p)
  119 + owner.add_member(public_p)
  120 +
  121 + block = MembersBlock.new
  122 + block.expects(:owner).returns(owner).at_least_once
  123 +
  124 + assert_equal 2, block.profile_count
  125 + end
  126 +
  127 +
  128 + should 'not count number of invisible members' do
  129 + owner = fast_create(Community)
  130 + private_p = fast_create(Person, {:visible => false})
  131 + public_p = fast_create(Person, {:visible => true})
  132 +
  133 + owner.add_member(private_p)
  134 + owner.add_member(public_p)
  135 +
  136 + block = MembersBlock.new
  137 + block.expects(:owner).returns(owner).at_least_once
  138 +
  139 + assert_equal 1, block.profile_count
  140 + end
  141 +
  142 + should 'provide link to members page without a visible_role selected' do
  143 + profile = create_user('mytestuser').person
  144 + block = MembersBlock.new
  145 + block.box = profile.boxes.first
  146 + block.save!
  147 +
  148 + expects(:_).with('View all').returns('View all')
  149 + expects(:link_to).with('View all' , :profile => 'mytestuser', :controller => 'people_block_plugin_profile', :action => 'members', :role_key => block.visible_role).returns('link-to-members')
  150 +
  151 + assert_equal 'link-to-members', instance_eval(&block.footer)
  152 + end
  153 +
  154 + should 'provide link to members page with a selected role' do
  155 + profile = create_user('mytestuser').person
  156 + block = MembersBlock.new
  157 + block.box = profile.boxes.first
  158 + block.visible_role = 'profile_member'
  159 + block.save!
  160 +
  161 + expects(:_).with('View all').returns('View all')
  162 + expects(:link_to).with('View all' , :profile => 'mytestuser', :controller => 'people_block_plugin_profile', :action => 'members', :role_key => block.visible_role).returns('link-to-members')
  163 +
  164 + assert_equal 'link-to-members', instance_eval(&block.footer)
  165 + end
  166 +
  167 + should 'provide a role to be displayed (and default to nil)' do
  168 + env = fast_create(Environment)
  169 + env.boxes << Box.new
  170 + block = MembersBlock.new
  171 + assert_equal nil, block.visible_role
  172 + env.boxes.first.blocks << block
  173 + block.visible_role = 'profile_member'
  174 + block.save!
  175 + assert_equal 'profile_member', block.visible_role
  176 + end
  177 +
  178 + should 'list all members' do
  179 + env = fast_create(Environment)
  180 + env.boxes << Box.new
  181 + profile1 = fast_create(Person, :environment_id => env.id)
  182 + profile2 = fast_create(Person, :environment_id => env.id)
  183 +
  184 + block = MembersBlock.new
  185 + owner = fast_create(Community)
  186 + block.stubs(:owner).returns(owner)
  187 + env.boxes.first.blocks << block
  188 + block.save!
  189 +
  190 + owner.add_member profile1
  191 + owner.add_member profile2
  192 + profiles = block.profiles
  193 +
  194 + assert_includes profiles, profile1
  195 + assert_includes profiles, profile2
  196 + end
  197 +
  198 + should 'list only profiles with moderator role' do
  199 + env = fast_create(Environment)
  200 + env.boxes << Box.new
  201 + profile1 = fast_create(Person, :environment_id => env.id)
  202 + profile2 = fast_create(Person, :environment_id => env.id)
  203 +
  204 + block = MembersBlock.new
  205 + owner = fast_create(Community)
  206 + block.visible_role = Profile::Roles.moderator(owner.environment.id).key
  207 + block.stubs(:owner).returns(owner)
  208 + env.boxes.first.blocks << block
  209 + block.save!
  210 +
  211 + owner.add_member profile2
  212 + owner.add_moderator profile1
  213 + profiles = block.profiles
  214 +
  215 + assert_includes profiles, profile1
  216 + assert_not_includes profiles, profile2
  217 + end
  218 +
  219 + should 'list only profiles with member role' do
  220 + env = fast_create(Environment)
  221 + env.boxes << Box.new
  222 + profile1 = fast_create(Person, :environment_id => env.id)
  223 + profile2 = fast_create(Person, :environment_id => env.id)
  224 +
  225 + block = MembersBlock.new
  226 + owner = fast_create(Community)
  227 + block.visible_role = Profile::Roles.member(owner.environment.id).key
  228 + block.stubs(:owner).returns(owner)
  229 + env.boxes.first.blocks << block
  230 + block.save!
  231 +
  232 + owner.add_member profile2
  233 + owner.add_moderator profile1
  234 + profiles = block.profiles
  235 +
  236 + assert_not_includes profiles, profile1
  237 + assert_includes profiles, profile2
  238 + end
  239 +
  240 + should 'list available roles' do
  241 + block = MembersBlock.new
  242 + owner = fast_create(Community)
  243 + block.stubs(:owner).returns(owner)
  244 + assert_includes block.roles, Profile::Roles.member(owner.environment.id)
  245 + assert_includes block.roles, Profile::Roles.admin(owner.environment.id)
  246 + assert_includes block.roles, Profile::Roles.moderator(owner.environment.id)
  247 + end
  248 +
  249 + protected
  250 + include NoosferoTestHelper
  251 +
  252 +end
... ...
plugins/people_block/test/unit/people_block_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class PeopleBlockPluginTest < ActiveSupport::TestCase
  4 +
  5 + should "return PeopleBlock in extra_blocks class method" do
  6 + assert PeopleBlockPlugin.extra_blocks.keys.include?(PeopleBlock)
  7 + end
  8 +
  9 + should "return MembersBlock in extra_blocks class method" do
  10 + assert PeopleBlockPlugin.extra_blocks.keys.include?(MembersBlock)
  11 + end
  12 +
  13 + should "return FriendsBlock in extra_blocks class method" do
  14 + assert PeopleBlockPlugin.extra_blocks.keys.include?(FriendsBlock)
  15 + end
  16 +
  17 + should "return false for class method has_admin_url?" do
  18 + assert !PeopleBlockPlugin.has_admin_url?
  19 + end
  20 +
  21 + should "return false for class method stylesheet?" do
  22 + assert PeopleBlockPlugin.new.stylesheet?
  23 + end
  24 +
  25 +end
... ...
plugins/people_block/test/unit/people_block_test.rb 0 → 100644
... ... @@ -0,0 +1,146 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class PeopleBlockTest < ActiveSupport::TestCase
  4 +
  5 + should 'inherit from Block' do
  6 + assert_kind_of Block, PeopleBlock.new
  7 + end
  8 +
  9 +
  10 + should 'declare its default title' do
  11 + assert_not_equal Block.new.default_title, PeopleBlock.new.default_title
  12 + end
  13 +
  14 +
  15 + should 'describe itself' do
  16 + assert_not_equal Block.description, PeopleBlock.description
  17 + end
  18 +
  19 +
  20 + should 'is editable' do
  21 + block = PeopleBlock.new
  22 + assert block.editable?
  23 + end
  24 +
  25 +
  26 + should 'have field limit' do
  27 + block = PeopleBlock.new
  28 + assert_respond_to block, :limit
  29 + end
  30 +
  31 +
  32 + should 'default value of limit' do
  33 + block = PeopleBlock.new
  34 + assert_equal 6, block.limit
  35 + end
  36 +
  37 +
  38 + should 'have field name' do
  39 + block = PeopleBlock.new
  40 + assert_respond_to block, :name
  41 + end
  42 +
  43 +
  44 + should 'default value of name' do
  45 + block = PeopleBlock.new
  46 + assert_equal "", block.name
  47 + end
  48 +
  49 +
  50 + should 'have field address' do
  51 + block = PeopleBlock.new
  52 + assert_respond_to block, :address
  53 + end
  54 +
  55 +
  56 + should 'default value of address' do
  57 + block = PeopleBlock.new
  58 + assert_equal "", block.address
  59 + end
  60 +
  61 +
  62 + should 'prioritize profiles with image by default' do
  63 + assert PeopleBlock.new.prioritize_profiles_with_image
  64 + end
  65 +
  66 +
  67 + should 'respect limit when listing people' do
  68 + env = fast_create(Environment)
  69 + p1 = fast_create(Person, :environment_id => env.id)
  70 + p2 = fast_create(Person, :environment_id => env.id)
  71 + p3 = fast_create(Person, :environment_id => env.id)
  72 + p4 = fast_create(Person, :environment_id => env.id)
  73 +
  74 + block = PeopleBlock.new(:limit => 3)
  75 + block.stubs(:owner).returns(env)
  76 +
  77 + assert_equal 3, block.profile_list.size
  78 + end
  79 +
  80 +
  81 + should 'accept a limit of people to be displayed' do
  82 + block = PeopleBlock.new
  83 + block.limit = 20
  84 + assert_equal 20, block.limit
  85 + end
  86 +
  87 +
  88 + should 'list people from environment' do
  89 + owner = fast_create(Environment)
  90 + person1 = fast_create(Person, :environment_id => owner.id)
  91 + person2 = fast_create(Person, :environment_id => owner.id)
  92 +
  93 + block = PeopleBlock.new
  94 +
  95 + block.expects(:owner).returns(owner).at_least_once
  96 + expects(:profile_image_link).with(person1, :minor).returns(person1.name)
  97 + expects(:profile_image_link).with(person2, :minor).returns(person2.name)
  98 + expects(:block_title).with(anything).returns('')
  99 +
  100 + content = instance_exec(&block.content)
  101 +
  102 + assert_match(/#{person1.name}/, content)
  103 + assert_match(/#{person2.name}/, content)
  104 + end
  105 +
  106 +
  107 + should 'link to "all people"' do
  108 + env = fast_create(Environment)
  109 +
  110 + block = PeopleBlock.new
  111 +
  112 + stubs(:_).with('View all').returns('View all')
  113 + stubs(:link_to).returns('link-to-people')
  114 + stubs(:url_for).returns(' ')
  115 +
  116 + assert_equal 'link-to-people', instance_exec(&block.footer)
  117 + end
  118 +
  119 +
  120 + should 'count number of public and private people' do
  121 + owner = fast_create(Environment)
  122 + private_p = fast_create(Person, :public_profile => false, :environment_id => owner.id)
  123 + public_p = fast_create(Person, :public_profile => true, :environment_id => owner.id)
  124 +
  125 + block = PeopleBlock.new
  126 + block.expects(:owner).returns(owner).at_least_once
  127 +
  128 + assert_equal 2, block.profile_count
  129 + end
  130 +
  131 +
  132 + should 'not count number of invisible people' do
  133 + owner = fast_create(Environment)
  134 + private_p = fast_create(Person, :visible => false, :environment_id => owner.id)
  135 + public_p = fast_create(Person, :visible => true, :environment_id => owner.id)
  136 +
  137 + block = PeopleBlock.new
  138 + block.expects(:owner).returns(owner).at_least_once
  139 +
  140 + assert_equal 1, block.profile_count
  141 + end
  142 +
  143 + protected
  144 + include NoosferoTestHelper
  145 +
  146 +end
... ...
plugins/people_block/views/blocks/friends.html.erb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= link_to s_('friends|View all'), {:profile => profile.identifier, :controller => 'profile', :action => 'friends'}, :class => 'view-all' %>
... ...
plugins/people_block/views/blocks/members.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%= link_to _('View all'), {:profile => profile.identifier, :controller => 'people_block_plugin_profile', :action => 'members', :role_key => role_key}, :class => 'view-all' %>
  2 +
  3 +<% if show_join_leave_button %>
  4 + <%= render :partial => 'blocks/profile_info_actions/join_leave_community' %>
  5 +<% end %>
... ...
plugins/people_block/views/blocks/people.html.erb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= link_to _('View all'), {:controller => 'search', :action => 'people'}, :class => 'view-all' %>
... ...
plugins/people_block/views/box_organizer/_people_block_base.html.erb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<%= labelled_form_field _('Name:'), text_field(:block, :name) %>
  2 +
  3 +<%= labelled_form_field _('Address:'), text_field(:block, :address) %>
  4 +
  5 +<% if @block.kind_of?(MembersBlock) %>
  6 + <%= labelled_form_field _('Filter by role:'), '' %>
  7 + <%= select_tag 'block[visible_role]', options_for_select(@block.roles.map{|r| [r.name, r.key]}.insert(0,''), @block.visible_role) %>
  8 +<% end %>
  9 +
  10 +<%= render :partial => 'profile_list_block' %>
... ...
plugins/people_block/views/environment_design 0 → 120000
... ... @@ -0,0 +1 @@
  1 +box_organizer
0 2 \ No newline at end of file
... ...
plugins/people_block/views/profile_design 0 → 120000
... ... @@ -0,0 +1 @@
  1 +box_organizer
0 2 \ No newline at end of file
... ...
plugins/piwik/controllers/piwik_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class PiwikPluginAdminController < AdminController
  2 +
  3 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  4 +
  5 + def index
  6 + if request.post?
  7 + if @environment.update_attributes(params[:environment])
  8 + session[:notice] = _('Piwik plugin settings updated successfully.')
  9 + else
  10 + session[:notice] = _('Piwik plugin settings could not be saved.')
  11 + end
  12 + redirect_to :controller => 'plugins', :action => 'index'
  13 + end
  14 + end
  15 +
  16 +end
... ...
plugins/piwik/lib/ext/environment.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 + settings_items :piwik_domain
  5 + settings_items :piwik_site_id
  6 + attr_accessible :piwik_domain, :piwik_site_id
  7 +end
... ...
plugins/piwik/lib/piwik_plugin.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +class PiwikPlugin < Noosfero::Plugin
  2 +
  3 + include ActionView::Helpers::JavaScriptHelper
  4 + include ActionView::Helpers::FormHelper
  5 + include ActionView::Helpers::UrlHelper
  6 + include ActionView::Helpers::TagHelper
  7 +
  8 + def self.plugin_name
  9 + "Piwik"
  10 + end
  11 +
  12 + def self.plugin_description
  13 + _("Tracking and web analytics to your Noosfero's environment")
  14 + end
  15 +
  16 + def body_ending
  17 + domain = context.environment.piwik_domain
  18 + site_id = context.environment.piwik_site_id
  19 + unless domain.blank? || site_id.blank?
  20 + expanded_template('tracking-code.rhtml',{:domain => domain, :site_id => site_id})
  21 + end
  22 + end
  23 +
  24 +end
... ...
plugins/piwik/test/functional/piwik_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/piwik_plugin_admin_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class PiwikPluginAdminController; def rescue_action(e) raise e end; end
  6 +
  7 +class PiwikPluginAdminControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @environment = Environment.default
  11 + user_login = create_admin_user(@environment)
  12 + login_as(user_login)
  13 + @environment.enabled_plugins = ['PiwikPlugin']
  14 + @environment.save!
  15 + end
  16 +
  17 + should 'access index action' do
  18 + get :index
  19 + assert_template 'index'
  20 + assert_response :success
  21 + end
  22 +
  23 + should 'update piwik plugin settings' do
  24 + assert_nil @environment.reload.piwik_domain
  25 + assert_nil @environment.reload.piwik_site_id
  26 + post :index, :environment => { :piwik_domain => 'http://something', :piwik_site_id => 10 }
  27 + assert_not_nil @environment.reload.piwik_domain
  28 + assert_not_nil @environment.reload.piwik_site_id
  29 + end
  30 +
  31 +end
... ...
plugins/piwik/test/unit/piwik_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class PiwikPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = PiwikPlugin.new
  7 + @context = mock()
  8 + @plugin.context = @context
  9 + @environment = Environment.new
  10 + @context.stubs(:environment).returns(@environment)
  11 + end
  12 +
  13 + should 'add content at the body ending unless domain and site_id are blank' do
  14 + @environment.piwik_domain = 'piwik.domain.example.com'
  15 + @environment.piwik_site_id = 5
  16 + @plugin.stubs(:expanded_template).returns('content')
  17 + assert_equal 'content', @plugin.body_ending
  18 + end
  19 +
  20 + should 'not add any content at the body ending if domain is blank' do
  21 + @environment.piwik_domain = nil
  22 + @environment.piwik_site_id = 5
  23 + @plugin.stubs(:expanded_template).returns('content')
  24 + assert_equal nil, @plugin.body_ending
  25 + end
  26 +
  27 + should 'not add any content at the body ending if site_id is blank' do
  28 + @environment.piwik_domain = 'piwik.domain.example.com'
  29 + @environment.piwik_site_id = nil
  30 + @plugin.stubs(:expanded_template).returns('content')
  31 + assert_equal nil, @plugin.body_ending
  32 + end
  33 +
  34 + should 'extends Environment with attr piwik_domain' do
  35 + assert_respond_to Environment.new, :piwik_domain
  36 + end
  37 +
  38 + should 'extends Environment with attr piwik_site_id' do
  39 + assert_respond_to Environment.new, :piwik_site_id
  40 + end
  41 +
  42 +end
... ...
plugins/piwik/views/piwik_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<h1><%= _("Piwik plugin settings") %></h1>
  2 +
  3 +<%= form_for(:environment) do |f| %>
  4 +
  5 + <%= labelled_form_field _('Piwik domain'), f.text_field(:piwik_domain) %>
  6 +
  7 + <%= labelled_form_field _('Piwik site id'), f.text_field(:piwik_site_id) %>
  8 +
  9 + <% button_bar do %>
  10 + <%= submit_button(:save, _('Save'), :cancel => {:controller => 'plugins', :action => 'index'}) %>
  11 + <% end %>
  12 +
  13 +<% end %>
... ...
plugins/piwik/views/tracking-code.rhtml 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +<!-- Piwik -->
  2 +<script type="text/javascript">
  3 + var _paq = _paq || [];
  4 + _paq.push(['trackPageView']);
  5 + _paq.push(['enableLinkTracking']);
  6 + (function() {
  7 + var u=(("https:" == document.location.protocol) ? "https" : "http") + "://<%= escape_javascript locals[:domain] %>/piwik/";
  8 + _paq.push(['setTrackerUrl', u+'piwik.php']);
  9 + _paq.push(['setSiteId', <%= escape_javascript locals[:site_id] %>]);
  10 + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
  11 + g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
  12 + })();
  13 +</script>
  14 +<noscript><p><img src="http://<%= escape_javascript locals[:domain] %>/piwik/piwik.php?idsite=<%= escape_javascript locals[:site_id] %>" style="border:0;" alt="" /></p></noscript>
  15 +<!-- End Piwik Code -->
... ...
plugins/video/lib/video_block.rb
... ... @@ -6,8 +6,10 @@ class VideoBlock &lt; Block
6 6 settings_items :width, :type => :integer, :default => 400
7 7 settings_items :height, :type => :integer, :default => 315
8 8  
  9 + YOUTUBE_ID_FORMAT = '\w-'
  10 +
9 11 def is_youtube?
10   - url.match(/.*(youtube.com.*v=[[:alnum:]]+|youtu.be\/[[:alnum:]]+).*/) ? true : false
  12 + url.match(/.*(youtube.com.*v=[#{YOUTUBE_ID_FORMAT}]+|youtu.be\/[#{YOUTUBE_ID_FORMAT}]+).*/) ? true : false
11 13 end
12 14  
13 15 def is_vimeo?
... ... @@ -46,8 +48,8 @@ class VideoBlock &lt; Block
46 48  
47 49 def extract_youtube_id
48 50 return nil unless is_youtube?
49   - youtube_match = url.match('v=([[:alnum:]]*)')
50   - youtube_match ||= url.match('youtu.be\/([[:alnum:]]*)')
  51 + youtube_match = url.match("v=([#{YOUTUBE_ID_FORMAT}]*)")
  52 + youtube_match ||= url.match("youtu.be\/([#{YOUTUBE_ID_FORMAT}]*)")
51 53 youtube_match[1] unless youtube_match.nil?
52 54 end
53 55  
... ...
plugins/video/test/unit/video_block_test.rb
... ... @@ -70,6 +70,13 @@ class VideoBlockTest &lt; ActiveSupport::TestCase
70 70 assert_equal id, block.send('extract_youtube_id')
71 71 end
72 72  
  73 + should "extract youtube id from youtube video url's if it has underline and hyphen" do
  74 + block = VideoBlock.new
  75 + id = 'oi43_re-d2'
  76 + block.url = "youtube.com/?v=#{id}"
  77 + assert_equal id, block.send('extract_youtube_id')
  78 + end
  79 +
73 80 should "extract youtube id from youtube video url's if it's a valid youtube short url" do
74 81 block = VideoBlock.new
75 82 id = 'oi43jre2d2'
... ...
public/designs/themes/base/style.css
... ... @@ -478,12 +478,9 @@ div#notice {
478 478  
479 479 /************************** Profile List *****************************/
480 480  
481   -#content .people-block ul,
482 481 #content .profile-list-block ul,
483 482 #content .enterprises-block ul,
484   -#content .members-block ul,
485 483 #content .communities-block ul,
486   -#content .friends-block ul,
487 484 #content .fans-block ul {
488 485 min-width: 196px;
489 486 width: 192px;
... ... @@ -491,24 +488,18 @@ div#notice {
491 488 padding: 0px;
492 489 }
493 490  
494   -#content .box-1 .people-block ul,
495 491 #content .box-1 .profile-list-block ul,
496 492 #content .box-1 .enterprises-block ul,
497   -#content .box-1 .members-block ul,
498 493 #content .box-1 .communities-block ul,
499   -#content .box-1 .friends-block ul,
500 494 #content .box-1 .fans-block ul {
501 495 width: auto;
502 496 display: block;
503 497 }
504 498  
505 499 #content .tags-block .block-footer-content a,
506   -#content .people-block .block-footer-content a,
507 500 #content .profile-list-block .block-footer-content a,
508 501 #content .enterprises-block .block-footer-content a,
509   -#content .members-block .block-footer-content a,
510   -#content .communities-block .block-footer-content a,
511   -#content .friends-block .block-footer-content a {
  502 +#content .communities-block .block-footer-content a {
512 503 position: absolute;
513 504 top: 2px;
514 505 right: 0px;
... ... @@ -518,29 +509,12 @@ div#notice {
518 509 padding-right: 15px;
519 510 }
520 511 #content .tags-block .block-footer-content a,
521   -#content .people-block .block-footer-content a,
522 512 #content .profile-list-block .block-footer-content a,
523 513 #content .enterprises-block .block-footer-content a,
524   -#content .communities-block .block-footer-content a,
525   -#content .friends-block .block-footer-content a {
  514 +#content .communities-block .block-footer-content a {
526 515 background: url(imgs/arrow-right-p.png) 100% 50% no-repeat;
527 516 }
528 517  
529   -#content .members-block .block-footer-content .join-leave-button a {
530   - position: relative;
531   - background-color: #EEE;
532   - border: 1px solid #CCC;
533   - color: #555;
534   - padding-right: inherit;
535   -}
536   -
537   -#content .members-block .block-footer-content .join-leave-button a:hover {
538   - color: #FFF;
539   - background-color: #555;
540   - border: 1px solid #2e3436;
541   - text-decoration: none;
542   -}
543   -
544 518 #content .profile-list-block .block-title {
545 519 text-align: left;
546 520 }
... ...
public/plugins/people_block 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../../plugins/people_block/public
0 2 \ No newline at end of file
... ...
script/noosfero-plugins
... ... @@ -76,7 +76,8 @@ run(){
76 76  
77 77 _enable(){
78 78 plugin="$1"
79   - source="$available_plugins_dir/$plugin"
  79 + cd $enabled_plugins_dir
  80 + source="../../plugins/$plugin"
80 81 target="$enabled_plugins_dir/$plugin"
81 82 run "$source/before_enable.rb"
82 83 if [ -h "$target" ]; then
... ... @@ -98,11 +99,13 @@ _enable(){
98 99 fi
99 100 fi
100 101 if [ "$installation_ok" = true ] && [ "$dependencies_ok" = true ]; then
101   - ln -s "$source" "$target"
  102 + ln -s "$source" "$plugin"
102 103 plugins_public_dir="$NOOSFERO_DIR/public/plugins"
103 104 plugins_features_dir="$NOOSFERO_DIR/features/plugins"
104   - test -d "$target/public/" && ln -s "$target/public" "$plugins_public_dir/$plugin"
105   - test -d "$NOOSFERO_DIR/features" && test -d "$target/features" && ln -s "$target/features" "$plugins_features_dir/$plugin"
  105 + cd $plugins_public_dir
  106 + test -d "$source/public" && ln -s "$source/public" "$plugin"
  107 + cd $plugins_features_dir
  108 + test -d "$NOOSFERO_DIR/features" && test -d "$source/features" && ln -s "$source/features" "$plugin"
106 109 _say "$plugin enabled"
107 110 run "$source/after_enable.rb"
108 111 needs_migrate=true
... ... @@ -122,15 +125,19 @@ _disable(){
122 125 target="$enabled_plugins_dir/$plugin"
123 126 plugins_public_dir="$NOOSFERO_DIR/public/plugins"
124 127 plugins_features_dir="$NOOSFERO_DIR/features/plugins"
125   - run "$source/before_disable.rb"
126   - if [ -h "$target" ]; then
127   - rm "$target"
128   - test -h "$plugins_public_dir/$plugin" && rm "$plugins_public_dir/$plugin"
129   - test -h "$plugins_features_dir/$plugin" && rm "$plugins_features_dir/$plugin"
130   - _say "$plugin disabled"
131   - run "$source/after_disable.rb"
  128 + if ! run "$source/before_disable.rb"; then
  129 + echo "W: failed to disabling $plugin"
  130 + echo
132 131 else
133   - _say "$plugin already disabled"
  132 + if [ -h "$target" ]; then
  133 + rm "$target"
  134 + test -h "$plugins_public_dir/$plugin" && rm "$plugins_public_dir/$plugin"
  135 + test -h "$plugins_features_dir/$plugin" && rm "$plugins_features_dir/$plugin"
  136 + _say "$plugin disabled"
  137 + run "$source/after_disable.rb"
  138 + else
  139 + _say "$plugin already disabled"
  140 + fi
134 141 fi
135 142 }
136 143  
... ...
test/functional/cms_controller_test.rb
... ... @@ -1228,7 +1228,7 @@ class CmsControllerTest &lt; ActionController::TestCase
1228 1228 should 'allow user edit article if he is owner and has publish permission' do
1229 1229 c = Community.create!(:name => 'test_comm', :identifier => 'test_comm')
1230 1230 u = create_user_with_permission('test_user', 'publish_content', c)
1231   - a = create(Article, :profile => c, :name => 'test_article', :last_changed_by => u)
  1231 + a = create(Article, :profile => c, :name => 'test_article', :created_by => u)
1232 1232 login_as :test_user
1233 1233 @controller.stubs(:user).returns(u)
1234 1234  
... ... @@ -1774,6 +1774,31 @@ class CmsControllerTest &lt; ActionController::TestCase
1774 1774 assert_equal 'first version', Article.find(article.id).name
1775 1775 end
1776 1776  
  1777 + should 'set created_by when creating article' do
  1778 + login_as(profile.identifier)
  1779 +
  1780 + post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :article => { :name => 'changed by me', :body => 'content ...' }
  1781 +
  1782 + a = profile.articles.find_by_path('changed-by-me')
  1783 + assert_not_nil a
  1784 + assert_equal profile, a.created_by
  1785 + end
  1786 +
  1787 + should 'not change created_by when updating article' do
  1788 + other_person = create_user('otherperson').person
  1789 +
  1790 + a = profile.articles.build(:name => 'my article')
  1791 + a.created_by = other_person
  1792 + a.save!
  1793 +
  1794 + login_as(profile.identifier)
  1795 + post :edit, :profile => profile.identifier, :id => a.id, :article => { :body => 'new content for this article' }
  1796 +
  1797 + a.reload
  1798 +
  1799 + assert_equal other_person, a.created_by
  1800 + end
  1801 +
1777 1802 protected
1778 1803  
1779 1804 # FIXME this is to avoid adding an extra dependency for a proper JSON parser.
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -743,7 +743,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
743 743 c = Community.create!(:name => 'test_com')
744 744 u = create_user_with_permission('test_user', 'publish_content', c)
745 745 login_as u.identifier
746   - a = create(Article, :profile => c, :name => 'test-article', :last_changed_by => u, :published => false)
  746 + a = create(Article, :profile => c, :name => 'test-article', :created_by => u, :published => false)
747 747  
748 748 get :view_page, :profile => c.identifier, :page => a.path
749 749  
... ...
test/functional/environment_design_controller_test.rb
... ... @@ -8,7 +8,7 @@ class EnvironmentDesignControllerTest &lt; ActionController::TestCase
8 8  
9 9 # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
10 10 # the Noosfero core soon, see ActionItem3045
11   - ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
  11 + ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
12 12  
13 13 def setup
14 14 @controller = EnvironmentDesignController.new
... ... @@ -107,16 +107,6 @@ class EnvironmentDesignControllerTest &lt; ActionController::TestCase
107 107 assert_tag :tag => 'input', :attributes => { :id => 'block_limit' }
108 108 end
109 109  
110   - should 'be able to edit PeopleBlock' do
111   - login_as(create_admin_user(Environment.default))
112   - b = PeopleBlock.create!
113   - e = Environment.default
114   - e.boxes.create!
115   - e.boxes.first.blocks << b
116   - get :edit, :id => b.id
117   - assert_tag :tag => 'input', :attributes => { :id => 'block_limit' }
118   - end
119   -
120 110 should 'be able to edit SlideshowBlock' do
121 111 login_as(create_admin_user(Environment.default))
122 112 b = SlideshowBlock.create!
... ...
test/functional/profile_design_controller_test.rb
... ... @@ -6,8 +6,7 @@ class ProfileDesignController; def rescue_action(e) raise e end; end
6 6 class ProfileDesignControllerTest < ActionController::TestCase
7 7  
8 8 COMMOM_BLOCKS = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
9   - PERSON_BLOCKS = COMMOM_BLOCKS + [FriendsBlock, FavoriteEnterprisesBlock, CommunitiesBlock, EnterprisesBlock ]
10   - PERSON_BLOCKS_WITH_MEMBERS = PERSON_BLOCKS + [MembersBlock]
  9 + PERSON_BLOCKS = COMMOM_BLOCKS + [ FavoriteEnterprisesBlock, CommunitiesBlock, EnterprisesBlock ]
11 10 PERSON_BLOCKS_WITH_BLOG = PERSON_BLOCKS + [BlogArchivesBlock]
12 11  
13 12 ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, FeaturedProductsBlock, FansBlock, ProductCategoriesBlock]
... ... @@ -525,23 +524,6 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
525 524 assert_equal PERSON_BLOCKS, @controller.available_blocks
526 525 end
527 526  
528   - should 'the person with members blocks are all available' do
529   - profile = mock
530   - profile.stubs(:has_members?).returns(true)
531   - profile.stubs(:person?).returns(true)
532   - profile.stubs(:community?).returns(true)
533   - profile.stubs(:enterprise?).returns(false)
534   - profile.stubs(:has_blog?).returns(false)
535   - profile.stubs(:is_admin?).with(anything).returns(false)
536   - environment = mock
537   - profile.stubs(:environment).returns(environment)
538   - environment.stubs(:enabled?).returns(false)
539   - @controller.stubs(:profile).returns(profile)
540   - @controller.stubs(:user).returns(profile)
541   - Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([])
542   - assert_equal [], @controller.available_blocks - PERSON_BLOCKS_WITH_MEMBERS
543   - end
544   -
545 527 should 'the person with blog blocks are all available' do
546 528 profile = mock
547 529 profile.stubs(:has_members?).returns(false)
... ...
test/unit/article_test.rb
... ... @@ -154,7 +154,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
154 154 assert a4.errors[:slug.to_s].present?
155 155 end
156 156  
157   - should 'record who did the last change' do
  157 + should 'last_changed_by be a person' do
158 158 a = profile.articles.build(:name => 'test')
159 159  
160 160 # must be a person
... ... @@ -167,6 +167,19 @@ class ArticleTest &lt; ActiveSupport::TestCase
167 167 end
168 168 end
169 169  
  170 + should 'created_by be a person' do
  171 + a = profile.articles.build(:name => 'test')
  172 +
  173 + # must be a person
  174 + assert_raise ActiveRecord::AssociationTypeMismatch do
  175 + a.created_by = Profile.new
  176 + end
  177 + assert_nothing_raised do
  178 + a.created_by = Person.new
  179 + a.save!
  180 + end
  181 + end
  182 +
170 183 should 'not show private documents as recent' do
171 184 p = create_user('usr1').person
172 185 Article.destroy_all
... ... @@ -802,7 +815,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
802 815 should 'allow author to edit if is publisher' do
803 816 c = fast_create(Community)
804 817 p = create_user_with_permission('test_user', 'publish_content', c)
805   - a = create(Article, :name => 'a test article', :last_changed_by => p, :profile_id => c.id)
  818 + a = create(Article, :name => 'a test article', :created_by => p, :profile_id => c.id)
806 819  
807 820 assert a.allow_post_content?(p)
808 821 end
... ... @@ -1380,17 +1393,17 @@ class ArticleTest &lt; ActiveSupport::TestCase
1380 1393  
1381 1394 should "the author_name returns the name of the article's author" do
1382 1395 author = fast_create(Person)
1383   - a = create(Article, :name => 'a test article', :last_changed_by => author, :profile_id => profile.id)
  1396 + a = create(Article, :name => 'a test article', :created_by => author, :profile_id => profile.id)
1384 1397 assert_equal author.name, a.author_name
1385 1398 author.destroy
1386   - a.reload
  1399 + a = Article.find(a.id)
1387 1400 a.author_name = 'some name'
1388 1401 assert_equal 'some name', a.author_name
1389 1402 end
1390 1403  
1391 1404 should 'retrieve latest info from topic when has no comments' do
1392 1405 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
1393   - post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now, :last_changed_by_id => profile.id)
  1406 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now, :last_changed_by_id => profile.id, :created_by_id => profile.id)
1394 1407 assert_equal post.updated_at, post.info_from_last_update[:date]
1395 1408 assert_equal profile.name, post.info_from_last_update[:author_name]
1396 1409 assert_equal profile.url, post.info_from_last_update[:author_url]
... ... @@ -1744,30 +1757,30 @@ class ArticleTest &lt; ActiveSupport::TestCase
1744 1757  
1745 1758 should 'set author_name before creating article if there is an author' do
1746 1759 author = fast_create(Person)
1747   - article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => author)
  1760 + article = create(Article, :name => 'Test', :profile => profile, :created_by => author)
1748 1761 assert_equal author.name, article.author_name
1749 1762  
1750 1763 author_name = author.name
1751 1764 author.destroy
1752   - article.reload
  1765 + article = Article.find(article.id)
1753 1766 assert_equal author_name, article.author_name
1754 1767 end
1755 1768  
1756 1769 should "author_id return the author id of the article's author" do
1757 1770 author = fast_create(Person)
1758   - article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => author)
  1771 + article = create(Article, :name => 'Test', :profile => profile, :created_by => author)
1759 1772 assert_equal author.id, article.author_id
1760 1773 end
1761 1774  
1762 1775 should "author_id return nil if there is no article's author" do
1763   - article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil)
  1776 + article = create(Article, :name => 'Test', :profile => profile, :created_by => nil)
1764 1777 assert_nil article.author_id
1765 1778 end
1766 1779  
1767 1780 should "return the author of a specific version" do
1768 1781 author1 = fast_create(Person)
1769 1782 author2 = fast_create(Person)
1770   - article = create(Article, :name => 'first version', :profile => profile, :last_changed_by => author1)
  1783 + article = create(Article, :name => 'first version', :profile => profile, :created_by => author1, :last_changed_by => author1)
1771 1784 article.name = 'second version'
1772 1785 article.last_changed_by = author2
1773 1786 article.save
... ... @@ -1778,7 +1791,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1778 1791 should "return the author_name of a specific version" do
1779 1792 author1 = fast_create(Person)
1780 1793 author2 = fast_create(Person)
1781   - article = create(Article, :name => 'first version', :profile => profile, :last_changed_by => author1)
  1794 + article = create(Article, :name => 'first version', :profile => profile, :created_by => author1)
1782 1795 article.name = 'second version'
1783 1796 article.last_changed_by = author2
1784 1797 article.save
... ... @@ -1828,4 +1841,12 @@ class ArticleTest &lt; ActiveSupport::TestCase
1828 1841 assert_equivalent [c3], Article.with_types(['Event'])
1829 1842 end
1830 1843  
  1844 + should 'not create version when receive a comment' do
  1845 + a = Article.new(:name => 'my article', :body => 'my text')
  1846 + a.profile = profile
  1847 + a.save!
  1848 + Comment.create!(:title => 'test', :body => 'asdsad', :author => profile, :source => a)
  1849 + assert_equal 1, a.versions.count
  1850 + end
  1851 +
1831 1852 end
... ...
test/unit/box_test.rb
... ... @@ -39,14 +39,11 @@ class BoxTest &lt; ActiveSupport::TestCase
39 39 assert blocks.include?('fans-block')
40 40 assert blocks.include?('favorite-enterprises-block')
41 41 assert blocks.include?('feed-reader-block')
42   - assert blocks.include?('friends-block')
43 42 assert blocks.include?('highlights-block')
44 43 assert blocks.include?('link-list-block')
45 44 assert blocks.include?('login-block')
46 45 assert blocks.include?('main-block')
47   - assert blocks.include?('members-block')
48 46 assert blocks.include?('my-network-block')
49   - assert blocks.include?('people-block')
50 47 assert blocks.include?('profile-image-block')
51 48 assert blocks.include?('raw-html-block')
52 49 assert blocks.include?('recent-documents-block')
... ... @@ -74,14 +71,11 @@ class BoxTest &lt; ActiveSupport::TestCase
74 71 assert blocks.include?('favorite-enterprises-block')
75 72 assert blocks.include?('featured-products-block')
76 73 assert blocks.include?('feed-reader-block')
77   - assert blocks.include?('friends-block')
78 74 assert blocks.include?('highlights-block')
79 75 assert blocks.include?('link-list-block')
80 76 assert blocks.include?('location-block')
81 77 assert blocks.include?('login-block')
82   - assert blocks.include?('members-block')
83 78 assert blocks.include?('my-network-block')
84   - assert blocks.include?('people-block')
85 79 assert blocks.include?('products-block')
86 80 assert blocks.include?('profile-image-block')
87 81 assert blocks.include?('profile-info-block')
... ...
test/unit/forum_helper_test.rb
... ... @@ -38,7 +38,7 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
38 38  
39 39 should 'return post update if it has no comments' do
40 40 author = create_user('forum test author').person
41   - some_post = create(TextileArticle, :name => 'First post', :profile => profile, :parent => forum, :published => true, :last_changed_by => author)
  41 + some_post = create(TextileArticle, :name => 'First post', :profile => profile, :parent => forum, :published => true, :created_by => author)
42 42 assert some_post.comments.empty?
43 43 out = last_topic_update(some_post)
44 44 assert_match some_post.updated_at.to_s, out
... ...
test/unit/friends_block_test.rb
... ... @@ -1,86 +0,0 @@
1   -require File.dirname(__FILE__) + '/../test_helper'
2   -
3   -class FriendsBlockTest < ActiveSupport::TestCase
4   -
5   - should 'describe itself' do
6   - assert_not_equal ProfileListBlock.description, FriendsBlock.description
7   - end
8   -
9   - should 'declare its default title' do
10   - FriendsBlock.any_instance.stubs(:profile_count).returns(0)
11   - assert_not_equal ProfileListBlock.new.default_title, FriendsBlock.new.default_title
12   - end
13   -
14   - should 'list owner friends' do
15   - p1 = create_user('testuser1').person
16   - p2 = create_user('testuser2').person
17   - p3 = create_user('testuser3').person
18   - p4 = create_user('testuser4').person
19   -
20   - p1.add_friend(p2)
21   - p1.add_friend(p3)
22   - p1.add_friend(p4)
23   - p1.friends.reload
24   -
25   - block = FriendsBlock.new
26   - block.expects(:owner).returns(p1)
27   -
28   - assert_equivalent [p2, p3, p4], block.profiles
29   - end
30   -
31   - should 'point to list with all friends' do
32   - block = FriendsBlock.new
33   - user = mock
34   - user.expects(:identifier).returns('theuser')
35   - block.expects(:owner).returns(user)
36   -
37   - expects(:link_to).with('View all', :profile => 'theuser', :controller => 'profile', :action => 'friends')
38   -
39   - instance_eval(&block.footer)
40   - end
41   -
42   - should 'count number of owner friends' do
43   - p1 = create_user('testuser1').person
44   - p2 = create_user('testuser2').person
45   - p3 = create_user('testuser3').person
46   - p4 = create_user('testuser4').person
47   -
48   - p1.add_friend(p2)
49   - p1.add_friend(p3)
50   - p1.add_friend(p4)
51   -
52   - block = FriendsBlock.new
53   - block.expects(:owner).returns(p1)
54   -
55   - assert_equal 3, block.profile_count
56   - end
57   -
58   - should 'count number of public and private people' do
59   - owner = create_user('testuser1').person
60   - private_p = fast_create(Person, {:public_profile => false})
61   - public_p = fast_create(Person, {:public_profile => true})
62   -
63   - owner.add_friend(private_p)
64   - owner.add_friend(public_p)
65   -
66   - block = FriendsBlock.new
67   - block.expects(:owner).returns(owner)
68   -
69   - assert_equal 2, block.profile_count
70   - end
71   -
72   - should 'not count number of invisible people' do
73   - owner = create_user('testuser1').person
74   - private_p = fast_create(Person, {:visible => false})
75   - public_p = fast_create(Person, {:visible => true})
76   -
77   - owner.add_friend(private_p)
78   - owner.add_friend(public_p)
79   -
80   - block = FriendsBlock.new
81   - block.expects(:owner).returns(owner)
82   -
83   - assert_equal 1, block.profile_count
84   - end
85   -
86   -end
test/unit/members_block_test.rb
... ... @@ -1,62 +0,0 @@
1   -require File.dirname(__FILE__) + '/../test_helper'
2   -
3   -class MembersBlockTest < ActiveSupport::TestCase
4   -
5   - should 'inherit from ProfileListBlock' do
6   - assert_kind_of ProfileListBlock, MembersBlock.new
7   - end
8   -
9   - should 'describe itself' do
10   - assert_not_equal ProfileListBlock.description, MembersBlock.description
11   - end
12   -
13   - should 'provide a default title' do
14   - assert_not_equal ProfileListBlock.new.default_title, MembersBlock.new.default_title
15   - end
16   -
17   - should 'display members file' do
18   - community = fast_create(Community)
19   - block = MembersBlock.create
20   - block.expects(:owner).returns(community)
21   -
22   - self.expects(:render).with(:file => 'blocks/members', :locals => { :profile => community, :show_join_leave_button => false}).returns('file-with-members-list')
23   - assert_equal 'file-with-members-list', instance_eval(&block.footer)
24   - end
25   -
26   - should 'pick random members' do
27   - block = MembersBlock.new
28   -
29   - owner = mock
30   - block.expects(:owner).returns(owner)
31   -
32   - list = []
33   - owner.expects(:members).returns(list)
34   -
35   - assert_same list, block.profiles
36   - end
37   -
38   - should 'use logged-in to compose cache key' do
39   - person = fast_create(Person)
40   - community = fast_create(Community)
41   - block = MembersBlock.create
42   - block.expects(:owner).returns(community)
43   -
44   - assert_match(/-logged-in/,block.cache_key('en', person))
45   - end
46   -
47   - should 'use logged-in and member to compose cache key for members' do
48   - person = fast_create(Person)
49   - community = fast_create(Community)
50   - community.add_member person
51   - block = MembersBlock.create
52   - block.expects(:owner).returns(community)
53   -
54   - assert_match(/-logged-in-member/,block.cache_key('en', person))
55   - end
56   -
57   - should 'not change block cache key if user is nil' do
58   - block = MembersBlock.new
59   - assert_equal block.cache_key('en'), block.cache_key('en', nil)
60   - end
61   -
62   -end
test/unit/people_block_test.rb
... ... @@ -1,50 +0,0 @@
1   -require File.dirname(__FILE__) + '/../test_helper'
2   -
3   -class PeopleBlockTest < ActiveSupport::TestCase
4   -
5   - should 'inherit from ProfileListBlock' do
6   - assert_kind_of ProfileListBlock, PeopleBlock.new
7   - end
8   -
9   - should 'declare its default title' do
10   - assert_not_equal ProfileListBlock.new.default_title, PeopleBlock.new.default_title
11   - end
12   -
13   - should 'describe itself' do
14   - assert_not_equal ProfileListBlock.description, PeopleBlock.description
15   - end
16   -
17   - should 'give help' do
18   - assert_not_equal ProfileListBlock.new.help, PeopleBlock.new.help
19   - end
20   -
21   - should 'list people' do
22   - owner = fast_create(Environment)
23   - block = PeopleBlock.new
24   - block.expects(:owner).returns(owner).at_least_once
25   - person1 = fast_create(Person, :environment_id => owner.id)
26   - person2 = fast_create(Person, :environment_id => owner.id)
27   -
28   - expects(:profile_image_link).with(person1, :minor).returns(person1.name)
29   - expects(:profile_image_link).with(person2, :minor).returns(person2.name)
30   - expects(:block_title).with(anything).returns('')
31   -
32   - content = instance_eval(&block.content)
33   -
34   - assert_match(/#{person1.name}/, content)
35   - assert_match(/#{person2.name}/, content)
36   - end
37   -
38   - should 'link to browse people' do
39   - block = PeopleBlock.new
40   - block.stubs(:owner).returns(Environment.default)
41   -
42   - expects(:_).with('View all').returns('View all people')
43   - expects(:link_to).with('View all people', :controller => 'search', :action => 'people')
44   - instance_eval(&block.footer)
45   - end
46   -
47   - protected
48   - include NoosferoTestHelper
49   -
50   -end
test/unit/tiny_mce_article_test.rb
... ... @@ -8,7 +8,7 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
8 8 @profile = create_user('zezinho').person
9 9 end
10 10 attr_reader :profile
11   -
  11 +
12 12 # this test can be removed when we get real tests for TinyMceArticle
13 13 should 'be an article' do
14 14 assert_subclass TextArticle, TinyMceArticle
... ... @@ -210,7 +210,7 @@ end
210 210 assert_equal true, a.notifiable?
211 211 assert_equal true, a.advertise?
212 212 assert_equal true, a.is_trackable?
213   -
  213 +
214 214 a.published=false
215 215 assert_equal false, a.published?
216 216 assert_equal false, a.is_trackable?
... ... @@ -237,4 +237,13 @@ end
237 237 assert_tag_in_string article.body, :tag => 'source', :attributes => {:src => 'http://example.ogv', :type => 'video/ogg'}
238 238 end
239 239  
  240 + should 'not sanitize colspan and rowspan attributes' do
  241 + article = TinyMceArticle.create!(:name => 'table with colspan and rowspan',
  242 + :body => "<table colspan='2' rowspan='3'><tr></tr></table>",
  243 + :profile => profile
  244 + )
  245 + assert_tag_in_string article.body, :tag => 'table',
  246 + :attributes => { :colspan => 2, :rowspan => 3 }
  247 + end
  248 +
240 249 end
... ...
vendor/plugins/acts_as_list/Rakefile 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +require 'rake'
  2 +require 'rake/testtask'
  3 +
  4 +desc 'Default: run acts_as_list unit tests.'
  5 +task :default => :test
  6 +
  7 +desc 'Test the acts_as_ordered_tree plugin.'
  8 +Rake::TestTask.new(:test) do |t|
  9 + t.libs << 'lib'
  10 + t.pattern = 'test/**/*_test.rb'
  11 + t.verbose = true
  12 +end
... ...
vendor/plugins/acts_as_list/lib/active_record/acts/list.rb
... ... @@ -26,8 +26,8 @@ module ActiveRecord
26 26 # Configuration options are:
27 27 #
28 28 # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
29   - # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
30   - # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
  29 + # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt>
  30 + # (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
31 31 # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
32 32 # Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>
33 33 def acts_as_list(options = {})
... ... @@ -39,11 +39,16 @@ module ActiveRecord
39 39 if configuration[:scope].is_a?(Symbol)
40 40 scope_condition_method = %(
41 41 def scope_condition
42   - if #{configuration[:scope].to_s}.nil?
43   - "#{configuration[:scope].to_s} IS NULL"
44   - else
45   - "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}"
  42 + self.class.send(:sanitize_sql_hash_for_conditions, { :#{configuration[:scope].to_s} => send(:#{configuration[:scope].to_s}) })
  43 + end
  44 + )
  45 + elsif configuration[:scope].is_a?(Array)
  46 + scope_condition_method = %(
  47 + def scope_condition
  48 + attrs = %w(#{configuration[:scope].join(" ")}).inject({}) do |memo,column|
  49 + memo[column.intern] = send(column.intern); memo
46 50 end
  51 + self.class.send(:sanitize_sql_hash_for_conditions, attrs)
47 52 end
48 53 )
49 54 else
... ... @@ -63,7 +68,7 @@ module ActiveRecord
63 68  
64 69 #{scope_condition_method}
65 70  
66   - before_destroy :remove_from_list
  71 + before_destroy :decrement_positions_on_lower_items
67 72 before_create :add_to_list_bottom
68 73 EOV
69 74 end
... ... @@ -250,7 +255,7 @@ module ActiveRecord
250 255 increment_positions_on_lower_items(position)
251 256 self.update_attribute(position_column, position)
252 257 end
253   - end
  258 + end
254 259 end
255 260 end
256 261 end
... ...
vendor/plugins/acts_as_list/test/list_test.rb
... ... @@ -6,14 +6,15 @@ require &#39;active_record&#39;
6 6  
7 7 require "#{File.dirname(__FILE__)}/../init"
8 8  
9   -ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
  9 +ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
10 10  
11 11 def setup_db
12 12 ActiveRecord::Schema.define(:version => 1) do
13 13 create_table :mixins do |t|
14 14 t.column :pos, :integer
15 15 t.column :parent_id, :integer
16   - t.column :created_at, :datetime
  16 + t.column :parent_type, :string
  17 + t.column :created_at, :datetime
17 18 t.column :updated_at, :datetime
18 19 end
19 20 end
... ... @@ -46,6 +47,11 @@ class ListWithStringScopeMixin &lt; ActiveRecord::Base
46 47 def self.table_name() "mixins" end
47 48 end
48 49  
  50 +class ArrayScopeListMixin < Mixin
  51 + acts_as_list :column => "pos", :scope => [:parent_id, :parent_type]
  52 +
  53 + def self.table_name() "mixins" end
  54 +end
49 55  
50 56 class ListTest < Test::Unit::TestCase
51 57  
... ... @@ -95,7 +101,7 @@ class ListTest &lt; Test::Unit::TestCase
95 101  
96 102 def test_injection
97 103 item = ListMixin.new(:parent_id => 1)
98   - assert_equal "parent_id = 1", item.scope_condition
  104 + assert_equal '"mixins"."parent_id" = 1', item.scope_condition
99 105 assert_equal "pos", item.position_column
100 106 end
101 107  
... ... @@ -187,40 +193,60 @@ class ListTest &lt; Test::Unit::TestCase
187 193 new2.move_higher
188 194 assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos')
189 195 end
190   -
191   -
192   - def test_remove_from_list_should_then_fail_in_list?
  196 +
  197 + def test_remove_from_list_should_then_fail_in_list?
193 198 assert_equal true, ListMixin.find(1).in_list?
194 199 ListMixin.find(1).remove_from_list
195 200 assert_equal false, ListMixin.find(1).in_list?
196   - end
197   -
198   - def test_remove_from_list_should_set_position_to_nil
  201 + end
  202 +
  203 + def test_remove_from_list_should_set_position_to_nil
199 204 assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
200   -
201   - ListMixin.find(2).remove_from_list
202   -
  205 +
  206 + ListMixin.find(2).remove_from_list
  207 +
203 208 assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
204   -
  209 +
205 210 assert_equal 1, ListMixin.find(1).pos
206 211 assert_equal nil, ListMixin.find(2).pos
207 212 assert_equal 2, ListMixin.find(3).pos
208 213 assert_equal 3, ListMixin.find(4).pos
209   - end
210   -
211   - def test_remove_before_destroy_does_not_shift_lower_items_twice
  214 + end
  215 +
  216 + def test_remove_before_destroy_does_not_shift_lower_items_twice
212 217 assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
213   -
214   - ListMixin.find(2).remove_from_list
215   - ListMixin.find(2).destroy
216   -
  218 +
  219 + ListMixin.find(2).remove_from_list
  220 + ListMixin.find(2).destroy
  221 +
217 222 assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
218   -
  223 +
  224 + assert_equal 1, ListMixin.find(1).pos
  225 + assert_equal 2, ListMixin.find(3).pos
  226 + assert_equal 3, ListMixin.find(4).pos
  227 + end
  228 +
  229 + def test_before_destroy_callbacks_do_not_update_position_to_nil_before_deleting_the_record
  230 + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
  231 +
  232 + # We need to trigger all the before_destroy callbacks without actually
  233 + # destroying the record so we can see the affect the callbacks have on
  234 + # the record.
  235 + list = ListMixin.find(2)
  236 + if list.respond_to?(:run_callbacks)
  237 + list.run_callbacks(:destroy)
  238 + else
  239 + list.send(:callback, :before_destroy)
  240 + end
  241 +
  242 + assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
  243 +
219 244 assert_equal 1, ListMixin.find(1).pos
  245 + assert_equal 2, ListMixin.find(2).pos
220 246 assert_equal 2, ListMixin.find(3).pos
221 247 assert_equal 3, ListMixin.find(4).pos
222   - end
223   -
  248 + end
  249 +
224 250 end
225 251  
226 252 class ListSubTest < Test::Unit::TestCase
... ... @@ -271,7 +297,7 @@ class ListSubTest &lt; Test::Unit::TestCase
271 297  
272 298 def test_injection
273 299 item = ListMixin.new("parent_id"=>1)
274   - assert_equal "parent_id = 1", item.scope_condition
  300 + assert_equal '"mixins"."parent_id" = 1', item.scope_condition
275 301 assert_equal "pos", item.position_column
276 302 end
277 303  
... ... @@ -330,3 +356,165 @@ class ListSubTest &lt; Test::Unit::TestCase
330 356 end
331 357  
332 358 end
  359 +
  360 +class ArrayScopeListTest < Test::Unit::TestCase
  361 +
  362 + def setup
  363 + setup_db
  364 + (1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter, :parent_id => 5, :parent_type => 'ParentClass' }
  365 + end
  366 +
  367 + def teardown
  368 + teardown_db
  369 + end
  370 +
  371 + def test_reordering
  372 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  373 +
  374 + ArrayScopeListMixin.find(2).move_lower
  375 + assert_equal [1, 3, 2, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  376 +
  377 + ArrayScopeListMixin.find(2).move_higher
  378 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  379 +
  380 + ArrayScopeListMixin.find(1).move_to_bottom
  381 + assert_equal [2, 3, 4, 1], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  382 +
  383 + ArrayScopeListMixin.find(1).move_to_top
  384 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  385 +
  386 + ArrayScopeListMixin.find(2).move_to_bottom
  387 + assert_equal [1, 3, 4, 2], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  388 +
  389 + ArrayScopeListMixin.find(4).move_to_top
  390 + assert_equal [4, 1, 3, 2], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  391 + end
  392 +
  393 + def test_move_to_bottom_with_next_to_last_item
  394 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  395 + ArrayScopeListMixin.find(3).move_to_bottom
  396 + assert_equal [1, 2, 4, 3], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  397 + end
  398 +
  399 + def test_next_prev
  400 + assert_equal ArrayScopeListMixin.find(2), ArrayScopeListMixin.find(1).lower_item
  401 + assert_nil ArrayScopeListMixin.find(1).higher_item
  402 + assert_equal ArrayScopeListMixin.find(3), ArrayScopeListMixin.find(4).higher_item
  403 + assert_nil ArrayScopeListMixin.find(4).lower_item
  404 + end
  405 +
  406 + def test_injection
  407 + item = ArrayScopeListMixin.new(:parent_id => 1, :parent_type => 'ParentClass')
  408 + assert_equal '"mixins"."parent_id" = 1 AND "mixins"."parent_type" = \'ParentClass\'', item.scope_condition
  409 + assert_equal "pos", item.position_column
  410 + end
  411 +
  412 + def test_insert
  413 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  414 + assert_equal 1, new.pos
  415 + assert new.first?
  416 + assert new.last?
  417 +
  418 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  419 + assert_equal 2, new.pos
  420 + assert !new.first?
  421 + assert new.last?
  422 +
  423 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  424 + assert_equal 3, new.pos
  425 + assert !new.first?
  426 + assert new.last?
  427 +
  428 + new = ArrayScopeListMixin.create(:parent_id => 0, :parent_type => 'ParentClass')
  429 + assert_equal 1, new.pos
  430 + assert new.first?
  431 + assert new.last?
  432 + end
  433 +
  434 + def test_insert_at
  435 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  436 + assert_equal 1, new.pos
  437 +
  438 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  439 + assert_equal 2, new.pos
  440 +
  441 + new = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  442 + assert_equal 3, new.pos
  443 +
  444 + new4 = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  445 + assert_equal 4, new4.pos
  446 +
  447 + new4.insert_at(3)
  448 + assert_equal 3, new4.pos
  449 +
  450 + new.reload
  451 + assert_equal 4, new.pos
  452 +
  453 + new.insert_at(2)
  454 + assert_equal 2, new.pos
  455 +
  456 + new4.reload
  457 + assert_equal 4, new4.pos
  458 +
  459 + new5 = ArrayScopeListMixin.create(:parent_id => 20, :parent_type => 'ParentClass')
  460 + assert_equal 5, new5.pos
  461 +
  462 + new5.insert_at(1)
  463 + assert_equal 1, new5.pos
  464 +
  465 + new4.reload
  466 + assert_equal 5, new4.pos
  467 + end
  468 +
  469 + def test_delete_middle
  470 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  471 +
  472 + ArrayScopeListMixin.find(2).destroy
  473 +
  474 + assert_equal [1, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  475 +
  476 + assert_equal 1, ArrayScopeListMixin.find(1).pos
  477 + assert_equal 2, ArrayScopeListMixin.find(3).pos
  478 + assert_equal 3, ArrayScopeListMixin.find(4).pos
  479 +
  480 + ArrayScopeListMixin.find(1).destroy
  481 +
  482 + assert_equal [3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  483 +
  484 + assert_equal 1, ArrayScopeListMixin.find(3).pos
  485 + assert_equal 2, ArrayScopeListMixin.find(4).pos
  486 + end
  487 +
  488 + def test_remove_from_list_should_then_fail_in_list?
  489 + assert_equal true, ArrayScopeListMixin.find(1).in_list?
  490 + ArrayScopeListMixin.find(1).remove_from_list
  491 + assert_equal false, ArrayScopeListMixin.find(1).in_list?
  492 + end
  493 +
  494 + def test_remove_from_list_should_set_position_to_nil
  495 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  496 +
  497 + ArrayScopeListMixin.find(2).remove_from_list
  498 +
  499 + assert_equal [2, 1, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  500 +
  501 + assert_equal 1, ArrayScopeListMixin.find(1).pos
  502 + assert_equal nil, ArrayScopeListMixin.find(2).pos
  503 + assert_equal 2, ArrayScopeListMixin.find(3).pos
  504 + assert_equal 3, ArrayScopeListMixin.find(4).pos
  505 + end
  506 +
  507 + def test_remove_before_destroy_does_not_shift_lower_items_twice
  508 + assert_equal [1, 2, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  509 +
  510 + ArrayScopeListMixin.find(2).remove_from_list
  511 + ArrayScopeListMixin.find(2).destroy
  512 +
  513 + assert_equal [1, 3, 4], ArrayScopeListMixin.find(:all, :conditions => "parent_id = 5 AND parent_type = 'ParentClass'", :order => 'pos').map(&:id)
  514 +
  515 + assert_equal 1, ArrayScopeListMixin.find(1).pos
  516 + assert_equal 2, ArrayScopeListMixin.find(3).pos
  517 + assert_equal 3, ArrayScopeListMixin.find(4).pos
  518 + end
  519 +
  520 +end
... ...