diff --git a/controllers/software_communities_plugin_profile_controller.rb b/controllers/software_communities_plugin_profile_controller.rb new file mode 100644 index 0000000..9f80e73 --- /dev/null +++ b/controllers/software_communities_plugin_profile_controller.rb @@ -0,0 +1,49 @@ +class SoftwareCommunitiesPluginProfileController < ProfileController + append_view_path File.join(File.dirname(__FILE__) + '/../views') + + before_filter :validate_download_params, only: [:download_file] + + ERROR_MESSAGES = { + :not_found => _("Could not find the download file"), + :invalid_params => _("Invalid download params") + } + + def download_file + download_block = DownloadBlock.find_by_id params[:block] + index = params[:download_index].to_i + + if download_block and (index < download_block.downloads.size) + download = Download.new(download_block.downloads[index]) + + download.total_downloads += 1 + download_block.downloads[index] = download.to_hash + download_block.save + + redirect_to download.link + else + session[:notice] = ERROR_MESSAGES[:not_found] + render_not_found + end + end + + private + + def validate_download_params + valid_block = (!params[:block].nil?) and (params[:block].to_i > 0) + valid_index = params[:download_index].to_i >= 0 + + if !valid_block or !valid_index + session[:notice] = ERROR_MESSAGES[:invalid_params] + safe_redirect_back + end + end + + def safe_redirect_back + begin + redirect_to :back + rescue ActionController::RedirectBackError + # There is no :back if it is a copied url + render_not_found + end + end +end diff --git a/lib/download.rb b/lib/download.rb new file mode 100644 index 0000000..0b63fed --- /dev/null +++ b/lib/download.rb @@ -0,0 +1,51 @@ +#FIX ME: Turn this into a proper model(next release) +class Download + def initialize data + @name = data[:name] + @link = data[:link] + @software_description = data[:software_description] + @minimum_requirements = data[:minimum_requirements] + @size = data[:size] + + @total_downloads = if data[:total_downloads] + data[:total_downloads] + else + 0 + end + end + + def self.validate_download_list download_list + download_list.select! do |download| + not download[:name].blank? + end + + download_list.map do |download| + Download.new(download).to_hash + end + end + + def to_hash + { + :name => @name, + :link => @link, + :software_description => @software_description, + :minimum_requirements => @minimum_requirements, + :size => @size, + :total_downloads => @total_downloads + } + end + + def total_downloads= value + if value.is_a? Integer + @total_downloads = value + end + end + + def total_downloads + @total_downloads + end + + def link + @link + end +end diff --git a/lib/download_block.rb b/lib/download_block.rb index 3a786ca..58048b7 100644 --- a/lib/download_block.rb +++ b/lib/download_block.rb @@ -8,11 +8,7 @@ class DownloadBlock < Block validate :download_values def download_values - self.downloads.each do |download| - if download[:name] == "" - downloads.delete(download) - end - end + self.downloads = Download.validate_download_list(self.downloads) end def self.description diff --git a/lib/ext/community.rb b/lib/ext/community.rb index c737374..6f8602f 100644 --- a/lib/ext/community.rb +++ b/lib/ext/community.rb @@ -12,6 +12,8 @@ class Community has_one :software_info, :dependent=>:destroy + settings_items :hits, :type => :integer, :default => 0 + def self.create_after_moderation(requestor, attributes = {}) community = Community.new(attributes) @@ -55,4 +57,10 @@ class Community def remove_of_community_search_software? return software? end + + def hit + self.hits += 1 + self.save! + end + end diff --git a/lib/ext/profile_controller.rb b/lib/ext/profile_controller.rb index 95cd530..ba82165 100644 --- a/lib/ext/profile_controller.rb +++ b/lib/ext/profile_controller.rb @@ -2,6 +2,8 @@ require_dependency 'profile_controller' class ProfileController + before_filter :hit_view_page + def communities type = [] params[:type].downcase! unless params[:type].nil? @@ -37,4 +39,33 @@ class ProfileController end end + def user_is_a_bot? + user_agent= request.env["HTTP_USER_AGENT"] + user_agent.blank? || + user_agent.match(/bot/) || + user_agent.match(/spider/) || + user_agent.match(/crawler/) || + user_agent.match(/\(.*https?:\/\/.*\)/) + end + + def already_visited?(element) + user_id = if user.nil? then -1 else current_user.id end + user_id = "#{user_id}_#{element.id}_#{element.class}" + + if cookies.signed[:visited] == user_id + return true + else + cookies.permanent.signed[:visited] = user_id + return false + end + end + + def hit_view_page + if profile + community = profile + community.hit unless user_is_a_bot? || + already_visited?(community) || + community.class != Community + end + end end diff --git a/lib/software_communities_plugin.rb b/lib/software_communities_plugin.rb index 1f2c36c..d8508e8 100644 --- a/lib/software_communities_plugin.rb +++ b/lib/software_communities_plugin.rb @@ -42,7 +42,8 @@ class SoftwareCommunitiesPlugin < Noosfero::Plugin SearchCatalogBlock => { :type => [Environment] }, SoftwareHighlightsBlock => { :type => [Environment] }, SoftwareTabDataBlock => {:type => [Community], :position => 1}, - WikiBlock => {:type => [Community]} + WikiBlock => {:type => [Community]}, + StatisticBlock => { :type => [Community] } } end diff --git a/lib/statistic_block.rb b/lib/statistic_block.rb new file mode 100644 index 0000000..fd45f4f --- /dev/null +++ b/lib/statistic_block.rb @@ -0,0 +1,52 @@ +class StatisticBlock < Block + + settings_items :benefited_people, :type => :integer, :default => 0 + settings_items :saved_resources, :type => :float, :default => 0.0 + + attr_accessible :benefited_people, :saved_resources + + def self.description + _('Software Statistics') + end + + def help + _('This block displays software statistics.') + end + + def content(args={}) + download_blocks = get_profile_download_blocks(self.owner) + downloads = download_blocks.map do |download_block| + get_downloads_from_block(download_block) + end + + block = self + + lambda do |object| + render( + :file => 'blocks/software_statistics', + :locals => { + :block => block, + :total_downloads => downloads.sum + } + ) + end + end + + def cacheable? + false + end + + private + + def get_profile_download_blocks profile + DownloadBlock.joins(:box).where("boxes.owner_id = ?", profile.id) + end + + def get_downloads_from_block download_block + downloads = download_block.downloads.map do |download| + download[:total_downloads] unless download[:total_downloads].nil? + end + downloads.select! {|value| not value.nil? } + downloads.sum + end +end diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb new file mode 100644 index 0000000..3805787 --- /dev/null +++ b/test/functional/profile_controller_test.rb @@ -0,0 +1,40 @@ +require "test_helper" +require 'profile_controller' + +# Re-raise errors caught by the controller. +class ProfileController; def rescue_action(e) raise e end; end + +class ProfileControllerTest < ActionController::TestCase + def setup + Environment.default.enable('products_for_enterprises') + @profile = create_user('testuser').person + end + attr_reader :profile + + should 'not count a visit twice for the same user' do + profile = create_user('someone').person + login_as(@profile.identifier) + community = fast_create('Community') + + get :index, :profile => community.identifier + community.reload + assert_equal 1, community.hits + + get :index, :profile => community.identifier + community.reload + assert_equal 1, community.hits + end + + should 'not count a visit twice for unlogged users' do + profile = create_user('someone').person + community = fast_create('Community') + get :index, :profile => community.identifier + community.reload + assert_equal 1, community.hits + + get :index, :profile => community.identifier + community.reload + assert_equal 1, community.hits + end +end + diff --git a/test/functional/software_communities_plugin_profile_controller_test.rb b/test/functional/software_communities_plugin_profile_controller_test.rb new file mode 100644 index 0000000..00c715e --- /dev/null +++ b/test/functional/software_communities_plugin_profile_controller_test.rb @@ -0,0 +1,67 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' +require File.dirname(__FILE__) + '/../helpers/software_test_helper' +require File.dirname(__FILE__) + '/../../controllers/software_communities_plugin_profile_controller' + +class SoftwareCommunitiesPluginProfileController; def rescue_action(e) raise e end; end + +class SoftwareCommunitiesPluginProfileControllerTest < ActionController::TestCase + include SoftwareTestHelper + + def setup + @controller = SoftwareCommunitiesPluginProfileController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @environment = Environment.default + @environment.enable_plugin('SoftwareCommunitiesPlugin') + @environment.save! + + LicenseInfo.create( + :version=>"CC-GPL-V2", + :link=>"http://creativecommons.org/licenses/GPL/2.0/legalcode.pt" + ) + @download_data = { + :name=>"Google", + :link=>"http://google.com", + :software_description=>"all", + :minimum_requirements=>"none", + :size=>"?", + :total_downloads=>0 + } + + @software = create_software(software_fields) + @software.save! + + download_block = DownloadBlock.new + download_block.downloads = Download.validate_download_list([@download_data]) + download_block.save! + + @software.community.blocks << download_block + @software.community.save! + end + + should 'redirect to download link with correct params' do + download_block = DownloadBlock.last + get :download_file, :profile=>@software.community.identifier, + :block => download_block.id, :download_index => 0 + + assert_equal nil, session[:notice] + assert_redirected_to download_block.downloads[0][:link] + end + + should "notice when the download was not found" do + download_block = DownloadBlock.last + get :download_file, :profile=>@software.community.identifier, + :block => 123, :download_index => 0 + + assert_equal "Could not find the download file", session[:notice] + end + + should "notice when given invalid download params" do + download_block = DownloadBlock.last + get :download_file, :profile=>@software.community.identifier, + :block => download_block.id, :download_index => -5 + + assert_equal "Invalid download params", session[:notice] + end +end diff --git a/test/unit/download_test.rb b/test/unit/download_test.rb new file mode 100644 index 0000000..4b301fd --- /dev/null +++ b/test/unit/download_test.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' +require File.dirname(__FILE__) + '/../helpers/plugin_test_helper' + +class DownloadTest < ActiveSupport::TestCase + include PluginTestHelper + + def setup + @downloads_sample_data = [ + { + :name=>"Sample data A", + :link=>"http://some.url.com", + :software_description=>"all", + :minimum_requirements=>"none", + :size=>"10 mb", + :total_downloads=>0 + }, + { + :name=>"Sample data B", + :link=>"http://other.url", + :software_description=>"Linux", + :minimum_requirements=>"500 mb Ram", + :size=>"3 GB", + :total_downloads=>123 + } + ] + end + + should "Set as 0(zero) total_downloads if it is not given" do + without_total_downloads = Download.new({}) + with_total_downloads = Download.new(@downloads_sample_data.last) + + assert_equal 0, without_total_downloads.total_downloads + assert_equal @downloads_sample_data.last[:total_downloads], with_total_downloads.total_downloads + end + + should "Remove downloads without a name" do + @downloads_sample_data[1] = @downloads_sample_data[1].slice! :name + downloads = Download.validate_download_list @downloads_sample_data + + assert_equal 1, downloads.size + assert_equal @downloads_sample_data[0][:name], downloads[0][:name] + end + + should "Only set total_downloads if the value is integer" do + download = Download.new(@downloads_sample_data.last) + + download.total_downloads = "456" + assert_not_equal 456, download.total_downloads + + download.total_downloads = 456 + assert_equal 456, download.total_downloads + end +end diff --git a/views/blocks/download.html.erb b/views/blocks/download.html.erb index 34ee2af..c05a5a9 100644 --- a/views/blocks/download.html.erb +++ b/views/blocks/download.html.erb @@ -4,12 +4,19 @@