diff --git a/plugins/communities_ratings/controllers/communities_ratings_plugin_admin_controller.rb b/plugins/communities_ratings/controllers/communities_ratings_plugin_admin_controller.rb new file mode 100644 index 0000000..bcd123c --- /dev/null +++ b/plugins/communities_ratings/controllers/communities_ratings_plugin_admin_controller.rb @@ -0,0 +1,17 @@ +class CommunitiesRatingsPluginAdminController < PluginAdminController + + append_view_path File.join(File.dirname(__FILE__) + '/../views') + + def index + end + + def update + if @environment.update_attributes(params[:environment]) + 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 diff --git a/plugins/communities_ratings/controllers/communities_ratings_plugin_profile_controller.rb b/plugins/communities_ratings/controllers/communities_ratings_plugin_profile_controller.rb new file mode 100644 index 0000000..b8b2504 --- /dev/null +++ b/plugins/communities_ratings/controllers/communities_ratings_plugin_profile_controller.rb @@ -0,0 +1,80 @@ +class CommunitiesRatingsPluginProfileController < ProfileController + include RatingsHelper + + def new_rating + @rating_available = can_rate_now? + @users_ratings = get_ratings(profile.id) + @users_ratings = @users_ratings.paginate( + :per_page => environment.communities_ratings_per_page, + :page => params[:npage] + ) + @default_rate = environment.communities_ratings_default_rating + @min_rate = Environment.communities_ratings_min_rating + + if request.post? + if @rating_available + create_new_rate + else + session[:notice] = _("You cant vote on this community") + end + end + end + + private + + def can_rate_now? + return false unless user + + ratings = CommunityRating.where( + :community_id=>profile.id, + :person_id=>user.id + ) + + return false if !ratings.empty? && environment.communities_ratings_vote_once + + if ratings.empty? + true + else + elapsed_time_since_last_rating = Time.zone.now - ratings.last.created_at + elapsed_time_since_last_rating > environment.communities_ratings_cooldown.hours + end + end + + def create_new_rate + community_rating = CommunityRating.new(params[:community_rating]) + community_rating.person = current_user.person + community_rating.community = profile + community_rating.value = params[:community_rating_value] if params[:community_rating_value] + + if params[:comments] and (not params[:comments][:body].empty?) + if !environment.communities_ratings_are_moderated + comment = Comment.new(params[:comments]) + comment.author = community_rating.person + comment.community = community_rating.community + comment.save + + community_rating.comment = comment + else + create_comment = CreateCommunityRatingComment.create!( + params[:comments].merge( + :requestor => community_rating.person, + :source => community_rating.community, + :community_rating => community_rating, + :organization => community_rating.community + ) + ) + end + end + + if community_rating.save + session[:notice] = _("#{profile.name} successfully rated!") + redirect_to :controller => 'profile', :action => 'index' + else + session[:notice] = _("Sorry, there were problems rating this profile.") + end + end + + def permission + :manage_memberships + end +end diff --git a/plugins/communities_ratings/db/migrate/20150701122801_create_community_ratings.rb b/plugins/communities_ratings/db/migrate/20150701122801_create_community_ratings.rb new file mode 100644 index 0000000..5534983 --- /dev/null +++ b/plugins/communities_ratings/db/migrate/20150701122801_create_community_ratings.rb @@ -0,0 +1,11 @@ +class CreateCommunityRatings < ActiveRecord::Migration + def change + create_table :community_ratings do |t| + t.belongs_to :community + t.belongs_to :person + t.integer :value + + t.timestamps + end + end +end diff --git a/plugins/communities_ratings/db/migrate/20150706161041_add_comments_count_to_community.rb b/plugins/communities_ratings/db/migrate/20150706161041_add_comments_count_to_community.rb new file mode 100644 index 0000000..d3bd9a4 --- /dev/null +++ b/plugins/communities_ratings/db/migrate/20150706161041_add_comments_count_to_community.rb @@ -0,0 +1,11 @@ +class AddCommentsCountToCommunity < 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 diff --git a/plugins/communities_ratings/db/migrate/20150707133834_add_community_rating_to_comments.rb b/plugins/communities_ratings/db/migrate/20150707133834_add_community_rating_to_comments.rb new file mode 100644 index 0000000..10c7bda --- /dev/null +++ b/plugins/communities_ratings/db/migrate/20150707133834_add_community_rating_to_comments.rb @@ -0,0 +1,11 @@ +class AddCommunityRatingToComments < ActiveRecord::Migration + def self.up + change_table :comments do |t| + t.belongs_to :community_rating + end + end + + def self.down + remove_column :comments, :community_rating_id + end +end diff --git a/plugins/communities_ratings/db/migrate/20150806192933_create_community_rating_comment_task.rb b/plugins/communities_ratings/db/migrate/20150806192933_create_community_rating_comment_task.rb new file mode 100644 index 0000000..e5d6a98 --- /dev/null +++ b/plugins/communities_ratings/db/migrate/20150806192933_create_community_rating_comment_task.rb @@ -0,0 +1,13 @@ +class CreateCommunityRatingCommentTask < ActiveRecord::Migration + def up + change_table :tasks do |t| + t.belongs_to :community_rating + t.belongs_to :source, :foreign_key => :source_id + end + end + + def down + remove_column :tasks, :community_ratings_id + remove_column :tasks, :source_id + end +end diff --git a/plugins/communities_ratings/db/migrate/20151010171028_add_communities_rating_config_to_environment.rb b/plugins/communities_ratings/db/migrate/20151010171028_add_communities_rating_config_to_environment.rb new file mode 100644 index 0000000..4a7c9dc --- /dev/null +++ b/plugins/communities_ratings/db/migrate/20151010171028_add_communities_rating_config_to_environment.rb @@ -0,0 +1,11 @@ +class AddCommunitiesRatingConfigToEnvironment < ActiveRecord::Migration + + def change + add_column :environments, :communities_ratings_cooldown, :integer, :default => 24 + add_column :environments, :communities_ratings_default_rating, :integer, :default => 1 + add_column :environments, :communities_ratings_order, :string, :default => "most recent" + add_column :environments, :communities_ratings_per_page, :integer, :default => 10 + add_column :environments, :communities_ratings_vote_once, :boolean, :default => false + add_column :environments, :communities_ratings_are_moderated, :boolean, :default => true + end +end diff --git a/plugins/communities_ratings/lib/communities_ratings_block.rb b/plugins/communities_ratings/lib/communities_ratings_block.rb new file mode 100644 index 0000000..fcee628 --- /dev/null +++ b/plugins/communities_ratings/lib/communities_ratings_block.rb @@ -0,0 +1,31 @@ +class CommunitiesRatingsBlock < Block + include RatingsHelper + + def self.description + _('Community Ratings') + end + + def help + _('This block displays the community ratings.') + end + + def content(args = {}) + block = self + + proc do + render( + :file => 'blocks/communities_ratings_block', + :locals => {:block => block} + ) + end + end + + def limit_number_of_ratings + count = self.owner.community_ratings.count + count > 3 ? 3 : count + end + + def cacheable? + false + end +end diff --git a/plugins/communities_ratings/lib/communities_ratings_plugin.rb b/plugins/communities_ratings/lib/communities_ratings_plugin.rb new file mode 100644 index 0000000..eb618a2 --- /dev/null +++ b/plugins/communities_ratings/lib/communities_ratings_plugin.rb @@ -0,0 +1,62 @@ +class CommunitiesRatingsPlugin < Noosfero::Plugin + include Noosfero::Plugin::HotSpot + + def self.plugin_name + "Communities Ratings" + end + + def self.plugin_description + _("A plugin that allows you to rate a community and comment about it.") + end + + module Hotspots + def communities_ratings_plugin_comments_extra_fields + nil + end + + def communities_ratings_title + nil + end + + def communities_ratings_plugin_star_message + nil + end + + def communities_ratings_plugin_extra_fields_show_data user_rating + nil + end + end + + # Plugin Hotspot to display the average rating + def display_community_average_rating community + unless community.nil? + average_rating = CommunityRating.average_rating community.id + + Proc::new { + render :file => 'hotspots/display_community_average_rating', + :locals => { + :profile_identifier => community.identifier, + :average_rating => average_rating + } + } + end + end + + def self.extra_blocks + { + CommunitiesRatingsBlock => { :type => [Community], :position => ['1']} + } + end + + def stylesheet? + true + end + + def js_files + %w( + public/rate.js + public/comunities_rating_management.js + ) + end + +end diff --git a/plugins/communities_ratings/lib/community_rating.rb b/plugins/communities_ratings/lib/community_rating.rb new file mode 100644 index 0000000..a8f551a --- /dev/null +++ b/plugins/communities_ratings/lib/community_rating.rb @@ -0,0 +1,26 @@ +class CommunityRating < ActiveRecord::Base + belongs_to :person + belongs_to :community + + attr_accessible :value, :person, :community + + validates :value, + :presence => true, :inclusion => { + in: 1..5, message: _("must be between 1 and 5") + } + + validates :community_id, :person_id, + :presence => true + + has_one :comment + + def self.average_rating community_id + average = CommunityRating.where(community_id: community_id).average(:value) + + if average + (average - average.truncate) >= 0.5 ? average.ceil : average.floor + else + nil + end + end +end diff --git a/plugins/communities_ratings/lib/create_community_rating_comment.rb b/plugins/communities_ratings/lib/create_community_rating_comment.rb new file mode 100644 index 0000000..07a8a6b --- /dev/null +++ b/plugins/communities_ratings/lib/create_community_rating_comment.rb @@ -0,0 +1,101 @@ +class CreateCommunityRatingComment < Task + include Rails.application.routes.url_helpers + + validates_presence_of :requestor_id, :community_rating, :target_id + + attr_accessible :community_rating, :source, :body, :requestor, :reject_explanation, :organization + belongs_to :source, :class_name => 'Community', :foreign_key => :source_id + belongs_to :community_rating + + alias :organization :target + alias :organization= :target= + + DATA_FIELDS = ['body'] + DATA_FIELDS.each do |field| + settings_items field.to_sym + end + + + def perform + comment = Comment.create!(:source => self.source, :body => self.body, :author => self.requestor) + + self.community_rating.comment = comment + self.community_rating.save! + end + + def title + _("New Comment") + end + + def information + message = _("
%{requestor} wants to create a comment in the \"%{source}\" community.
Comment:
\"%{body}\"
") % + {:requestor => self.requestor.name, :source => self.source.name, :body => self.body } + + {: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 the \"%{source}\" community') % + {:requestor => self.requestor.name, :source => self.source.name } + end + + def target_notification_message + _("User \"%{user}\" just requested to create a comment in the \"%{source}\" community. + You have to approve or reject it through the \"Pending Validations\" + section in your control panel.\n") % + { :user => self.requestor.name, :source => self.source.name } + end + + def task_created_message + + _("Your request for commenting at %{source} 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.") % + { :source => self.source.name } + end + + def task_cancelled_message + _("Your request for commenting at %{source} was + not approved by the environment administrator. The following explanation + was given: \n\n%{explanation}") % + { :source => self.source.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 => mount_url } + end + + private + + def mount_url + identifier = self.source.identifier + # The use of url_for doesn't allow the /social within the Public Software + # portal. That's why the url is mounted so 'hard coded' + url = "#{organization.top_url}/profile/#{identifier}" + end + +end diff --git a/plugins/communities_ratings/lib/ext/comments.rb b/plugins/communities_ratings/lib/ext/comments.rb new file mode 100644 index 0000000..3a14edd --- /dev/null +++ b/plugins/communities_ratings/lib/ext/comments.rb @@ -0,0 +1,8 @@ +require_dependency "comment" + +Comment.class_eval do + alias :community :source + alias :community= :source= + + belongs_to :community_rating +end diff --git a/plugins/communities_ratings/lib/ext/community.rb b/plugins/communities_ratings/lib/ext/community.rb new file mode 100644 index 0000000..d89ca6a --- /dev/null +++ b/plugins/communities_ratings/lib/ext/community.rb @@ -0,0 +1,7 @@ +require_dependency 'community' + +Community.class_eval do + has_many :community_ratings + + has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc' +end diff --git a/plugins/communities_ratings/lib/ext/environment.rb b/plugins/communities_ratings/lib/ext/environment.rb new file mode 100644 index 0000000..a38f958 --- /dev/null +++ b/plugins/communities_ratings/lib/ext/environment.rb @@ -0,0 +1,35 @@ +require_dependency 'environment' + +Environment.class_eval do + attr_accessible :communities_ratings_cooldown, :communities_ratings_default_rating, :communities_ratings_order, :communities_ratings_per_page, :communities_ratings_vote_once, :communities_ratings_are_moderated + + COMMUNITIES_RATINGS_ORDER_OPTIONS = ["Most Recent", "Best Ratings"] + COMMUNITIES_RATINGS_MINIMUM_RATING = 1 + COMMUNITIES_RATINGS_MAX_COOLDOWN = 1000 + + validates :communities_ratings_default_rating, + :presence => true, :numericality => { + greater_than_or_equal_to: COMMUNITIES_RATINGS_MINIMUM_RATING, + less_than_or_equal_to: 5 + } + + validates :communities_ratings_cooldown, + :presence => true, :numericality => { + greater_than_or_equal_to: 0, + less_than_or_equal_to: COMMUNITIES_RATINGS_MAX_COOLDOWN + } + + validates :communities_ratings_per_page, + :presence => true, :numericality => { + :greater_than_or_equal_to => 5, + :less_than_or_equal_to => 20 + } + + def self.communities_ratings_min_rating + COMMUNITIES_RATINGS_MINIMUM_RATING + end + + def self.communities_ratings_order_options + COMMUNITIES_RATINGS_ORDER_OPTIONS + end +end diff --git a/plugins/communities_ratings/lib/ext/person.rb b/plugins/communities_ratings/lib/ext/person.rb new file mode 100644 index 0000000..f0839f7 --- /dev/null +++ b/plugins/communities_ratings/lib/ext/person.rb @@ -0,0 +1,5 @@ +require_dependency 'person' + +Person.class_eval do + has_many :community_ratings +end diff --git a/plugins/communities_ratings/lib/ratings_helper.rb b/plugins/communities_ratings/lib/ratings_helper.rb new file mode 100644 index 0000000..1692a91 --- /dev/null +++ b/plugins/communities_ratings/lib/ratings_helper.rb @@ -0,0 +1,10 @@ +module RatingsHelper + + def get_ratings (profile_id) + if Environment.default.communities_ratings_order.downcase == ("best ratings") + ratings = CommunityRating.where(community_id: profile_id).order("value DESC") + else + ratings = CommunityRating.where(community_id: profile_id).order("created_at DESC") + end + end +end \ No newline at end of file diff --git a/plugins/communities_ratings/public/comunities_rating_management.js b/plugins/communities_ratings/public/comunities_rating_management.js new file mode 100644 index 0000000..6281b6d --- /dev/null +++ b/plugins/communities_ratings/public/comunities_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_communities_ratings_vote_once"); + this.$hours_timer_input = $("#environment_communities_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); diff --git a/plugins/communities_ratings/public/images/small-star-negative.png b/plugins/communities_ratings/public/images/small-star-negative.png new file mode 100644 index 0000000..eabea40 Binary files /dev/null and b/plugins/communities_ratings/public/images/small-star-negative.png differ diff --git a/plugins/communities_ratings/public/images/small-star-positive.png b/plugins/communities_ratings/public/images/small-star-positive.png new file mode 100644 index 0000000..febf0de Binary files /dev/null and b/plugins/communities_ratings/public/images/small-star-positive.png differ diff --git a/plugins/communities_ratings/public/images/star-negative-medium.png b/plugins/communities_ratings/public/images/star-negative-medium.png new file mode 100644 index 0000000..41973e7 Binary files /dev/null and b/plugins/communities_ratings/public/images/star-negative-medium.png differ diff --git a/plugins/communities_ratings/public/images/star-negative.png b/plugins/communities_ratings/public/images/star-negative.png new file mode 100644 index 0000000..41973e7 Binary files /dev/null and b/plugins/communities_ratings/public/images/star-negative.png differ diff --git a/plugins/communities_ratings/public/images/star-positive-medium.png b/plugins/communities_ratings/public/images/star-positive-medium.png new file mode 100644 index 0000000..ca15335 Binary files /dev/null and b/plugins/communities_ratings/public/images/star-positive-medium.png differ diff --git a/plugins/communities_ratings/public/images/star-positive.png b/plugins/communities_ratings/public/images/star-positive.png new file mode 100644 index 0000000..ca15335 Binary files /dev/null and b/plugins/communities_ratings/public/images/star-positive.png differ diff --git a/plugins/communities_ratings/public/images/user-not-logged.png b/plugins/communities_ratings/public/images/user-not-logged.png new file mode 100644 index 0000000..7b433a4 Binary files /dev/null and b/plugins/communities_ratings/public/images/user-not-logged.png differ diff --git a/plugins/communities_ratings/public/rate.js b/plugins/communities_ratings/public/rate.js new file mode 100644 index 0000000..3094ad6 --- /dev/null +++ b/plugins/communities_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 community, 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); diff --git a/plugins/communities_ratings/style.css b/plugins/communities_ratings/style.css new file mode 100644 index 0000000..565d2b5 --- /dev/null +++ b/plugins/communities_ratings/style.css @@ -0,0 +1,196 @@ +.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; +} + +.community-average-rating-container { + border-top: 1px dotted #D3D6DE; + margin-top: 20px; + padding-top: 10px; +} + +.community-average-rating-container .star-rate-text { + float: left; + margin-right: 10px; + padding-top: 5px; +} + +.community-average-rating-container .rating-invitation { + font-size: 14px; + float: left; + margin-right: 10px; + padding-top: 3px; +} + +.community-average-rating-container .star-container { + float: left; + width: 120px; +} + +.community-average-rating-container .rate-this-community { + 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; +} \ No newline at end of file diff --git a/plugins/communities_ratings/test/functional/communities_ratings_plugin_admin_controller_test.rb b/plugins/communities_ratings/test/functional/communities_ratings_plugin_admin_controller_test.rb new file mode 100644 index 0000000..06e1394 --- /dev/null +++ b/plugins/communities_ratings/test/functional/communities_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/communities_ratings_plugin_admin_controller' + +# Re-raise errors caught by the controller. +class CommunitiesRatingsPluginAdminController; def rescue_action(e) raise e end; end + +class CommunitiesRatingsPluginAdminControllerTest < ActionController::TestCase + + def setup + @controller = CommunitiesRatingsPluginAdminController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @environment = Environment.default + @environment.enabled_plugins = ['CommunitiesRatingsPlugin'] + @environment.save + + @community = Community.create(:name => "TestCommunity") + + login_as(create_admin_user(@environment)) + end + + test "should update communities rating plugin configuration" do + post :update, :environment => { :communities_ratings_default_rating => 5, + :communities_ratings_cooldown => 12, + :communities_ratings_order => "Most Recent", + :communities_ratings_per_page => 10, + :communities_ratings_vote_once => true } + + assert :success + @environment.reload + assert_equal 5, @environment.communities_ratings_default_rating + assert_equal "Configuration updated successfully.", session[:notice] + end + + test "should not update communities rating plugin configuration with wrong cooldown time" do + post :update, :environment => { :communities_ratings_default_rating => 5, + :communities_ratings_cooldown => -50, + :communities_ratings_order => "Most Recent", + :communities_ratings_per_page => 10, + :communities_ratings_vote_once => true } + + assert :success + @environment.reload + assert_equal 24, @environment.communities_ratings_cooldown + assert_equal "Configuration could not be saved.", session[:notice] + end +end + diff --git a/plugins/communities_ratings/test/functional/communities_ratings_plugin_profile_controller_test.rb b/plugins/communities_ratings/test/functional/communities_ratings_plugin_profile_controller_test.rb new file mode 100644 index 0000000..3ee14c2 --- /dev/null +++ b/plugins/communities_ratings/test/functional/communities_ratings_plugin_profile_controller_test.rb @@ -0,0 +1,65 @@ +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' +require File.expand_path(File.dirname(__FILE__)) + '/../../controllers/communities_ratings_plugin_profile_controller' + +# Re-raise errors caught by the controller. +class CommunitiesRatingsPluginProfileController; def rescue_action(e) raise e end; end + +class CommunitiesRatingsPluginProfileControllerTest < ActionController::TestCase + + def setup + @controller = CommunitiesRatingsPluginProfileController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @environment = Environment.default + @environment.enabled_plugins = ['CommunitiesRatingsPlugin'] + @environment.save + + @person = create_user('testuser').person + @community = Community.create(:name => "TestCommunity") + + 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"}, :community_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 => ""}, :community_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 => ""}, :community_rating_value => nil + + assert_equal "Sorry, there were problems rating this profile.", session[:notice] + end + + test "do not create two ratings when environment vote once is true" do + @environment.communities_ratings_vote_once = true + @environment.save + post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test"}, :community_rating_value => 3 + + assert_equal "#{@community.name} successfully rated!", session[:notice] + + post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test 2"}, :community_rating_value => 3 + assert_equal "You cant vote on this community", session[:notice] + end + + test "Display unavailable rating message for users that must wait the rating cooldown time" do + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :community_rating_value => 3 + assert_not_match(/The administrators set the minimum time of/, @response.body) + valid_rating = CommunityRating.last + + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :community_rating_value => 3 + assert_match(/The administrators set the minimum time of/, @response.body) + new_rating = CommunityRating.last + + assert_equal valid_rating.id, new_rating.id + end +end diff --git a/plugins/communities_ratings/test/unit/community_rating_test.rb b/plugins/communities_ratings/test/unit/community_rating_test.rb new file mode 100644 index 0000000..671b6c1 --- /dev/null +++ b/plugins/communities_ratings/test/unit/community_rating_test.rb @@ -0,0 +1,65 @@ +require 'test_helper' + +class CommunityRatingTest < ActiveSupport::TestCase + test "The value must be between 1 and 5" do + community_rating1 = CommunityRating.new :value => -1 + community_rating2 = CommunityRating.new :value => 6 + + assert_equal false, community_rating1.valid? + assert_equal false, community_rating2.valid? + + assert_equal true, community_rating1.errors[:value].include?("must be between 1 and 5") + assert_equal true, community_rating2.errors[:value].include?("must be between 1 and 5") + + community_rating1.value = 1 + community_rating1.valid? + + community_rating2.value = 5 + community_rating2.valid? + + assert_equal false, community_rating1.errors[:value].include?("must be between 1 and 5") + assert_equal false, community_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@email.com" + person.save! + + community = fast_create(Community) + community.add_admin(person) + + community_rating = CommunityRating.create!( + :value => 3, + :person => person, + :community => community + ) + + create_community_rating_comment = CreateCommunityRatingComment.create!( + :requestor => person, + :source => community, + :community_rating => community_rating, + :organization => community + ) + + assert community.tasks.include?(create_community_rating_comment) + 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" + + CommunityRating.create! :value => 2, :community => community, :person => p1 + CommunityRating.create! :value => 3, :community => community, :person => p2 + CommunityRating.create! :value => 5, :community => community, :person => p3 + + assert_equal 3, CommunityRating.average_rating(community) + + p4 = fast_create Person, :name=>"Person 4" + CommunityRating.create! :value => 4, :community => community, :person => p4 + + assert_equal 4, CommunityRating.average_rating(community) + end +end diff --git a/plugins/communities_ratings/test/unit/environment_test.rb b/plugins/communities_ratings/test/unit/environment_test.rb new file mode 100644 index 0000000..6af365a --- /dev/null +++ b/plugins/communities_ratings/test/unit/environment_test.rb @@ -0,0 +1,34 @@ +require 'test_helper' + +class EnvironmentTest < ActiveSupport::TestCase + test "Communities ratings default rating validation" do + environment = Environment.new :communities_ratings_default_rating => 0 + environment.valid? + + assert_equal "must be greater than or equal to 1", environment.errors[:communities_ratings_default_rating].first + + environment.communities_ratings_default_rating = 6 + environment.valid? + + assert_equal "must be less than or equal to 5", environment.errors[:communities_ratings_default_rating].first + end + + test "Communities ratings cooldown validation" do + environment = Environment.new :communities_ratings_cooldown => -1 + environment.valid? + + assert_equal "must be greater than or equal to 0", environment.errors[:communities_ratings_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 diff --git a/plugins/communities_ratings/test/unit/ratings_helper_test.rb b/plugins/communities_ratings/test/unit/ratings_helper_test.rb new file mode 100644 index 0000000..9a28638 --- /dev/null +++ b/plugins/communities_ratings/test/unit/ratings_helper_test.rb @@ -0,0 +1,62 @@ +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 = ['CommunitiesRatingsPlugin'] + @environment.save + @person = create_user('testuser').person + @community = Community.create(:name => "TestCommunity") + end + + should "get the ratings of a community ordered by most recent ratings" do + ratings_array = [] + + first_rating = CommunityRating.new + first_rating.community = @community + first_rating.person = @person + first_rating.value = 3 + first_rating.save + + most_recent_rating = CommunityRating.new + most_recent_rating.community = @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 @environment.communities_ratings_order, "most recent" + assert_equal ratings_array, get_ratings(@community.id) + end + + should "get the ratings of a community ordered by best ratings" do + ratings_array = [] + @environment.communities_ratings_order = "best ratings" + @environment.save + + first_rating = CommunityRating.new + first_rating.community = @community + first_rating.person = @person + first_rating.value = 3 + first_rating.save + + second_rating = CommunityRating.new + second_rating.community = @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 diff --git a/plugins/communities_ratings/views/blocks/communities_ratings_block.html.erb b/plugins/communities_ratings/views/blocks/communities_ratings_block.html.erb new file mode 100644 index 0000000..4d93e70 --- /dev/null +++ b/plugins/communities_ratings/views/blocks/communities_ratings_block.html.erb @@ -0,0 +1,21 @@ +
+ <%= block_title(block.title) %> + <% if block.get_ratings(block.owner.id).empty? %> +
+ <%= _("This community does not have any ratings") %> + <%= render :partial => 'shared/make_report_block' %> +
+ <% else %> +
+ <% 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' %> + +
+ <%= link_to _('See more'), url_for(:controller => 'communities_ratings_plugin_profile', :action => 'new_rating'), :class => 'icon-arrow-right-p' %> +
+<% end %> +
diff --git a/plugins/communities_ratings/views/communities_ratings_plugin_admin/index.html.erb b/plugins/communities_ratings/views/communities_ratings_plugin_admin/index.html.erb new file mode 100644 index 0000000..e4b9dfb --- /dev/null +++ b/plugins/communities_ratings/views/communities_ratings_plugin_admin/index.html.erb @@ -0,0 +1,53 @@ +

<%= _("Communities Rating Management") %>

+ +<%= labelled_form_for(:environment, :url => {:action => 'update'}) do |f| %> + + + + + + + + + + + + + + + + + + + + + + + <% hours_options = {size: 1} %> + <% hours_options[:disabled] = "disabled" if environment.communities_ratings_vote_once %> + + + + + + + + + + + + +
<%= c_('Configuration') %><%= _('Value') %>
<%= _('Default amount of stars marked on evaluations') %><%= select :environment, :communities_ratings_default_rating, (Environment.communities_ratings_min_rating)..5 %>
<%= _('Can only vote for one community once') %><%= check_box :environment, :communities_ratings_vote_once %>
<%= _('The comments are moderated') %><%= check_box :environment, :communities_ratings_are_moderated %>
<%= _('Time cooldown between evaluations from the same user') %><%= text_field :environment, :communities_ratings_cooldown, hours_options %> + <%= _('hours') %> +
<%= _('Order ratings by') %><%= select :environment, :communities_ratings_order, (Environment.communities_ratings_order_options) %>
<%= _('Ratings per page') %> + <%= select :environment, :communities_ratings_per_page, 5..20 %> +
+ +
+ <% button_bar do %> + <%= submit_button('save', c_('Save changes')) %> + <%= button :back, _('Back'), :controller => 'plugins' %> + <% end %> +
+ +<% end %> diff --git a/plugins/communities_ratings/views/communities_ratings_plugin_profile/_new_rating_fields.html.erb b/plugins/communities_ratings/views/communities_ratings_plugin_profile/_new_rating_fields.html.erb new file mode 100644 index 0000000..783c0f4 --- /dev/null +++ b/plugins/communities_ratings/views/communities_ratings_plugin_profile/_new_rating_fields.html.erb @@ -0,0 +1,79 @@ +
+ <%= @plugins.dispatch(:communities_ratings_title).collect { |content| instance_exec(&content) }.join("") %> +
+ +
+ +
+
+ <%= profile_image(current_user.person, :portrait) %> +
+ +
+ <%= current_user.name %> +
+
+ + <% if @rating_available %> +
+
"rate" %>> +
+ <%= @plugins.dispatch(:communities_ratings_plugin_star_message).collect { |content| instance_exec(&content) }.join("") %> +
+ +
+ + <% (1..5).each do |rate_number| %> + <% if rate_number <= @default_rate %> +
+ <% else %> +
+ <% end %> + <% end %> +
+ +
+ <%= _("Rated as") %> <%= _("stars") %> +
+
+ +
+ <%= form_for :comments do |c| %> +
+ <%= c.label :body, _('Comment (Optional):'), :class => "formlabel" %> + <%= c.text_area :body %> +
+ + <%= @plugins.dispatch(:communities_ratings_plugin_comments_extra_fields).collect { |content| instance_exec(&content) }.join("") %> + +
+ <%= submit_button(:save, _('Save'), :cancel => {controller: 'profile', action: 'index'}) %> +
+ + + + <% end %> +
+ + <% elsif environment.communities_ratings_vote_once %> +
+ <%= _("Hi, #{current_user.name}! The administrators set that you can vote") %> + + <%= 'only once' %> + + <%= "for this community." %> + <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %> +
+ <% else %> +
+ <%= _("Hi, #{current_user.name}! The administrators set the minimum time of") %> + <%= _("%s hour(s)" % environment.communities_ratings_cooldown) %> + <%= _("between each evaluation.") %> + + <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %> +
+ <% end %> + + +
+
\ No newline at end of file diff --git a/plugins/communities_ratings/views/communities_ratings_plugin_profile/new_rating.html.erb b/plugins/communities_ratings/views/communities_ratings_plugin_profile/new_rating.html.erb new file mode 100644 index 0000000..b9da0ca --- /dev/null +++ b/plugins/communities_ratings/views/communities_ratings_plugin_profile/new_rating.html.erb @@ -0,0 +1,17 @@ +<% if logged_in? %> + <%= render :partial => "new_rating_fields" %> +<% else %> +
+ <%= render :partial => "shared/make_report_block" %> +
+<% end %> + +
+ <% @users_ratings.each do |user_rate| %> + <%= render :partial => "shared/user_rating_container", :locals => {:user_rate => user_rate} %> + <% end %> +
+ +
+ <%= pagination_links @users_ratings, :param_name => 'npage' %> +
\ No newline at end of file diff --git a/plugins/communities_ratings/views/hotspots/display_community_average_rating.html.erb b/plugins/communities_ratings/views/hotspots/display_community_average_rating.html.erb new file mode 100644 index 0000000..d0dc51e --- /dev/null +++ b/plugins/communities_ratings/views/hotspots/display_community_average_rating.html.erb @@ -0,0 +1,25 @@ +
+ <% if average_rating %> +
+ <%= _("Rating: ") %> +
+ +
+ <% (1..5).each do |star_number| %> + <% if star_number <= average_rating %> +
+ <% else %> +
+ <% end %> + <% end %> +
+ <% else %> +
+ <%= _("Be the first to rate!") %> +
+ <% end %> + +
+ <%= link_to _('Rate this community'), url_for(:controller => 'communities_ratings_plugin_profile', :action => 'new_rating', :profile=>profile_identifier) %> +
+
\ No newline at end of file diff --git a/plugins/communities_ratings/views/shared/_make_report_block.html.erb b/plugins/communities_ratings/views/shared/_make_report_block.html.erb new file mode 100644 index 0000000..9654e6e --- /dev/null +++ b/plugins/communities_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/communities_ratings/public/images/user-not-logged.png') %> + +
+
+
+ <%= logged_in? ? logged_in_image : logged_out_image %> +
+ +
+ <%= logged_in? ? current_user.person.name : _('User not logged *') %> +
+
+ +
+
+ <%= _('Report your experiences.') %> +
+ + <%= render :partial => 'shared/rating_button', :locals => { :disabled => false } %> + + <% unless logged_in? %> +
+ <%= _('* You must be logged in to submit a report.') %> +
+ <% end %> +
+
\ No newline at end of file diff --git a/plugins/communities_ratings/views/shared/_rating_button.html.erb b/plugins/communities_ratings/views/shared/_rating_button.html.erb new file mode 100644 index 0000000..57627a0 --- /dev/null +++ b/plugins/communities_ratings/views/shared/_rating_button.html.erb @@ -0,0 +1,9 @@ +
+ <% options = disabled ? {:disabled => 'disabled', :class => 'disabled-button'} : {} %> + + <% if logged_in? %> + <%= button('rate',_('Rate Community'), {:controller => 'communities_ratings_plugin_profile', :action => 'new_rating'}, options) %> + <% else %> + <%= button('rate',_('Rate Community'), {:controller => 'account', :action => 'login'}, options) %> + <% end %> +
\ No newline at end of file diff --git a/plugins/communities_ratings/views/shared/_user_rating_container.html.erb b/plugins/communities_ratings/views/shared/_user_rating_container.html.erb new file mode 100644 index 0000000..935ee77 --- /dev/null +++ b/plugins/communities_ratings/views/shared/_user_rating_container.html.erb @@ -0,0 +1,33 @@ +
+
+
+ <%= profile_image(user_rate.person, :portrait) %> +
+ +
+ <%= user_rate.person.name %> +
+
+ +
+
+ <%= time_ago_in_words(user_rate.created_at) %> +
+ +
+ <% (1..5).each do |rate_number| %> + <% if rate_number <= user_rate.value %> +
+ <% else %> +
+ <% end %> + <% end %> +
+ +
+ <%= user_rate.comment.body unless user_rate.comment.nil? %> +
+ + <%= @plugins.dispatch(:communities_ratings_plugin_extra_fields_show_data, user_rate).collect { |content| instance_exec(&content) }.join("") %> +
+
-- libgit2 0.21.2