[Git][noosfero/noosfero][master] Add Organization Ratings Plugin

Daniela Feitosa gitlab at gitlab.com
Thu Sep 10 17:39:18 BRT 2015


Daniela Feitosa pushed to branch master at Noosfero / noosfero


Commits:
29249040 by Daniela Feitosa at 2015-09-10T20:33:41Z
Add Organization Ratings Plugin

A plugin that allow users to rate a organization and comment about it.

Signed-off-by: Alexandre Torres <alexandrekry at gmail.com>
Signed-off-by: Andre Bernardes <andrebsguedes at gmail.com>
Signed-off-by: Brenddon Gontijo <brenddongontijo at msn.com>
Signed-off-by: DylanGuedes <djmgguedes at gmail.com>
Signed-off-by: Fabio Teixeira <fabio1079 at gmail.com>
Signed-off-by: Filipe Ribeiro <firibeiro77 at live.com>
Signed-off-by: Gabriela Navarro <navarro1703 at gmail.com
Signed-off-by: Hebert Douglas <hebertdougl at gmail.com>
Signed-off-by: Luciano Prestes Cavalcanti <lucianopcbr at gmail.com>
Signed-off-by: Omar Junior <omarroinuj at gmail.com>
Signed-off-by: Pedro de Lyra <pedrodelyra at gmail.com>
Signed-off-by: Simião Carvalho <simiaosimis at gmail.com>
Signed-off-by: Tallys Martins <tallysmartins at gmail.com>

- - - - -


43 changed files:

- lib/noosfero/plugin.rb
- + plugins/organization_ratings/controllers/organization_ratings_plugin_admin_controller.rb
- + plugins/organization_ratings/controllers/organization_ratings_plugin_profile_controller.rb
- + plugins/organization_ratings/db/migrate/20150830225546_create_organization_ratings.rb
- + plugins/organization_ratings/db/migrate/20150830225733_create_organization_ratings_config.rb
- + plugins/organization_ratings/db/migrate/20150830230047_add_comments_count_to_profile.rb
- + plugins/organization_ratings/features/rate_community.feature
- + plugins/organization_ratings/lib/average_rating_block.rb
- + plugins/organization_ratings/lib/create_organization_rating_comment.rb
- + plugins/organization_ratings/lib/ext/comments.rb
- + plugins/organization_ratings/lib/ext/environment.rb
- + plugins/organization_ratings/lib/ext/organization.rb
- + plugins/organization_ratings/lib/ext/person.rb
- + plugins/organization_ratings/lib/organization_rating.rb
- + plugins/organization_ratings/lib/organization_ratings_block.rb
- + plugins/organization_ratings/lib/organization_ratings_config.rb
- + plugins/organization_ratings/lib/organization_ratings_plugin.rb
- + plugins/organization_ratings/lib/ratings_helper.rb
- + plugins/organization_ratings/public/images/small-star-negative.png
- + plugins/organization_ratings/public/images/small-star-positive.png
- + plugins/organization_ratings/public/images/star-negative-medium.png
- + plugins/organization_ratings/public/images/star-negative.png
- + plugins/organization_ratings/public/images/star-positive-medium.png
- + plugins/organization_ratings/public/images/star-positive.png
- + plugins/organization_ratings/public/images/user-not-logged.png
- + plugins/organization_ratings/public/organization_rating_management.js
- + plugins/organization_ratings/public/rate.js
- + plugins/organization_ratings/style.css
- + plugins/organization_ratings/test/functional/organization_ratings_plugin_admin_controller_test.rb
- + plugins/organization_ratings/test/functional/organization_ratings_plugin_profile_controller_test.rb
- + plugins/organization_ratings/test/unit/organization_rating_config_test.rb
- + plugins/organization_ratings/test/unit/organization_rating_test.rb
- + plugins/organization_ratings/test/unit/ratings_helper_test.rb
- + plugins/organization_ratings/views/blocks/display_organization_average_rating.html.erb
- + plugins/organization_ratings/views/blocks/organization_ratings_block.html.erb
- + plugins/organization_ratings/views/organization_ratings_plugin_admin/index.html.erb
- + plugins/organization_ratings/views/organization_ratings_plugin_profile/_new_rating_fields.html.erb
- + plugins/organization_ratings/views/organization_ratings_plugin_profile/new_rating.html.erb
- + plugins/organization_ratings/views/shared/_make_report_block.html.erb
- + plugins/organization_ratings/views/shared/_rating_button.html.erb
- + plugins/organization_ratings/views/shared/_user_rating_container.html.erb
- + plugins/organization_ratings/views/tasks/_create_organization_rating_comment_accept_details.html.erb
- plugins/statistics/lib/statistics_block.rb


Changes:

=====================================
lib/noosfero/plugin.rb
=====================================
--- a/lib/noosfero/plugin.rb
+++ b/lib/noosfero/plugin.rb
@@ -241,6 +241,16 @@ class Noosfero::Plugin
     nil
   end
 
+  # -> Customize the way comments are counted for Profiles and Environment
+  # considering more than just articles comments
+  # Used on statistic block
+  # Ex: a plugin may want that Communities receive comments themselves
+  # as evaluations
+  # returns = the number of comments to be sum on the statistics
+  def more_comments_count owner
+    nil
+  end
+
   # -> Adds tabs to the profile
   # returns   = { :title => title, :id => id, :content => content, :start => start }
   #   title   = name that will be displayed.


=====================================
plugins/organization_ratings/controllers/organization_ratings_plugin_admin_controller.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/controllers/organization_ratings_plugin_admin_controller.rb
@@ -0,0 +1,19 @@
+class OrganizationRatingsPluginAdminController < PluginAdminController
+
+  include RatingsHelper
+  helper :ratings
+  append_view_path File.join(File.dirname(__FILE__) + '/../views')
+
+  def index
+  end
+
+  def update
+    if env_organization_ratings_config.update_attributes(params[:organization_ratings_config])
+      session[:notice] = _('Configuration updated successfully.')
+    else
+      session[:notice] = _('Configuration could not be saved.')
+    end
+    render :action => 'index'
+  end
+
+end
\ No newline at end of file


=====================================
plugins/organization_ratings/controllers/organization_ratings_plugin_profile_controller.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/controllers/organization_ratings_plugin_profile_controller.rb
@@ -0,0 +1,76 @@
+class OrganizationRatingsPluginProfileController < ProfileController
+  include RatingsHelper
+  helper :ratings
+
+  def new_rating
+    @rating_available = user_can_rate_now?
+    @users_ratings = get_ratings(profile.id).paginate(
+                      :per_page => env_organization_ratings_config.per_page,
+                      :page => params[:npage]
+                    )
+    if request.post?
+      if @rating_available
+        create_new_rate
+      else
+        session[:notice] = _("You can not vote on this %s") % profile.class.name
+      end
+    end
+  end
+
+  private
+
+  def user_can_rate_now?
+    return false unless user
+    ratings = OrganizationRating.where(
+      :organization_id => profile.id,
+      :person_id => user.id
+    )
+
+    return false if (!ratings.empty? && env_organization_ratings_config.vote_once)
+
+    if ratings.empty?
+      true
+    else
+      elapsed_time_since_last_rating = Time.zone.now - ratings.last.created_at
+      elapsed_time_since_last_rating > env_organization_ratings_config.cooldown.hours
+    end
+  end
+
+  def create_new_rate
+    rating = OrganizationRating.new(params[:organization_rating])
+    rating.person = current_user.person
+    rating.organization = profile
+    rating.value = params[:organization_rating_value] if params[:organization_rating_value]
+
+    if rating.save
+      create_rating_comment(rating)
+      session[:notice] = _("%s successfully rated!") % profile.name
+    else
+      session[:notice] = _("Sorry, there were problems rating this profile.")
+    end
+
+    redirect_to :controller => 'profile',  :action => 'index'
+  end
+
+  def create_rating_comment(rating)
+    if params[:comments]
+        comment_task = CreateOrganizationRatingComment.create!(
+          params[:comments].merge(
+            :requestor => rating.person,
+            :organization_rating_id => rating.id,
+            :target => rating.organization
+          )
+        )
+        comment_task.finish if can_perform?(params)
+    end
+  end
+
+  def can_perform? (params)
+    (params[:comments][:body].blank? ||
+    !env_organization_ratings_config.are_moderated)
+  end
+
+  def permission
+    :manage_memberships
+  end
+end


=====================================
plugins/organization_ratings/db/migrate/20150830225546_create_organization_ratings.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/db/migrate/20150830225546_create_organization_ratings.rb
@@ -0,0 +1,12 @@
+class CreateOrganizationRatings < ActiveRecord::Migration
+  def change
+    create_table :organization_ratings do |t|
+      t.belongs_to :organization
+      t.belongs_to :person
+      t.belongs_to :comment
+      t.integer :value
+
+      t.timestamps
+    end
+  end
+end


=====================================
plugins/organization_ratings/db/migrate/20150830225733_create_organization_ratings_config.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/db/migrate/20150830225733_create_organization_ratings_config.rb
@@ -0,0 +1,14 @@
+class CreateOrganizationRatingsConfig < ActiveRecord::Migration
+
+  def change
+    create_table :organization_ratings_configs do |t|
+     t.belongs_to :environment
+     t.integer :cooldown, :integer, :default => 24
+     t.integer :default_rating, :integer, :default => 1
+     t.string  :order, :string, :default => "recent"
+     t.integer :per_page, :integer, :default => 10
+     t.boolean :vote_once, :boolean, :default => false
+     t.boolean :are_moderated, :boolean, :default => true
+    end
+  end
+end


=====================================
plugins/organization_ratings/db/migrate/20150830230047_add_comments_count_to_profile.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/db/migrate/20150830230047_add_comments_count_to_profile.rb
@@ -0,0 +1,11 @@
+class AddCommentsCountToProfile < ActiveRecord::Migration
+  def self.up
+    change_table :profiles do |t|
+      t.integer :comments_count
+    end
+  end
+
+  def self.down
+    remove_column :profiles, :comments_count
+  end
+end
\ No newline at end of file


=====================================
plugins/organization_ratings/features/rate_community.feature
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/features/rate_community.feature
@@ -0,0 +1,30 @@
+Feature: rate_community
+  As a user
+  I want to be able rate a community
+  So that users can see my feedback about that community
+
+  Background:
+    Given plugin "OrganizationRatings" is enabled on environment
+    Given the following user
+      | login     | name       |
+      | joaosilva | Joao Silva |
+    And the following community
+      | identifier  | name         |
+      | mycommunity | My Community |
+    And the following blocks
+      | owner       | type                |
+      | mycommunity | AverageRatingBlock  |
+      | mycommunity | OrganizationRatingsBlock  |
+    And the environment domain is "localhost"
+    And I am logged in as "joaosilva"
+
+  @selenium
+  Scenario: display rate button inside average block
+    Given I am on mycommunity's homepage
+    Then I should see "Rate this Community" within ".average-rating-block"
+    And I should see "Be the first to rate" within ".average-rating-block"
+
+  @selenium
+  Scenario: display rate button inside communities ratings block
+    Given I am on mycommunity's homepage
+    Then I should see "Rate Community" within ".make-report-block"


=====================================
plugins/organization_ratings/lib/average_rating_block.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/average_rating_block.rb
@@ -0,0 +1,30 @@
+class AverageRatingBlock < Block
+  include RatingsHelper
+
+  def self.description
+    _('Organization Average Rating')
+  end
+
+  def help
+    _('This block displays the organization average rating.')
+  end
+
+  def content(args = {})
+    profile_identifier = self.owner.identifier
+    average_rating = OrganizationRating.average_rating self.owner.id
+
+    proc do
+      render(
+        :file => 'blocks/display_organization_average_rating',
+        :locals => {
+          :profile_identifier => profile_identifier,
+          :average_rating => average_rating
+        }
+      )
+    end
+  end
+
+  def cacheable?
+    false
+  end
+end


=====================================
plugins/organization_ratings/lib/create_organization_rating_comment.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/create_organization_rating_comment.rb
@@ -0,0 +1,131 @@
+class CreateOrganizationRatingComment < Task
+  include Rails.application.routes.url_helpers
+
+  validates_presence_of :requestor_id, :organization_rating_id, :target_id
+
+  settings_items :organization_rating_id, :type => Integer, :default => nil
+  settings_items :organization_rating_comment_id, :type => Integer, :default => nil
+
+  attr_accessible :organization_rating_id, :body, :requestor
+  attr_accessible :reject_explanation, :target
+
+  before_save :update_comment_body
+
+  DATA_FIELDS = ['body']
+  DATA_FIELDS.each do |field|
+    settings_items field.to_sym
+  end
+
+  def update_comment_body
+    if self.organization_rating_comment_id.nil?
+      create_comment
+    else
+      comment = Comment.find_by_id(self.organization_rating_comment_id)
+      comment.body = get_comment_message
+      comment.save
+    end
+  end
+
+  def create_comment
+    if (self.body && !self.body.blank?)
+      comment_body = _("Comment waiting for approval")
+      comment = Comment.create!(:source => self.target, :body => comment_body, :author => self.requestor)
+
+
+      self.organization_rating_comment_id = comment.id
+      link_comment_with_its_rating(comment)
+    end
+  end
+
+  def link_comment_with_its_rating(user_comment)
+    rating = OrganizationRating.find(self.organization_rating_id)
+    rating.comment = user_comment
+    rating.save
+  end
+
+  def get_comment_message
+    if self.status == Status::CANCELLED
+      _("Comment rejected")
+    elsif self.status == Status::FINISHED
+      self.body
+    else
+      _("No comment")
+    end
+  end
+
+  def accept_details
+    true
+  end
+
+  def title
+    _("New Comment")
+  end
+
+  def information
+    message = _("<a href=%{requestor_url}>%{requestor}</a> wants to create a comment in this %{target_class}") %
+    {:requestor_url => url_for(self.requestor.url), :requestor => self.requestor.name, :target_class => self.target.class.name.downcase}
+
+    {:message => message}
+  end
+
+  def reject_details
+    true
+  end
+
+  def icon
+    {:type => :profile_image, :profile => requestor, :url => requestor.url}
+  end
+
+  # tells if this request was rejected
+  def rejected?
+    self.status == Task::Status::CANCELLED
+  end
+
+  # tells if this request was appoved
+  def approved?
+    self.status == Task::Status::FINISHED
+  end
+
+  def target_notification_description
+    _("%{requestor} wants to create a comment in this \"%{target}\"") %
+    {:requestor => self.requestor.name, :target => self.target.class.name.downcase }
+  end
+
+  def target_notification_message
+    _("User \"%{user}\" just requested to create a comment in the %{target_class}
+      \"%{target_name}\".
+      You have to approve or reject it through the \"Pending Validations\"
+      section in your control panel.\n") %
+    { :user => self.requestor.name, :target_class => self.target.class.name.downcase, :target_name => self.target.name }
+  end
+
+  def task_created_message
+    _("Your request for commenting at %{target} was
+      just sent. Environment administrator will receive it and will approve or
+      reject your request according to his methods and criteria.
+      You will be notified as soon as environment administrator has a position
+      about your request.") %
+    { :target => self.target.name }
+  end
+
+  def task_cancelled_message
+    _("Your request for commenting at %{target} was
+      not approved by the environment administrator. The following explanation
+      was given: \n\n%{explanation}") %
+    { :target => self.target.name,
+      :explanation => self.reject_explanation }
+  end
+
+  def task_finished_message
+    _('Your request for commenting was approved.
+      You can access %{url} to see your comment.') %
+    { :url => ratings_url }
+  end
+
+  private
+
+  def ratings_url
+    url = url_for(self.target.public_profile_url) + "/plugin/organization_ratings/new_rating"
+  end
+
+end


=====================================
plugins/organization_ratings/lib/ext/comments.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/ext/comments.rb
@@ -0,0 +1,6 @@
+require_dependency "comment"
+
+Comment.class_eval do
+
+  has_one :organization_rating
+end


=====================================
plugins/organization_ratings/lib/ext/environment.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/ext/environment.rb
@@ -0,0 +1,5 @@
+require_dependency "environment"
+
+class Environment
+  has_one :organization_ratings_config
+end


=====================================
plugins/organization_ratings/lib/ext/organization.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/ext/organization.rb
@@ -0,0 +1,7 @@
+require_dependency 'organization'
+
+Organization.class_eval do
+  has_many :organization_ratings
+
+  has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
+end


=====================================
plugins/organization_ratings/lib/ext/person.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/ext/person.rb
@@ -0,0 +1,5 @@
+require_dependency 'person'
+
+Person.class_eval do
+  has_many :organization_ratings
+end


=====================================
plugins/organization_ratings/lib/organization_rating.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/organization_rating.rb
@@ -0,0 +1,25 @@
+class OrganizationRating < ActiveRecord::Base
+  belongs_to :person
+  belongs_to :organization
+  belongs_to :comment
+
+  attr_accessible :value, :person, :organization, :comment
+
+  validates :value,
+            :presence => true, :inclusion => {
+              in: 1..5, message: _("must be between 1 and 5")
+            }
+
+  validates :organization_id, :person_id,
+            :presence => true
+
+
+  def self.average_rating organization_id
+    average = OrganizationRating.where(organization_id: organization_id).average(:value)
+
+    if average
+      (average - average.truncate) >= 0.5 ? average.ceil : average.floor
+    end
+  end
+
+end


=====================================
plugins/organization_ratings/lib/organization_ratings_block.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/organization_ratings_block.rb
@@ -0,0 +1,30 @@
+class OrganizationRatingsBlock < Block
+  include RatingsHelper
+
+  def self.description
+    _('Organization Ratings')
+  end
+
+  def help
+    _('This block displays the community ratings.')
+  end
+
+  def content(args = {})
+    block = self
+
+    proc do
+      render(
+        :file => 'blocks/organization_ratings_block',
+        :locals => {:block => block}
+      )
+    end
+  end
+
+  def limit_number_of_ratings
+    env_organization_ratings_config.per_page
+  end
+
+  def cacheable?
+    false
+  end
+end


=====================================
plugins/organization_ratings/lib/organization_ratings_config.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/organization_ratings_config.rb
@@ -0,0 +1,53 @@
+class OrganizationRatingsConfig < ActiveRecord::Base
+
+  belongs_to :environment
+
+  attr_accessible :cooldown, :default_rating, :order, :per_page
+  attr_accessible :vote_once, :are_moderated, :environment_id
+
+  ORDER_OPTIONS = {recent: _('More Recent'), best: _('Best Ratings')}
+
+  MINIMUM_RATING = 1
+  MAX_COOLDOWN = 1000
+
+  validates :default_rating,
+            :presence => true, :numericality => {
+              greater_than_or_equal_to: MINIMUM_RATING,
+              less_than_or_equal_to: 5
+            }
+
+  validates :cooldown,
+            :presence => true, :numericality => {
+              greater_than_or_equal_to: 0,
+              less_than_or_equal_to: MAX_COOLDOWN
+            }
+
+  validates :per_page,
+            :presence => true, :numericality => {
+              :greater_than_or_equal_to => 5,
+              :less_than_or_equal_to  => 20
+            }
+
+
+  def order_options
+    ORDER_OPTIONS
+  end
+
+  def minimum_ratings
+    MINIMUM_RATING
+  end
+
+  def max_cooldown
+    MAX_COOLDOWN
+  end
+
+  class << self
+    def instance
+      environment = Environment.default
+      environment.organization_ratings_config || create(environment_id: environment.id)
+    end
+
+    private :new
+  end
+
+end


=====================================
plugins/organization_ratings/lib/organization_ratings_plugin.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/organization_ratings_plugin.rb
@@ -0,0 +1,73 @@
+class OrganizationRatingsPlugin < Noosfero::Plugin
+  include Noosfero::Plugin::HotSpot
+
+  def self.plugin_name
+    "Organization Ratings"
+  end
+
+  def self.plugin_description
+    _("A plugin that allows you to rate a organization and comment about it.")
+  end
+
+  module Hotspots
+    def organization_ratings_plugin_comments_extra_fields
+      nil
+    end
+
+    def organization_ratings_title
+      nil
+    end
+
+    def organization_ratings_plugin_star_message
+      nil
+    end
+
+    def organization_ratings_plugin_extra_fields_show_data user_rating
+      nil
+    end
+  end
+
+  # Plugin Hotspot to display the average rating
+  def display_organization_average_rating organization
+    unless organization.nil?
+      average_rating = OrganizationRating.average_rating organization.id
+
+      Proc::new {
+        render :file => 'blocks/display_organization_average_rating',
+               :locals => {
+                 :profile_identifier => organization.identifier,
+                 :average_rating => average_rating
+               }
+      }
+    end
+  end
+
+  def more_comments_count owner
+    if owner.kind_of?(Environment) then
+      owner.profiles.sum(:comments_count)
+    elsif owner.kind_of?(Profile) then
+      owner.comments_count
+    else
+      0
+    end
+  end
+
+  def self.extra_blocks
+    {
+      OrganizationRatingsBlock => {:type => [Enterprise, Community], :position => ['1']},
+      AverageRatingBlock => {:type => [Enterprise, Community]}
+    }
+  end
+
+  def stylesheet?
+    true
+  end
+
+  def js_files
+    %w(
+      public/rate.js
+      public/comunities_rating_management.js
+    )
+  end
+
+end


=====================================
plugins/organization_ratings/lib/ratings_helper.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/lib/ratings_helper.rb
@@ -0,0 +1,15 @@
+module RatingsHelper
+
+  def env_organization_ratings_config
+    OrganizationRatingsConfig.instance
+  end
+
+  def get_ratings (profile_id)
+    order_options = env_organization_ratings_config.order_options
+    if env_organization_ratings_config.order.downcase == order_options[:recent]
+      ratings = OrganizationRating.where(organization_id: profile_id).order("value DESC")
+    else
+      ratings = OrganizationRating.where(organization_id: profile_id).order("created_at DESC")
+    end
+  end
+end
\ No newline at end of file


=====================================
plugins/organization_ratings/public/images/small-star-negative.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/small-star-negative.png differ


=====================================
plugins/organization_ratings/public/images/small-star-positive.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/small-star-positive.png differ


=====================================
plugins/organization_ratings/public/images/star-negative-medium.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/star-negative-medium.png differ


=====================================
plugins/organization_ratings/public/images/star-negative.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/star-negative.png differ


=====================================
plugins/organization_ratings/public/images/star-positive-medium.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/star-positive-medium.png differ


=====================================
plugins/organization_ratings/public/images/star-positive.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/star-positive.png differ


=====================================
plugins/organization_ratings/public/images/user-not-logged.png
=====================================
Binary files /dev/null and b/plugins/organization_ratings/public/images/user-not-logged.png differ


=====================================
plugins/organization_ratings/public/organization_rating_management.js
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/public/organization_rating_management.js
@@ -0,0 +1,35 @@
+(function($) {
+  "use strict";
+
+  var VoteOnce = {
+    init: function() {
+      this.cacheDom();
+      this.setEvents();
+    },
+
+
+    cacheDom: function() {
+      this.$vote_once_checkbox = $("#environment_organization_ratings_vote_once");
+      this.$hours_timer_input = $("#environment_organization_ratings_cooldown");
+    },
+
+
+    setEvents: function() {
+      this.$vote_once_checkbox.on("click", this.verifyHoursTimerDisable.bind(this));
+    },
+
+
+    verifyHoursTimerDisable: function() {
+      if (this.$vote_once_checkbox.is(":checked")) {
+        this.$hours_timer_input.attr("disabled", "disabled");
+      } else {
+        this.$hours_timer_input.removeAttr("disabled");
+      }
+    }
+  }
+
+
+  $(document).ready(function() {
+    VoteOnce.init();
+  });
+}) (jQuery);


=====================================
plugins/organization_ratings/public/rate.js
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/public/rate.js
@@ -0,0 +1,122 @@
+;(function($, undefined) {
+  "use strict";
+
+  /*
+  * All global data that are used in the stars feature.
+  */
+  var DATA = {
+    selected_rate: 0, // The actual selected star when the user click on a star
+    maximum_stars: 5, // (const) The maximum number of allowed stars
+    minimum_stars: 1, // (const) The minimum number of allowed stars
+    DATA_RATE_ATTRIBUTE: "data-star-rate", // (const) The data attribute with the star rate
+    NOT_SELECTED_VALUE: 0 // (const) The value when there is no selected rate
+  }
+
+
+  /*
+  * Prepare the global data that are variable.
+  * If the user already rated the organization, set the selected_rate as the rated value
+  */
+  function set_global_data() {
+    var selected_rate = parseInt($("#selected-star-rate").val());
+    var minimum_stars = parseInt($("#minimum_stars").val());
+    DATA.selected_rate = selected_rate;
+    DATA.minimum_stars = minimum_stars;
+  }
+
+
+  /*
+  * Given a start rate, an end rate and the elements, it makes a regex that filter
+  * the elements by the given range and returns it.
+  */
+  function star_filter(start, end, elements) {
+    var test_regex = undefined;
+
+    // Verify if it is a valid range and makes its range regex: /[start-end]/
+    if (end >= start) {
+      test_regex = new RegExp("["+(start)+"-"+(end)+"]");
+    } else {
+      // If the range is invalid, make a regex that will return no element
+      test_regex = new RegExp("[]");
+    }
+
+    // Filter the elements that are in the given range
+    var result = elements.filter(function(i, element) {
+      var rate = parseInt(element.getAttribute(DATA.DATA_RATE_ATTRIBUTE));
+
+      return test_regex.test(rate);
+    });
+
+    return result;
+  }
+
+
+  /*
+  * Show or hide the stars depending on the mouse position and the limit rate.
+  * Given the mouseover rate, the limit rate and the css classes to be swapped,
+  *
+  * It verify if the user already selected a star rate:
+  * If true:
+  *   It swap the css classes from the selected star up to the given limit rate
+  * If false:
+  *   It swap the css classes from the minimum rate up to the mouseover rate
+  */
+  function change_stars_class(rate_mouseover, limit_rate, remove_class, add_class) {
+    var previous_stars = undefined;
+
+    // The default not selected rate value is 0 and minimum is 1.
+    if (DATA.selected_rate >= DATA.minimum_stars) {
+      previous_stars = star_filter(DATA.selected_rate+1, limit_rate, $("."+remove_class));
+    } else {
+      previous_stars = star_filter(DATA.minimum_stars, rate_mouseover, $("."+remove_class));
+    }
+
+    previous_stars.switchClass(remove_class, add_class);
+  }
+
+
+  /*
+  * Sets the stars mouse events.
+  */
+  function set_star_hover_actions() {
+    $(".star-negative, .star-positive")
+      .on("mouseover", function() { // On mouse over, show the current rate star
+        var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE));
+
+        change_stars_class(rate_mouseover, rate_mouseover, "star-negative", "star-positive");
+      })
+
+      .on("mouseout", function() { // On mouse out, hide the stars
+        var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE));
+
+        change_stars_class(rate_mouseover, DATA.maximum_stars, "star-positive", "star-negative");
+      })
+
+      .on("click", function() { // On mouse click, set the selected star rate
+        var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE));
+
+        // If the new rate is different from actual, update it
+        if (rate_mouseover !== DATA.selected_rate && rate_mouseover > DATA.minimum_stars) {
+          DATA.selected_rate = rate_mouseover;
+        } else { // or else, uncheck it
+          DATA.selected_rate = DATA.minimum_stars;
+        }
+
+        // Mark the selected_rate
+        $("#selected-star-rate").val(DATA.selected_rate);
+
+        var star_notice = $(".star-notice");
+        star_notice.find("span").html(DATA.selected_rate);
+        star_notice.removeClass("star-hide");
+      });
+  }
+
+
+  /*
+  * When the page DOM is ready, set all the stars events
+  */
+  $(document).ready(function() {
+    set_global_data();
+    set_star_hover_actions();
+  });
+}) (jQuery);


=====================================
plugins/organization_ratings/style.css
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/style.css
@@ -0,0 +1,200 @@
+.star-container {
+  width: 100%;
+  height: 20px;
+}
+
+.star-negative, .star-positive {
+  width: 20px;
+  height: 20px;
+  background-repeat: no-repeat;
+  margin-right: 2px;
+  position: relative;
+  float: left;
+  cursor: pointer;
+}
+
+.star-negative {
+  background-image: url('public/images/star-negative.png');
+}
+
+.star-positive {
+  background-image: url('public/images/star-positive.png');
+}
+
+.small-star-negative, .small-star-positive {
+  background-repeat: no-repeat;
+  float: left;
+  height: 15px;
+  margin-right: 2px;
+  position: relative;
+  width: 15px;
+}
+
+.small-star-negative {
+  background-image: url('public/images/small-star-negative.png');
+}
+
+.small-star-positive {
+  background-image: url('public/images/small-star-positive.png');
+}
+
+.medium-star-negative, .medium-star-positive {
+  background-repeat: no-repeat;
+  float: left;
+  height: 20px;
+  margin-right: 2px;
+  position: relative;
+  width: 20px;
+}
+
+.medium-star-positive {
+  background-image: url('public/images/star-positive-medium.png');
+}
+
+.medium-star-negative {
+  background-image: url('public/images/star-negative-medium.png');
+}
+
+.star-hide {
+  display: none;
+}
+
+.organization-average-rating-container {
+  border-top: 1px dotted #D3D6DE;
+  margin-top: 20px;
+  padding-top: 10px;
+}
+
+.organization-average-rating-container .star-rate-text {
+  float: left;
+  margin-right: 10px;
+  padding-top: 5px;
+}
+
+.organization-average-rating-container .rating-invitation {
+  font-size: 14px;
+  float: left;
+  margin-right: 10px;
+  padding-top: 3px;
+}
+
+.organization-average-rating-container .star-container {
+  float: left;
+  width: 120px;
+}
+
+.organization-average-rating-container .rate-this-organization {
+  border-left: 1px dotted #D3D6DE;
+  float: left;
+  padding: 4px 0px 2px 10px;
+}
+
+.star-rate-data {
+  width: 100%;
+  padding-top: 20px;
+  position: relative;
+  overflow: auto;
+}
+
+.star-profile-information, .star-rate-form {
+  display: table-cell;
+  vertical-align: top;
+  width: 362px;
+}
+
+.star-profile-information {
+  width: 134px;
+}
+
+.star-rate-form {
+  display: table-cell;
+  vertical-align: top;
+}
+
+.star-profile-image, .star-profile-name {
+  text-align: center;
+}
+
+.star-profile-name {
+  word-break: break-word;
+  margin: auto;
+  margin-top: 5px;
+  width: 66px;
+}
+
+.star-rate-data .star-rate-form .star-comment-container .formfield textarea {
+  width: 361px;
+}
+
+/************* Users ratings list ****************/
+
+.ratings-list .user-rating-block,
+.ratings-list .make-report-block {
+  border-top: 1px solid #D3D6DE;
+  margin-top: 25px;
+  padding-top: 20px;
+}
+
+.ratings-list .make-report-block {
+  padding-bottom: 25px;
+}
+
+.ratings-list .see-more{
+  border-top: 1px solid #D3D6DE;
+}
+.ratings-list .user-rating-block .user-testimony-container {
+  display: table-cell;
+  padding-left: 20px;
+}
+
+.ratings-list .make-report-block .make-report-container {
+  display: table-cell;
+}
+
+.ratings-list .user-rating-block .user-testimony-container .star-container {
+  display: table-cell;
+}
+
+.ratings-list .user-rating-block .user-testimony-container .testimony-rate-date {
+  display: table-cell;
+  max-width: 95px;
+  min-width: 95px;
+  padding-right: 160px;
+  white-space: nowrap;
+}
+
+.ratings-list .user-rating-block .user-testimony-container .user-testimony {
+  margin-top: 10px;
+  word-break: break-word;
+}
+
+.ratings-list .make-report-block .make-report-container .make-report-message {
+  font-size: 14px;
+  font-style: italic;
+  word-break: break-word;
+}
+
+.ratings-list .make-report-block .make-report-container .button-bar {
+  overflow: auto;
+  padding-top: 15px;
+}
+
+.ratings-list .user-rating-block .star-profile-information {
+  border-right: 1px dotted #D3D6DE;
+}
+
+.ratings-list .icon-arrow-right-p {
+  background: url(/designs/themes/base/imgs/arrow-right-p.png) 100% 50% no-repeat;
+  display: block;
+  float: right;
+  margin-top: 20px;
+  padding-right: 15px;
+}
+
+.task_information .comment {
+  padding-left: 60px;
+}
+
+.average-rating-block {
+  height: 55px;
+}


=====================================
plugins/organization_ratings/test/functional/organization_ratings_plugin_admin_controller_test.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/test/functional/organization_ratings_plugin_admin_controller_test.rb
@@ -0,0 +1,49 @@
+require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
+require File.expand_path(File.dirname(__FILE__)) + '/../../controllers/organization_ratings_plugin_admin_controller'
+
+# Re-raise errors caught by the controller.
+class OrganizationRatingsPluginAdminController; def rescue_action(e) raise e end; end
+
+class OrganizationRatingsPluginAdminControllerTest < ActionController::TestCase
+
+  def setup
+    @controller = OrganizationRatingsPluginAdminController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+
+    @environment = Environment.default
+    @environment.enabled_plugins = ['OrganizationRatingsPlugin']
+    @environment.save
+
+    @community = Community.create(:name => "TestCommunity")
+
+    login_as(create_admin_user(@environment))
+  end
+
+  test "should update organization rating plugin configuration" do
+    post :update,  :organization_ratings_config => { :default_rating => 5,
+                                                            :cooldown => 12,
+                                                            :order => "recent",
+                                                            :per_page => 10,
+                                                            :vote_once => true }
+
+    assert :success
+    @environment.reload
+    assert_equal 5, @environment.organization_ratings_config.default_rating
+    assert_equal "Configuration updated successfully.", session[:notice]
+  end
+
+  test "should not update organization rating plugin configuration with negative cooldown time" do
+    post :update,  :organization_ratings_config => { :default_rating => 5,
+                                                  :cooldown => -50,
+                                                  :order => "recent",
+                                                  :per_page => 10,
+                                                  :vote_once => true }
+
+    assert :success
+    @environment.reload
+    assert_equal 24, @environment.organization_ratings_config.cooldown
+    assert_equal "Configuration could not be saved.", session[:notice]
+  end
+end
+


=====================================
plugins/organization_ratings/test/functional/organization_ratings_plugin_profile_controller_test.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/test/functional/organization_ratings_plugin_profile_controller_test.rb
@@ -0,0 +1,104 @@
+require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
+require File.expand_path(File.dirname(__FILE__)) + '/../../controllers/organization_ratings_plugin_profile_controller'
+
+# Re-raise errors caught by the controller.
+class OrganizationRatingsPluginProfileController; def rescue_action(e) raise e end; end
+
+class OrganizationRatingsPluginProfileControllerTest < ActionController::TestCase
+
+  def setup
+    @controller = OrganizationRatingsPluginProfileController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+
+    @environment = Environment.default
+    @environment.enabled_plugins = ['OrganizationRatingsPlugin']
+    @environment.save
+
+    @person = create_user('testuser').person
+    @community = Community.create(:name => "TestCommunity")
+    @enterprise = fast_create(Enterprise)
+    @config = OrganizationRatingsConfig.instance
+    login_as(@person.identifier)
+    @controller.stubs(:logged_in?).returns(true)
+    @controller.stubs(:current_user).returns(@person.user)
+  end
+
+  test "should add new comment to community" do
+    post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 4
+    assert_equal "#{@community.name} successfully rated!", session[:notice]
+  end
+
+  test "Create community_rating without comment body" do
+    post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 2
+
+    assert_equal "#{@community.name} successfully rated!", session[:notice]
+  end
+
+  test "Do not create community_rating without a rate value" do
+    post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => nil
+
+    assert_equal "Sorry, there were problems rating this profile.", session[:notice]
+  end
+
+  test "do not create two ratings on Community when vote once config is true" do
+    post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 3
+
+    assert_equal "#{@community.name} successfully rated!", session[:notice]
+
+    @environment.organization_ratings_config.vote_once = true
+    @environment.save
+
+    post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test 2"}, :organization_rating_value => 3
+    assert_equal "You can not vote on this Community", session[:notice]
+  end
+
+  test "do not create two ratings on Enterprise when vote once config is true" do
+    post :new_rating, profile: @enterprise.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 3
+
+    assert_equal "#{@enterprise.name} successfully rated!", session[:notice]
+
+    @environment.organization_ratings_config.vote_once = true
+    @environment.save
+
+    post :new_rating, profile: @enterprise.identifier, :comments => {:body => "This is a test 2"}, :organization_rating_value => 3
+    assert_equal "You can not vote on this Enterprise", session[:notice]
+  end
+
+  test "should count organization ratings on statistic block when block owner = Environment" do
+    block = StatisticsBlock.new
+    enterprise = fast_create(Enterprise)
+    post :new_rating, profile: enterprise.identifier, :comments => {:body => "body board"}, :organization_rating_value => 1
+    enterprise.reload
+    @environment.reload
+    block.expects(:owner).at_least_once.returns(@environment)
+    assert_equal 1, block.comments
+  end
+
+
+  test "should count organization ratings on statistic block when block owner = Profile" do
+    @config.cooldown = 0
+    @config.save
+
+    block = StatisticsBlock.new
+
+    post :new_rating, profile: @community.identifier, :comments => {:body => "body board"}, :organization_rating_value => 1
+    post :new_rating, profile: @community.identifier, :comments => {:body => "body surf"}, :organization_rating_value => 5
+
+    block.expects(:owner).at_least_once.returns(@community)
+    @community.reload
+    assert_equal 2, block.comments
+  end
+
+  test "Display unavailable rating message for users that must wait the rating cooldown time" do
+    post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 3
+    assert_not_match(/The administrators set the minimum time of/, @response.body)
+    valid_rating = OrganizationRating.last
+
+    post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 3
+    assert_match(/The administrators set the minimum time of/, @response.body)
+    new_rating = OrganizationRating.last
+
+    assert_equal valid_rating.id, new_rating.id
+  end
+end


=====================================
plugins/organization_ratings/test/unit/organization_rating_config_test.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/test/unit/organization_rating_config_test.rb
@@ -0,0 +1,43 @@
+require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
+
+class OrganizationRatingConfigTest < ActiveSupport::TestCase
+
+  def setup
+    @environment = Environment.default
+    @environment.enabled_plugins = ['OrganizationRatingsPlugin']
+    @environment.save
+    @organization_ratings_config = OrganizationRatingsConfig.instance
+  end
+
+  test "Community ratings config default rating validation" do
+    @organization_ratings_config.default_rating = 0
+    @organization_ratings_config.save
+
+    assert_equal false, @organization_ratings_config.valid?
+    assert_equal "must be greater than or equal to 1", @organization_ratings_config.errors[:default_rating].first
+
+    @organization_ratings_config.default_rating = 6
+    assert_equal false, @organization_ratings_config.valid?
+
+    assert_equal "must be less than or equal to 5", @organization_ratings_config.errors[:default_rating].first
+  end
+
+  test "Communities ratings config cooldown validation" do
+    @organization_ratings_config.cooldown = -1
+    assert_equal false, @organization_ratings_config.valid?
+
+    assert_equal "must be greater than or equal to 0", @organization_ratings_config.errors[:cooldown].first
+  end
+
+  # test "communities ratings per page validation" do
+  #   environment = Environment.new :communities_ratings_per_page => 4
+  #   environment.valid?
+
+  #   assert_equal "must be greater than or equal to 5", environment.errors[:communities_ratings_per_page].first
+
+  #   environment.communities_ratings_per_page = 21
+  #   environment.valid?
+
+  #   assert_equal "must be less than or equal to 20", environment.errors[:communities_ratings_per_page].first
+  # end
+end


=====================================
plugins/organization_ratings/test/unit/organization_rating_test.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/test/unit/organization_rating_test.rb
@@ -0,0 +1,154 @@
+require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
+
+class OrganizationRatingTest < ActiveSupport::TestCase
+  test "The value must be between 1 and 5" do
+    organization_rating1 = OrganizationRating.new :value => -1
+    organization_rating2 = OrganizationRating.new :value => 6
+
+    assert_equal false, organization_rating1.valid?
+    assert_equal false, organization_rating2.valid?
+
+    assert_equal true, organization_rating1.errors[:value].include?("must be between 1 and 5")
+    assert_equal true, organization_rating2.errors[:value].include?("must be between 1 and 5")
+
+    organization_rating1.value = 1
+    organization_rating1.valid?
+
+    organization_rating2.value = 5
+    organization_rating2.valid?
+
+    assert_equal false, organization_rating1.errors[:value].include?("must be between 1 and 5")
+    assert_equal false, organization_rating2.errors[:value].include?("must be between 1 and 5")
+  end
+
+  test "Create task for create a rating comment" do
+    person = create_user('molly').person
+    person.email = "person at email.com"
+    person.save!
+
+    community = fast_create(Community)
+    community.add_admin(person)
+
+    organization_rating = OrganizationRating.create!(
+        :value => 3,
+        :person => person,
+        :organization => community
+    )
+
+    create_organization_rating_comment = CreateOrganizationRatingComment.create!(
+      :requestor => person,
+      :organization_rating_id => organization_rating.id,
+      :target => community
+    )
+
+    assert community.tasks.include?(create_organization_rating_comment)
+  end
+
+    test "Check comment message when Task status = ACTIVE" do
+    person = create_user('molly').person
+    person.email = "person at email.com"
+    person.save!
+
+    community = fast_create(Community)
+    community.add_admin(person)
+
+
+    organization_rating = OrganizationRating.create!(
+        :value => 3,
+        :person => person,
+        :organization => community
+    )
+
+    create_organization_rating_comment = CreateOrganizationRatingComment.create!(
+      :requestor => person,
+      :organization_rating_id => organization_rating.id,
+      :target => community,
+      :body => "sample comment"
+    )
+    assert_equal 1, create_organization_rating_comment.status
+    message = "Comment waiting for approval"
+    comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id)
+    assert_equal message, comment.body
+  end
+
+  test "Check comment message when Task status = CANCELLED" do
+    person = create_user('molly').person
+    person.email = "person at email.com"
+    person.save!
+
+    community = fast_create(Community)
+    community.add_admin(person)
+
+
+    organization_rating = OrganizationRating.create!(
+        :value => 3,
+        :person => person,
+        :organization => community
+    )
+
+    create_organization_rating_comment = CreateOrganizationRatingComment.create!(
+      :requestor => person,
+      :organization_rating_id => organization_rating.id,
+      :target => community,
+      :body => "sample comment"
+    )
+    create_organization_rating_comment.cancel
+    assert_equal 2, create_organization_rating_comment.status
+    message = "Comment rejected"
+    comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id)
+    assert_equal message, comment.body
+  end
+
+  test "Check comment message when Task status = FINISHED" do
+    person = create_user('molly').person
+    person.email = "person at email.com"
+    person.save!
+
+    community = fast_create(Community)
+    community.add_admin(person)
+
+    comment = Comment.create!(source: community,
+                                                 body: "regular comment",
+                                                 author: person)
+
+    organization_rating = OrganizationRating.create!(
+        :value => 3,
+        :person => person,
+        :organization => community,
+        :comment => comment
+    )
+
+    create_organization_rating_comment = CreateOrganizationRatingComment.create!(
+          :body => comment.body,
+          :requestor => organization_rating.person,
+          :organization_rating_id => organization_rating.id,
+          :target => organization_rating.organization,
+          :body => "sample comment"
+      )
+
+    create_organization_rating_comment.finish
+    assert_equal 3, create_organization_rating_comment.status
+    message = "sample comment"
+    comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id)
+    assert_equal message, comment.body
+  end
+
+
+  test "Should calculate community's rating average" do
+    community = fast_create Community
+    p1 = fast_create Person, :name=>"Person 1"
+    p2 = fast_create Person, :name=>"Person 2"
+    p3 = fast_create Person, :name=>"Person 3"
+
+    OrganizationRating.create! :value => 2, :organization => community, :person => p1
+    OrganizationRating.create! :value => 3, :organization => community, :person => p2
+    OrganizationRating.create! :value => 5, :organization => community, :person => p3
+
+    assert_equal 3, OrganizationRating.average_rating(community)
+
+    p4 = fast_create Person, :name=>"Person 4"
+    OrganizationRating.create! :value => 4, :organization => community, :person => p4
+
+    assert_equal 4, OrganizationRating.average_rating(community)
+  end
+end


=====================================
plugins/organization_ratings/test/unit/ratings_helper_test.rb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/test/unit/ratings_helper_test.rb
@@ -0,0 +1,63 @@
+require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper'
+require 'ratings_helper'
+
+class RatingsHelperTest < ActiveSupport::TestCase
+  include RatingsHelper
+
+  def setup
+
+    @environment = Environment.default
+    @environment.enabled_plugins = ['OrganizationRatingsPlugin']
+    @environment.save
+    @person = create_user('testuser').person
+    @community = Community.create(:name => "TestCommunity")
+    @organization_ratings_config = OrganizationRatingsConfig.instance
+  end
+
+  should "get the ratings of a community ordered by most recent ratings" do
+    ratings_array = []
+
+    first_rating = OrganizationRating.new
+    first_rating.organization = @community
+    first_rating.person = @person
+    first_rating.value = 3
+    first_rating.save
+
+    most_recent_rating = OrganizationRating.new
+    most_recent_rating.organization = @community
+    most_recent_rating.person = @person
+    most_recent_rating.value = 5
+    sleep 2
+    most_recent_rating.save
+
+    ratings_array << most_recent_rating
+    ratings_array << first_rating
+
+    assert_equal @organization_ratings_config.order, "recent"
+    assert_equal ratings_array, get_ratings(@community.id)
+  end
+
+  should "get the ratings of a community ordered by best ratings" do
+    ratings_array = []
+    @organization_ratings_config = "best"
+    @environment.save
+
+    first_rating = OrganizationRating.new
+    first_rating.organization = @community
+    first_rating.person = @person
+    first_rating.value = 3
+    first_rating.save
+
+    second_rating = OrganizationRating.new
+    second_rating.organization = @community
+    second_rating.person = @person
+    second_rating.value = 5
+    sleep 2
+    second_rating.save
+
+    ratings_array << second_rating
+    ratings_array << first_rating
+
+    assert_equal ratings_array, get_ratings(@community.id)
+  end
+end


=====================================
plugins/organization_ratings/views/blocks/display_organization_average_rating.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/blocks/display_organization_average_rating.html.erb
@@ -0,0 +1,25 @@
+<div class="organization-average-rating-container">
+  <% if average_rating %>
+    <div class="star-rate-text">
+      <%= _("Rating: ") %>
+    </div>
+
+    <div class="star-container">
+      <% (1..5).each do |star_number| %>
+        <% if star_number <= average_rating %>
+          <div class="medium-star-positive"></div>
+        <% else %>
+          <div class="medium-star-negative"></div>
+        <% end %>
+      <% end %>
+    </div>
+  <% else %>
+    <div class="rating-invitation">
+      <%= _("Be the first to rate!") %>
+    </div>
+  <% end %>
+
+  <div class="rate-this-organization">
+    <%= link_to _("Rate this %s" % profile.class.name), url_for(:controller => "organization_ratings_plugin_profile", :action => "new_rating", :profile=>profile_identifier) %>
+  </div>
+</div>
\ No newline at end of file


=====================================
plugins/organization_ratings/views/blocks/organization_ratings_block.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/blocks/organization_ratings_block.html.erb
@@ -0,0 +1,21 @@
+<div class="ratings-title">
+  <%= block_title(block.title) %>
+  <% if block.get_ratings(block.owner.id).empty? %>
+    <div class="ratings-list">
+      <%= render :partial => 'shared/make_report_block' %>
+    </div>
+  <% else %>
+    <div class="ratings-list">
+      <% block.get_ratings(block.owner.id).each_with_index do |r, index| %>
+        <% break if index >= block.limit_number_of_ratings %>
+        <%= render :partial => "shared/user_rating_container", :locals => {:user_rate => r} %>
+      <% end %>
+
+      <%= render :partial => 'shared/make_report_block' %>
+
+      <div class="see-more">
+        <%= link_to _('See more'), url_for(:controller => 'organization_ratings_plugin_profile', :action => 'new_rating'), :class => 'icon-arrow-right-p' %>
+      </div>
+    </div>
+  <% end %>
+</div>


=====================================
plugins/organization_ratings/views/organization_ratings_plugin_admin/index.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/organization_ratings_plugin_admin/index.html.erb
@@ -0,0 +1,54 @@
+<% config = env_organization_ratings_config %>
+
+<h1><%= _("Organization Rating Management") %> </h1>
+
+<%= labelled_form_for(:organization_ratings_config, :url => {:action => 'update'}) do |f| %>
+  <%= labelled_fields_for(:organization_ratings_config, config) do |c| %>
+    <table>
+      <tr>
+        <th><%= c_('Configuration') %></th>
+        <th><%= _('Value') %></th>
+      </tr>
+      <tr>
+        <td><%= _('Default amount of stars marked on evaluations') %></td>
+        <td><%= c.select :default_rating, (config.minimum_ratings)..5 %></td>
+      </tr>
+      <tr>
+        <td><%= _('Can rate an organization only once') %></td>
+        <td><%= c.check_box :vote_once %></td>
+      </tr>
+      <tr>
+        <td><%= _('The comments are moderated') %></td>
+        <td><%= c.check_box :are_moderated %></td>
+      </tr>
+      <tr>
+        <td>
+          <%= _('Time in hours between evaluations from the same user.') %>
+          <span class="hint" title=" <%= _('To disable cooldown use zero (0) value.') %> ">(?)</span>
+        </td>
+        <% hours_options = {size: 2} %>
+        <% hours_options[:disabled] = "disabled" if config.vote_once %>
+        <td><%= c.text_field :cooldown, hours_options %>
+        </td>
+      </tr>
+      <tr>
+        <td><%= _('Order ratings by') %></td>
+        <% order_options = [] %>
+        <% config.order_options.select{|k,v| order_options << v } %>
+        <td><%= c.select :order, order_options %></td>
+      </tr>
+      <tr>
+        <td><%= _('Ratings per page') %></td>
+        <td>
+          <%= c.select :per_page, 5..20 %>
+          </td>
+      </tr>
+    </table>
+    <div>
+      <% button_bar do %>
+        <%= submit_button('save', c_('Save changes')) %>
+        <%= button :back, _('Back'), :controller => 'plugins' %>
+      <% end %>
+    </div>
+  <% end %>
+<% end %>


=====================================
plugins/organization_ratings/views/organization_ratings_plugin_profile/_new_rating_fields.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/organization_ratings_plugin_profile/_new_rating_fields.html.erb
@@ -0,0 +1,80 @@
+<% min_rate = env_organization_ratings_config.minimum_ratings %>
+<% default_rating = env_organization_ratings_config.default_rating %>
+
+<div class="star-page-title">
+  <%= @plugins.dispatch(:organization_ratings_title).collect { |content| instance_exec(&content) }.join("") %>
+</div>
+
+<div class="star-rate-data">
+
+  <div class="star-profile-information">
+    <div class="star-profile-image">
+      <%= profile_image(current_user.person, :portrait) %>
+    </div>
+
+    <div class="star-profile-name">
+      <%= current_user.name %>
+    </div>
+  </div>
+
+  <% if @rating_available %>
+    <div class="star-rate-form">
+      <div data-rate-url=<%= url_for controller: "organization_ratings_plugin_profile", :action => "rate" %>>
+        <div class="star-rate-text">
+          <%= @plugins.dispatch(:organization_ratings_plugin_star_message).collect { |content| instance_exec(&content) }.join("") %>
+        </div>
+
+        <div class="star-container" data-min-rate="<%= min_rate %>">
+
+          <% (1..5).each do |rate_number| %>
+            <% if rate_number <= default_rating %>
+              <div class="star-positive" data-star-rate="<%= rate_number %>"></div>
+            <% else %>
+              <div class="star-negative" data-star-rate="<%= rate_number %>"></div>
+            <% end %>
+          <% end %>
+        </div>
+
+        <div class="star-notice star-hide">
+          <%= _("Rated as") %> <span></span> <%= _("stars") %>
+        </div>
+      </div>
+
+      <div class="star-comment-container">
+        <%= form_for :comments do |c| %>
+          <div class="formfieldline formfield type-text">
+              <%= c.label :body, _('Comment (Optional):'), :class => "formlabel" %>
+              <%= c.text_area :body %>
+          </div>
+
+          <%= @plugins.dispatch(:organization_ratings_plugin_comments_extra_fields).collect { |content| instance_exec(&content) }.join("") %>
+
+          <div class="button-bar">
+            <%= submit_button(:save, _('Save'), :cancel => {controller: 'profile', action: 'index'}) %>
+          </div>
+
+          <input type="hidden" id="selected-star-rate" name="organization_rating_value" value="<%=  @default_rate %>">
+          <input type="hidden" id="minimum_stars" name="organization_rating_min_value" value="<%= min_rate %>">
+        <% end %>
+      </div>
+
+    <% elsif env_organization_ratings_config.vote_once %>
+      <div class="star-rate-form rating-vote-once">
+        <%= _("Hi, %s! The administrators set that you can vote") % current_user.name %>
+        <strong><%= _("only once") %></strong>
+        <%= _("for this %s.") % profile.class.name.downcase %>
+        <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %>
+      </div>
+    <% else %>
+      <div class="star-rate-form rating-cooldown">
+        <%= _("Hi, %s! The administrators set the minimum time of") % current_user.name %>
+        <strong><%= _("%s hour(s)" % env_organization_ratings_config.cooldown) %></strong>
+        <%= _("between each evaluation.") %>
+
+        <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %>
+      </div>
+    <% end %>
+
+
+  </div>
+</div>
\ No newline at end of file


=====================================
plugins/organization_ratings/views/organization_ratings_plugin_profile/new_rating.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/organization_ratings_plugin_profile/new_rating.html.erb
@@ -0,0 +1,18 @@
+<% config = env_organization_ratings_config %>
+<% if logged_in? %>
+  <%= render :partial => "new_rating_fields" %>
+<% else %>
+  <div class="ratings-list">
+    <%= render :partial => "shared/make_report_block" %>
+  </div>
+<% end %>
+
+<div class="ratings-list">
+  <% @users_ratings.each do |user_rate| %>
+    <%= render :partial => "shared/user_rating_container", :locals => {:user_rate => user_rate} %>
+  <% end %>
+</div>
+
+<div id='pagination-profiles'>
+  <%= pagination_links @users_ratings, :param_name => 'npage' %>
+</div>
\ No newline at end of file


=====================================
plugins/organization_ratings/views/shared/_make_report_block.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/shared/_make_report_block.html.erb
@@ -0,0 +1,28 @@
+<% logged_in_image = profile_image(current_user.person, :portrait) if current_user %>
+<% logged_out_image = image_tag('plugins/organization_ratings/public/images/user-not-logged.png') %>
+
+<div class="make-report-block">
+  <div class="star-profile-information">
+    <div class="star-profile-image">
+      <%= logged_in? ?  logged_in_image : logged_out_image %>
+    </div>
+
+    <div class="star-profile-name">
+      <%= logged_in? ? current_user.person.name : _('User not logged *') %>
+    </div>
+  </div>
+
+  <div class="make-report-container">
+    <div class="make-report-message">
+      <%= _('Report your experiences.') %>
+    </div>
+
+    <%= render :partial => 'shared/rating_button', :locals => { :disabled => false } %>
+
+    <% unless logged_in? %>
+      <div class="alert">
+        <%= _('* You must be logged in to submit a report.') %>
+      </div>
+    <% end %>
+  </div>
+</div>
\ No newline at end of file


=====================================
plugins/organization_ratings/views/shared/_rating_button.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/shared/_rating_button.html.erb
@@ -0,0 +1,10 @@
+<% button_bar do %>
+  <% if logged_in? %>
+    <%= button(:new,_("Rate %s ") % profile.class.name,
+              {:controller => "organization_ratings_plugin_profile",
+               :action => "new_rating"}) %>
+  <% else %>
+     <%= button(:login,_("Log in") , {:controller => 'account',
+                                      :action => 'login'}) %>
+  <% end %>
+<% end %>


=====================================
plugins/organization_ratings/views/shared/_user_rating_container.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/shared/_user_rating_container.html.erb
@@ -0,0 +1,33 @@
+<div class="user-rating-block">
+  <div class="star-profile-information">
+    <div class="star-profile-image">
+      <%= profile_image(user_rate.person, :portrait) %>
+    </div>
+
+    <div class="star-profile-name">
+      <%= user_rate.person.name %>
+    </div>
+  </div>
+
+  <div class="user-testimony-container">
+    <div class="testimony-rate-date">
+      <%= time_ago_in_words(user_rate.created_at) %>
+    </div>
+
+    <div class="star-container">
+      <% (1..5).each do |rate_number| %>
+        <% if rate_number <=  user_rate.value %>
+          <div class="small-star-positive"></div>
+        <% else %>
+          <div class="small-star-negative"></div>
+        <% end %>
+      <% end %>
+    </div>
+
+    <div class="user-testimony">
+      <%= user_rate.comment.nil? ? _("No comment") : user_rate.comment.body %>
+    </div>
+
+    <%= @plugins.dispatch(:organization_ratings_plugin_extra_fields_show_data, user_rate).collect { |content| instance_exec(&content) }.join("") %>
+  </div>
+</div>


=====================================
plugins/organization_ratings/views/tasks/_create_organization_rating_comment_accept_details.html.erb
=====================================
--- /dev/null
+++ b/plugins/organization_ratings/views/tasks/_create_organization_rating_comment_accept_details.html.erb
@@ -0,0 +1,4 @@
+<div class="organization-rating-comment-body">
+  <%= _("Comment:")%>
+  <%= "\"#{task.body}\""%>
+</div>


=====================================
plugins/statistics/lib/statistics_block.rb
=====================================
--- a/plugins/statistics/lib/statistics_block.rb
+++ b/plugins/statistics/lib/statistics_block.rb
@@ -128,11 +128,12 @@ class StatisticsBlock < Block
     end
   end
 
+  include Noosfero::Plugin::HotSpot
   def comments
     if owner.kind_of?(Environment) then
-      owner.profiles.joins(:articles).sum(:comments_count).to_i
+      owner.articles.sum(:comments_count).to_i + plugins.dispatch(:more_comments_count, owner).first.to_i
     elsif owner.kind_of?(Profile) then
-      owner.articles.sum(:comments_count)
+      owner.articles.sum(:comments_count) + plugins.dispatch(:more_comments_count, owner).first.to_i
     else
       0
     end



View it on GitLab: https://gitlab.com/noosfero/noosfero/commit/29249040654c0a8948afeb1748ddd3f3e6819042
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listas.softwarelivre.org/pipermail/noosfero-dev/attachments/20150910/75c2f6ac/attachment-0001.html>


More information about the Noosfero-dev mailing list