Commit 2fd621c3d7332efcdb65b6e7045269ada32ad58c
Committed by
Tallys Martins
1 parent
d841eedf
Exists in
master
and in
5 other branches
Add software statistic block
Signed-off-by: brenddongontijo <brenddongontijo@msn.com> Signed-off-by: Fabio Teixeira <fabio1079@gmail.com> Signed-off-by: Pedro de Lyra <pedrodelyra@gmail.com> Signed-off-by: Luciano Prestes Cavalcanti <lucianopcbr@gmail.com> Signed-off-by: Simiao Carvalho <simiaosimis@gmail.com> Signed-off-by: Victor Matias Navarro <victor.matias.navarro@gmail.com>
Showing
13 changed files
with
383 additions
and
12 deletions
Show diff stats
controllers/software_communities_plugin_profile_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,49 @@ |
1 | +class SoftwareCommunitiesPluginProfileController < ProfileController | |
2 | + append_view_path File.join(File.dirname(__FILE__) + '/../views') | |
3 | + | |
4 | + before_filter :validate_download_params, only: [:download_file] | |
5 | + | |
6 | + ERROR_MESSAGES = { | |
7 | + :not_found => _("Could not find the download file"), | |
8 | + :invalid_params => _("Invalid download params") | |
9 | + } | |
10 | + | |
11 | + def download_file | |
12 | + download_block = DownloadBlock.find_by_id params[:block] | |
13 | + index = params[:download_index].to_i | |
14 | + | |
15 | + if download_block and (index < download_block.downloads.size) | |
16 | + download = Download.new(download_block.downloads[index]) | |
17 | + | |
18 | + download.total_downloads += 1 | |
19 | + download_block.downloads[index] = download.to_hash | |
20 | + download_block.save | |
21 | + | |
22 | + redirect_to download.link | |
23 | + else | |
24 | + session[:notice] = ERROR_MESSAGES[:not_found] | |
25 | + render_not_found | |
26 | + end | |
27 | + end | |
28 | + | |
29 | + private | |
30 | + | |
31 | + def validate_download_params | |
32 | + valid_block = (!params[:block].nil?) and (params[:block].to_i > 0) | |
33 | + valid_index = params[:download_index].to_i >= 0 | |
34 | + | |
35 | + if !valid_block or !valid_index | |
36 | + session[:notice] = ERROR_MESSAGES[:invalid_params] | |
37 | + safe_redirect_back | |
38 | + end | |
39 | + end | |
40 | + | |
41 | + def safe_redirect_back | |
42 | + begin | |
43 | + redirect_to :back | |
44 | + rescue ActionController::RedirectBackError | |
45 | + # There is no :back if it is a copied url | |
46 | + render_not_found | |
47 | + end | |
48 | + end | |
49 | +end | ... | ... |
... | ... | @@ -0,0 +1,51 @@ |
1 | +#FIX ME: Turn this into a proper model(next release) | |
2 | +class Download | |
3 | + def initialize data | |
4 | + @name = data[:name] | |
5 | + @link = data[:link] | |
6 | + @software_description = data[:software_description] | |
7 | + @minimum_requirements = data[:minimum_requirements] | |
8 | + @size = data[:size] | |
9 | + | |
10 | + @total_downloads = if data[:total_downloads] | |
11 | + data[:total_downloads] | |
12 | + else | |
13 | + 0 | |
14 | + end | |
15 | + end | |
16 | + | |
17 | + def self.validate_download_list download_list | |
18 | + download_list.select! do |download| | |
19 | + not download[:name].blank? | |
20 | + end | |
21 | + | |
22 | + download_list.map do |download| | |
23 | + Download.new(download).to_hash | |
24 | + end | |
25 | + end | |
26 | + | |
27 | + def to_hash | |
28 | + { | |
29 | + :name => @name, | |
30 | + :link => @link, | |
31 | + :software_description => @software_description, | |
32 | + :minimum_requirements => @minimum_requirements, | |
33 | + :size => @size, | |
34 | + :total_downloads => @total_downloads | |
35 | + } | |
36 | + end | |
37 | + | |
38 | + def total_downloads= value | |
39 | + if value.is_a? Integer | |
40 | + @total_downloads = value | |
41 | + end | |
42 | + end | |
43 | + | |
44 | + def total_downloads | |
45 | + @total_downloads | |
46 | + end | |
47 | + | |
48 | + def link | |
49 | + @link | |
50 | + end | |
51 | +end | ... | ... |
lib/download_block.rb
... | ... | @@ -8,11 +8,7 @@ class DownloadBlock < Block |
8 | 8 | validate :download_values |
9 | 9 | |
10 | 10 | def download_values |
11 | - self.downloads.each do |download| | |
12 | - if download[:name] == "" | |
13 | - downloads.delete(download) | |
14 | - end | |
15 | - end | |
11 | + self.downloads = Download.validate_download_list(self.downloads) | |
16 | 12 | end |
17 | 13 | |
18 | 14 | def self.description | ... | ... |
lib/ext/community.rb
... | ... | @@ -12,6 +12,8 @@ class Community |
12 | 12 | |
13 | 13 | has_one :software_info, :dependent=>:destroy |
14 | 14 | |
15 | + settings_items :hits, :type => :integer, :default => 0 | |
16 | + | |
15 | 17 | def self.create_after_moderation(requestor, attributes = {}) |
16 | 18 | community = Community.new(attributes) |
17 | 19 | |
... | ... | @@ -55,4 +57,10 @@ class Community |
55 | 57 | def remove_of_community_search_software? |
56 | 58 | return software? |
57 | 59 | end |
60 | + | |
61 | + def hit | |
62 | + self.hits += 1 | |
63 | + self.save! | |
64 | + end | |
65 | + | |
58 | 66 | end | ... | ... |
lib/ext/profile_controller.rb
... | ... | @@ -2,6 +2,8 @@ require_dependency 'profile_controller' |
2 | 2 | |
3 | 3 | class ProfileController |
4 | 4 | |
5 | + before_filter :hit_view_page | |
6 | + | |
5 | 7 | def communities |
6 | 8 | type = [] |
7 | 9 | params[:type].downcase! unless params[:type].nil? |
... | ... | @@ -37,4 +39,33 @@ class ProfileController |
37 | 39 | end |
38 | 40 | end |
39 | 41 | |
42 | + def user_is_a_bot? | |
43 | + user_agent= request.env["HTTP_USER_AGENT"] | |
44 | + user_agent.blank? || | |
45 | + user_agent.match(/bot/) || | |
46 | + user_agent.match(/spider/) || | |
47 | + user_agent.match(/crawler/) || | |
48 | + user_agent.match(/\(.*https?:\/\/.*\)/) | |
49 | + end | |
50 | + | |
51 | + def already_visited?(element) | |
52 | + user_id = if user.nil? then -1 else current_user.id end | |
53 | + user_id = "#{user_id}_#{element.id}_#{element.class}" | |
54 | + | |
55 | + if cookies.signed[:visited] == user_id | |
56 | + return true | |
57 | + else | |
58 | + cookies.permanent.signed[:visited] = user_id | |
59 | + return false | |
60 | + end | |
61 | + end | |
62 | + | |
63 | + def hit_view_page | |
64 | + if profile | |
65 | + community = profile | |
66 | + community.hit unless user_is_a_bot? || | |
67 | + already_visited?(community) || | |
68 | + community.class != Community | |
69 | + end | |
70 | + end | |
40 | 71 | end | ... | ... |
lib/software_communities_plugin.rb
... | ... | @@ -42,7 +42,8 @@ class SoftwareCommunitiesPlugin < Noosfero::Plugin |
42 | 42 | SearchCatalogBlock => { :type => [Environment] }, |
43 | 43 | SoftwareHighlightsBlock => { :type => [Environment] }, |
44 | 44 | SoftwareTabDataBlock => {:type => [Community], :position => 1}, |
45 | - WikiBlock => {:type => [Community]} | |
45 | + WikiBlock => {:type => [Community]}, | |
46 | + StatisticBlock => { :type => [Community] } | |
46 | 47 | } |
47 | 48 | end |
48 | 49 | ... | ... |
... | ... | @@ -0,0 +1,52 @@ |
1 | +class StatisticBlock < Block | |
2 | + | |
3 | + settings_items :benefited_people, :type => :integer, :default => 0 | |
4 | + settings_items :saved_resources, :type => :float, :default => 0.0 | |
5 | + | |
6 | + attr_accessible :benefited_people, :saved_resources | |
7 | + | |
8 | + def self.description | |
9 | + _('Software Statistics') | |
10 | + end | |
11 | + | |
12 | + def help | |
13 | + _('This block displays software statistics.') | |
14 | + end | |
15 | + | |
16 | + def content(args={}) | |
17 | + download_blocks = get_profile_download_blocks(self.owner) | |
18 | + downloads = download_blocks.map do |download_block| | |
19 | + get_downloads_from_block(download_block) | |
20 | + end | |
21 | + | |
22 | + block = self | |
23 | + | |
24 | + lambda do |object| | |
25 | + render( | |
26 | + :file => 'blocks/software_statistics', | |
27 | + :locals => { | |
28 | + :block => block, | |
29 | + :total_downloads => downloads.sum | |
30 | + } | |
31 | + ) | |
32 | + end | |
33 | + end | |
34 | + | |
35 | + def cacheable? | |
36 | + false | |
37 | + end | |
38 | + | |
39 | + private | |
40 | + | |
41 | + def get_profile_download_blocks profile | |
42 | + DownloadBlock.joins(:box).where("boxes.owner_id = ?", profile.id) | |
43 | + end | |
44 | + | |
45 | + def get_downloads_from_block download_block | |
46 | + downloads = download_block.downloads.map do |download| | |
47 | + download[:total_downloads] unless download[:total_downloads].nil? | |
48 | + end | |
49 | + downloads.select! {|value| not value.nil? } | |
50 | + downloads.sum | |
51 | + end | |
52 | +end | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +require "test_helper" | |
2 | +require 'profile_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class ProfileController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class ProfileControllerTest < ActionController::TestCase | |
8 | + def setup | |
9 | + Environment.default.enable('products_for_enterprises') | |
10 | + @profile = create_user('testuser').person | |
11 | + end | |
12 | + attr_reader :profile | |
13 | + | |
14 | + should 'not count a visit twice for the same user' do | |
15 | + profile = create_user('someone').person | |
16 | + login_as(@profile.identifier) | |
17 | + community = fast_create('Community') | |
18 | + | |
19 | + get :index, :profile => community.identifier | |
20 | + community.reload | |
21 | + assert_equal 1, community.hits | |
22 | + | |
23 | + get :index, :profile => community.identifier | |
24 | + community.reload | |
25 | + assert_equal 1, community.hits | |
26 | + end | |
27 | + | |
28 | + should 'not count a visit twice for unlogged users' do | |
29 | + profile = create_user('someone').person | |
30 | + community = fast_create('Community') | |
31 | + get :index, :profile => community.identifier | |
32 | + community.reload | |
33 | + assert_equal 1, community.hits | |
34 | + | |
35 | + get :index, :profile => community.identifier | |
36 | + community.reload | |
37 | + assert_equal 1, community.hits | |
38 | + end | |
39 | +end | |
40 | + | ... | ... |
test/functional/software_communities_plugin_profile_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,67 @@ |
1 | +require File.dirname(__FILE__) + '/../../../../test/test_helper' | |
2 | +require File.dirname(__FILE__) + '/../helpers/software_test_helper' | |
3 | +require File.dirname(__FILE__) + '/../../controllers/software_communities_plugin_profile_controller' | |
4 | + | |
5 | +class SoftwareCommunitiesPluginProfileController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class SoftwareCommunitiesPluginProfileControllerTest < ActionController::TestCase | |
8 | + include SoftwareTestHelper | |
9 | + | |
10 | + def setup | |
11 | + @controller = SoftwareCommunitiesPluginProfileController.new | |
12 | + @request = ActionController::TestRequest.new | |
13 | + @response = ActionController::TestResponse.new | |
14 | + | |
15 | + @environment = Environment.default | |
16 | + @environment.enable_plugin('SoftwareCommunitiesPlugin') | |
17 | + @environment.save! | |
18 | + | |
19 | + LicenseInfo.create( | |
20 | + :version=>"CC-GPL-V2", | |
21 | + :link=>"http://creativecommons.org/licenses/GPL/2.0/legalcode.pt" | |
22 | + ) | |
23 | + @download_data = { | |
24 | + :name=>"Google", | |
25 | + :link=>"http://google.com", | |
26 | + :software_description=>"all", | |
27 | + :minimum_requirements=>"none", | |
28 | + :size=>"?", | |
29 | + :total_downloads=>0 | |
30 | + } | |
31 | + | |
32 | + @software = create_software(software_fields) | |
33 | + @software.save! | |
34 | + | |
35 | + download_block = DownloadBlock.new | |
36 | + download_block.downloads = Download.validate_download_list([@download_data]) | |
37 | + download_block.save! | |
38 | + | |
39 | + @software.community.blocks << download_block | |
40 | + @software.community.save! | |
41 | + end | |
42 | + | |
43 | + should 'redirect to download link with correct params' do | |
44 | + download_block = DownloadBlock.last | |
45 | + get :download_file, :profile=>@software.community.identifier, | |
46 | + :block => download_block.id, :download_index => 0 | |
47 | + | |
48 | + assert_equal nil, session[:notice] | |
49 | + assert_redirected_to download_block.downloads[0][:link] | |
50 | + end | |
51 | + | |
52 | + should "notice when the download was not found" do | |
53 | + download_block = DownloadBlock.last | |
54 | + get :download_file, :profile=>@software.community.identifier, | |
55 | + :block => 123, :download_index => 0 | |
56 | + | |
57 | + assert_equal "Could not find the download file", session[:notice] | |
58 | + end | |
59 | + | |
60 | + should "notice when given invalid download params" do | |
61 | + download_block = DownloadBlock.last | |
62 | + get :download_file, :profile=>@software.community.identifier, | |
63 | + :block => download_block.id, :download_index => -5 | |
64 | + | |
65 | + assert_equal "Invalid download params", session[:notice] | |
66 | + end | |
67 | +end | ... | ... |
... | ... | @@ -0,0 +1,53 @@ |
1 | +require File.dirname(__FILE__) + '/../../../../test/test_helper' | |
2 | +require File.dirname(__FILE__) + '/../helpers/plugin_test_helper' | |
3 | + | |
4 | +class DownloadTest < ActiveSupport::TestCase | |
5 | + include PluginTestHelper | |
6 | + | |
7 | + def setup | |
8 | + @downloads_sample_data = [ | |
9 | + { | |
10 | + :name=>"Sample data A", | |
11 | + :link=>"http://some.url.com", | |
12 | + :software_description=>"all", | |
13 | + :minimum_requirements=>"none", | |
14 | + :size=>"10 mb", | |
15 | + :total_downloads=>0 | |
16 | + }, | |
17 | + { | |
18 | + :name=>"Sample data B", | |
19 | + :link=>"http://other.url", | |
20 | + :software_description=>"Linux", | |
21 | + :minimum_requirements=>"500 mb Ram", | |
22 | + :size=>"3 GB", | |
23 | + :total_downloads=>123 | |
24 | + } | |
25 | + ] | |
26 | + end | |
27 | + | |
28 | + should "Set as 0(zero) total_downloads if it is not given" do | |
29 | + without_total_downloads = Download.new({}) | |
30 | + with_total_downloads = Download.new(@downloads_sample_data.last) | |
31 | + | |
32 | + assert_equal 0, without_total_downloads.total_downloads | |
33 | + assert_equal @downloads_sample_data.last[:total_downloads], with_total_downloads.total_downloads | |
34 | + end | |
35 | + | |
36 | + should "Remove downloads without a name" do | |
37 | + @downloads_sample_data[1] = @downloads_sample_data[1].slice! :name | |
38 | + downloads = Download.validate_download_list @downloads_sample_data | |
39 | + | |
40 | + assert_equal 1, downloads.size | |
41 | + assert_equal @downloads_sample_data[0][:name], downloads[0][:name] | |
42 | + end | |
43 | + | |
44 | + should "Only set total_downloads if the value is integer" do | |
45 | + download = Download.new(@downloads_sample_data.last) | |
46 | + | |
47 | + download.total_downloads = "456" | |
48 | + assert_not_equal 456, download.total_downloads | |
49 | + | |
50 | + download.total_downloads = 456 | |
51 | + assert_equal 456, download.total_downloads | |
52 | + end | |
53 | +end | ... | ... |
views/blocks/download.html.erb
... | ... | @@ -4,12 +4,19 @@ |
4 | 4 | <h3 class="block-title"> <%= _("Download #{block.owner.software_info.community.name}") %> </h3> |
5 | 5 | <ul class="download-list"> |
6 | 6 | <% block.downloads.each_with_index do |download, index| %> |
7 | - <li id="download-item-<%=(index+1)%>"> | |
8 | - <div class="download-button"> | |
9 | - <%= link_to download[:link], title: _("Download the software") do %> | |
10 | - <span class="download-image"></span> | |
11 | - <span class="download-size"><%= download[:size] %></span> | |
12 | - <% end %> | |
7 | + <div id="download-info-<%=(index+1)%>"> | |
8 | + <div id="version01"> | |
9 | + <%= link_to :controller => 'software_communities_plugin_profile', :action=> 'download_file', :block=>block.id, :download_index=> index , title: _("Download the software") do %> | |
10 | + <span id="image-download"></span> | |
11 | + <span id="size-download"><%= download[:size] %></span> | |
12 | + <% end %> | |
13 | + </div> | |
14 | + | |
15 | + <div id="info-software-download"> | |
16 | + <span class="download-name"><%= _("#{download[:name]}") %></span> | |
17 | + <span class="download-system"><%= _("Platform:#{download[:software_description]}") %> </span> | |
18 | + <span class="req_min_spb"><%= link_to _("Minimum Requirements"), download[:minimum_requirements] %></span> | |
19 | + </div> | |
13 | 20 | </div> |
14 | 21 | <div class="download-info"> |
15 | 22 | <span class="download-name"><%= _("#{download[:name]}") %></span> | ... | ... |
... | ... | @@ -0,0 +1,11 @@ |
1 | +<div class="software-metrics-block"> | |
2 | + <ul class="metrics-list"> | |
3 | + <li><span class="arrow-globe-icon"></span><a href="#"><%= pluralize(profile.hits, 'visita', 'visitas') %></a></li> | |
4 | + <li><span class="downloads-icon"></span><a href="#"><%= pluralize(total_downloads, 'download', 'downloads') %></a></li> | |
5 | + <li><span class="face-icon"></span><a href="#"><%= block.benefited_people.to_s + _(' benefited people*') %></a></li> | |
6 | + <li><span class="pig-safe-icon"></span><a href="#"><strong class="saved-money"><%= number_to_currency(block.saved_resources, unit: 'R$ ', separator: ',', delimiter: '.') %></strong> <%= _(' saved resources*') %></a></li> | |
7 | + </ul> | |
8 | + | |
9 | + | |
10 | + <div class="admin-estimation">* <%= _("Data estimated by the software administrator.") %></div> | |
11 | +</div> | ... | ... |