Commit 0d7f79273bf29965639763a0987388b55a67f98a

Authored by Francisco Marcelo A. Lima Júnior
2 parents 39ea55d3 8b6dc0a2

Merge branch 'ActionItem2892' of github.com:SerproLivre/noosfero into ActionItem2892

Showing 213 changed files with 4328 additions and 594 deletions   Show diff stats
@@ -4,8 +4,9 @@ Copyright (c) 2007-2009, @@ -4,8 +4,9 @@ Copyright (c) 2007-2009,
4 Cáritas Brasileira <http://www.caritasbrasileira.org/> 4 Cáritas Brasileira <http://www.caritasbrasileira.org/>
5 Copyright (c) 2007-2009, 5 Copyright (c) 2007-2009,
6 Ynternet.org Foundation <http://www.ynternet.org/> 6 Ynternet.org Foundation <http://www.ynternet.org/>
7 -Copyright (c) 2008-2009, 7 +Copyright (c) 2008-2013,
8 Colivre <http://www.colivre.coop.br/> 8 Colivre <http://www.colivre.coop.br/>
  9 +Copyright (c) the Noosfero contributors. See AUTHORS
9 10
10 This program is free software: you can redistribute it and/or modify 11 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by 12 it under the terms of the GNU Affero General Public License as published by
@@ -52,3 +52,12 @@ If you write such script for your own OS, *please* share it with us at the @@ -52,3 +52,12 @@ If you write such script for your own OS, *please* share it with us at the
52 development mailing list so that we can include it in the official repository. 52 development mailing list so that we can include it in the official repository.
53 This way other people using the same OS will have to put less effort to develop 53 This way other people using the same OS will have to put less effort to develop
54 Noosfero. 54 Noosfero.
  55 +
  56 +== Submitting your changes back
  57 +
  58 +For now please read:
  59 +
  60 +- Coding conventions
  61 + http://noosfero.org/Development/CodingConventions
  62 +- Patch guidelines
  63 + http://noosfero.org/Development/PatchGuidelines
HACKING.rails235
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -This is a draft of how to create a environment to Rails 2.3.5 to Noosfero  
2 -development.  
3 -  
4 -Install dependencies:  
5 -  
6 -gem install rails -v 2.3.5  
7 -gem install i18n  
8 -gem install will_paginate -v 2.3.12  
9 -gem install cucumber  
10 -  
11 -Creating initial environment:  
12 -  
13 -rake db:schema:load  
@@ -6,7 +6,7 @@ To configure XMPP/BOSH in Noosfero you need: @@ -6,7 +6,7 @@ To configure XMPP/BOSH in Noosfero you need:
6 * SystemTimer - http://ph7spot.com/musings/system-timer 6 * SystemTimer - http://ph7spot.com/musings/system-timer
7 * Pidgin data files - http://www.pidgin.im/ 7 * Pidgin data files - http://www.pidgin.im/
8 8
9 -If you use Debian Wheezy: 9 +If you use Debian 6.0 (squeeze):
10 10
11 # apt-get install librestclient-ruby pidgin-data ruby1.8-dev 11 # apt-get install librestclient-ruby pidgin-data ruby1.8-dev
12 # gem install SystemTimer 12 # gem install SystemTimer
1 -noosfero - a web-based social platform 1 +Noosfero - a web-based social platform
2 ====================================== 2 ======================================
3 3
4 -:: About the project 4 +http://www.noosfero.org/
5 5
6 -Homepage: http://www.noosfero.org/ 6 +Documentation
  7 +-------------
7 8
8 -:: Authors and copyright 9 +The following documentation is available:
9 10
10 -Authors: see file AUTHORS  
11 -Copyright information: see file COPYRIGHT  
12 -Full license text; see file COPYING 11 +File Purpose
  12 +~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  13 +INSTALL install instructions
  14 +INSTALL.awstats install instructions - access statistics service
  15 +INSTALL.chat install instructions - chat service
  16 +INSTALL.email install instructions - email service
  17 +INSTALL.multitenancy install instructions - multiple sites
  18 +INSTALL.varnish install instructions - varnish HTTP caching (recommended)
  19 +HACKING development instruction
  20 +RELEASING instructions for doing releases
  21 +doc/noosfero/* user documentation (available through the app itself)
  22 +
  23 +
  24 +Authors and copyright
  25 +---------------------
  26 +
  27 +Authorship and copyright information is available in the files listed below.
  28 +
  29 +File Purpose
  30 +~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  31 +AUTHORS list of authors (updated at each release)
  32 +COPYRIGHT Copyright statement for the project
  33 +COPYING Full text of the project license
app/controllers/my_profile/cms_controller.rb
@@ -267,7 +267,10 @@ class CmsController &lt; MyProfileController @@ -267,7 +267,10 @@ class CmsController &lt; MyProfileController
267 @back_to = params[:back_to] || request.referer || url_for(profile.public_profile_url) 267 @back_to = params[:back_to] || request.referer || url_for(profile.public_profile_url)
268 @task = SuggestArticle.new(params[:task]) 268 @task = SuggestArticle.new(params[:task])
269 if request.post? 269 if request.post?
270 - @task.target = profile 270 + @task.target = profile
  271 + @task.ip_address = request.remote_ip
  272 + @task.user_agent = request.user_agent
  273 + @task.referrer = request.referrer
271 if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save 274 if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save
272 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') 275 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
273 redirect_to @back_to 276 redirect_to @back_to
app/controllers/my_profile/memberships_controller.rb
@@ -9,9 +9,10 @@ class MembershipsController &lt; MyProfileController @@ -9,9 +9,10 @@ class MembershipsController &lt; MyProfileController
9 def new_community 9 def new_community
10 @community = Community.new(params[:community]) 10 @community = Community.new(params[:community])
11 @community.environment = environment 11 @community.environment = environment
  12 + @back_to = params[:back_to] || url_for(:action => 'index')
12 if request.post? && @community.valid? 13 if request.post? && @community.valid?
13 @community = Community.create_after_moderation(user, {:environment => environment}.merge(params[:community])) 14 @community = Community.create_after_moderation(user, {:environment => environment}.merge(params[:community]))
14 - redirect_to :action => 'index' 15 + redirect_to @back_to
15 return 16 return
16 end 17 end
17 end 18 end
app/controllers/my_profile/profile_editor_controller.rb
@@ -4,7 +4,7 @@ class ProfileEditorController &lt; MyProfileController @@ -4,7 +4,7 @@ class ProfileEditorController &lt; MyProfileController
4 protect 'destroy_profile', :profile, :only => [:destroy_profile] 4 protect 'destroy_profile', :profile, :only => [:destroy_profile]
5 5
6 def index 6 def index
7 - @pending_tasks = Task.to(profile).pending.select{|i| user.has_permission?(i.permission, profile)} 7 + @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)}
8 end 8 end
9 9
10 helper :profile 10 helper :profile
app/controllers/my_profile/spam_controller.rb
@@ -14,9 +14,15 @@ class SpamController &lt; MyProfileController @@ -14,9 +14,15 @@ class SpamController &lt; MyProfileController
14 if params[:remove_comment] 14 if params[:remove_comment]
15 profile.comments_received.find(params[:remove_comment]).destroy 15 profile.comments_received.find(params[:remove_comment]).destroy
16 end 16 end
  17 + if params[:remove_task]
  18 + Task.to(profile).find_by_id(params[:remove_task]).destroy
  19 + end
17 if params[:mark_comment_as_ham] 20 if params[:mark_comment_as_ham]
18 profile.comments_received.find(params[:mark_comment_as_ham]).ham! 21 profile.comments_received.find(params[:mark_comment_as_ham]).ham!
19 end 22 end
  23 + if params[:mark_task_as_ham] && (t = Task.to(profile).find_by_id(params[:mark_task_as_ham]))
  24 + t.ham!
  25 + end
20 if request.xhr? 26 if request.xhr?
21 json_response(true) 27 json_response(true)
22 else 28 else
@@ -28,7 +34,8 @@ class SpamController &lt; MyProfileController @@ -28,7 +34,8 @@ class SpamController &lt; MyProfileController
28 return 34 return
29 end 35 end
30 36
31 - @spam = profile.comments_received.spam.paginate({:page => params[:page]}) 37 + @comment_spam = profile.comments_received.spam.paginate({:page => params[:comments_page]})
  38 + @task_spam = Task.to(profile).spam.paginate({:page => params[:tasks_page]})
32 end 39 end
33 40
34 protected 41 protected
app/controllers/my_profile/tasks_controller.rb
@@ -4,12 +4,12 @@ class TasksController &lt; MyProfileController @@ -4,12 +4,12 @@ class TasksController &lt; MyProfileController
4 4
5 def index 5 def index
6 @filter = params[:filter_type].blank? ? nil : params[:filter_type] 6 @filter = params[:filter_type].blank? ? nil : params[:filter_type]
7 - @tasks = Task.to(profile).pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) 7 + @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
8 @failed = params ? params[:failed] : {} 8 @failed = params ? params[:failed] : {}
9 end 9 end
10 10
11 def processed 11 def processed
12 - @tasks = Task.to(profile).closed.sort_by(&:created_at) 12 + @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at)
13 end 13 end
14 14
15 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ] 15 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ]
@@ -57,7 +57,7 @@ class TasksController &lt; MyProfileController @@ -57,7 +57,7 @@ class TasksController &lt; MyProfileController
57 end 57 end
58 58
59 def list_requested 59 def list_requested
60 - @tasks = Task.find_all_by_requestor_id(profile.id) 60 + @tasks = Task.without_spam.find_all_by_requestor_id(profile.id)
61 end 61 end
62 62
63 def ticket_details 63 def ticket_details
app/controllers/public/content_viewer_controller.rb
@@ -53,7 +53,9 @@ class ContentViewerController &lt; ApplicationController @@ -53,7 +53,9 @@ class ContentViewerController &lt; ApplicationController
53 # At this point the page will be showed 53 # At this point the page will be showed
54 @page.hit 54 @page.hit
55 55
56 - unless @page.mime_type == 'text/html' || (@page.image? && params[:view]) 56 + @page = FilePresenter.for @page
  57 +
  58 + unless @page.mime_type == 'text/html' || params[:view]
57 headers['Content-Type'] = @page.mime_type 59 headers['Content-Type'] = @page.mime_type
58 data = @page.data 60 data = @page.data
59 61
app/helpers/application_helper.rb
@@ -558,6 +558,9 @@ module ApplicationHelper @@ -558,6 +558,9 @@ module ApplicationHelper
558 # displays a link to the profile homepage with its image (as generated by 558 # displays a link to the profile homepage with its image (as generated by
559 # #profile_image) and its name below it. 559 # #profile_image) and its name below it.
560 def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil ) 560 def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil )
  561 + if content = @plugins.dispatch_first(:profile_image_link, profile, size, tag, extra_info)
  562 + return instance_eval(&content)
  563 + end
561 name = profile.short_name 564 name = profile.short_name
562 if profile.person? 565 if profile.person?
563 url = url_for(profile.check_friendship_url) 566 url = url_for(profile.check_friendship_url)
@@ -574,16 +577,16 @@ module ApplicationHelper @@ -574,16 +577,16 @@ module ApplicationHelper
574 extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) 577 extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' )
575 links = links_for_balloon(profile) 578 links = links_for_balloon(profile)
576 content_tag('div', content_tag(tag, 579 content_tag('div', content_tag(tag,
577 - (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") +  
578 - link_to(  
579 - content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +  
580 - content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +  
581 - extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ),  
582 - profile.url,  
583 - :class => 'profile_link url',  
584 - :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name,  
585 - :title => profile.name ),  
586 - :class => 'vcard'), :class => 'common-profile-list-block') 580 + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") +
  581 + link_to(
  582 + content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +
  583 + content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +
  584 + extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ),
  585 + profile.url,
  586 + :class => 'profile_link url',
  587 + :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name,
  588 + :title => profile.name ),
  589 + :class => 'vcard'), :class => 'common-profile-list-block')
587 end 590 end
588 591
589 def gravatar_url_for(email, options = {}) 592 def gravatar_url_for(email, options = {})
@@ -1113,15 +1116,34 @@ module ApplicationHelper @@ -1113,15 +1116,34 @@ module ApplicationHelper
1113 result 1116 result
1114 end 1117 end
1115 1118
1116 - def manage_enterprises  
1117 - if user && !user.enterprises.empty?  
1118 - enterprises_link = user.enterprises.map do |enterprise|  
1119 - link_to(content_tag('strong', [_('<span>Manage</span> %s') % enterprise.short_name(25)]), @environment.top_url + "/myprofile/#{enterprise.identifier}", :class => "icon-menu-"+enterprise.class.identification.underscore, :title => [_('Manage %s') % enterprise.short_name]) 1119 + def manage_link(list, kind)
  1120 + if list.present?
  1121 + link_to_all = nil
  1122 + if list.count > 5
  1123 + list = list.first(5)
  1124 + link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => current_user.login)
  1125 + end
  1126 + link = list.map do |element|
  1127 + link_to(content_tag('strong', [_('<span>Manage</span> %s') % element.short_name(25)]), @environment.top_url + "/myprofile/#{element.identifier}", :class => "icon-menu-"+element.class.identification.underscore, :title => [_('Manage %s') % element.short_name])
1120 end 1128 end
1121 - render :partial => 'shared/manage_enterprises', :locals => {:enterprises_link => enterprises_link} 1129 + if link_to_all
  1130 + link << link_to_all
  1131 + end
  1132 + render :partial => "shared/manage_link", :locals => {:link => link, :kind => kind.to_s}
1122 end 1133 end
1123 end 1134 end
1124 1135
  1136 + def manage_enterprises
  1137 + return unless user && user.environment.enabled?(:display_my_enterprises_on_user_menu)
  1138 + manage_link(user.enterprises, :enterprises)
  1139 + end
  1140 +
  1141 + def manage_communities
  1142 + return unless user && user.environment.enabled?(:display_my_communities_on_user_menu)
  1143 + administered_communities = user.communities.more_popular.select {|c| c.admins.include? user}
  1144 + manage_link(administered_communities, :communities)
  1145 + end
  1146 +
1125 def usermenu_logged_in 1147 def usermenu_logged_in
1126 pending_tasks_count = '' 1148 pending_tasks_count = ''
1127 count = user ? Task.to(user).pending.count : -1 1149 count = user ? Task.to(user).pending.count : -1
@@ -1133,6 +1155,7 @@ module ApplicationHelper @@ -1133,6 +1155,7 @@ module ApplicationHelper
1133 render_environment_features(:usermenu) + 1155 render_environment_features(:usermenu) +
1134 link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') + 1156 link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +
1135 manage_enterprises.to_s + 1157 manage_enterprises.to_s +
  1158 + manage_communities.to_s +
1136 link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) + 1159 link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) +
1137 pending_tasks_count + 1160 pending_tasks_count +
1138 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) 1161 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
@@ -1401,7 +1424,7 @@ module ApplicationHelper @@ -1401,7 +1424,7 @@ module ApplicationHelper
1401 end 1424 end
1402 1425
1403 def filter_html(html, source) 1426 def filter_html(html, source)
1404 - if @plugins 1427 + if @plugins && source.has_macro?
1405 html = convert_macro(html, source) 1428 html = convert_macro(html, source)
1406 #TODO This parse should be done through the macro infra, but since there 1429 #TODO This parse should be done through the macro infra, but since there
1407 # are old things that do not support it we are keeping this hot spot. 1430 # are old things that do not support it we are keeping this hot spot.
app/helpers/blog_helper.rb
@@ -42,7 +42,7 @@ module BlogHelper @@ -42,7 +42,7 @@ module BlogHelper
42 42
43 def display_post(article, format = 'full') 43 def display_post(article, format = 'full')
44 no_comments = (format == 'full') ? false : true 44 no_comments = (format == 'full') ? false : true
45 - html = send("display_#{format}_format", article).html_safe 45 + html = send("display_#{format}_format", FilePresenter.for(article)).html_safe
46 46
47 article_title(article, :no_comments => no_comments) + html 47 article_title(article, :no_comments => no_comments) + html
48 end 48 end
app/helpers/boxes_helper.rb
@@ -100,9 +100,7 @@ module BoxesHelper @@ -100,9 +100,7 @@ module BoxesHelper
100 options[:title] = _("This block is invisible. Your visitors will not see it.") 100 options[:title] = _("This block is invisible. Your visitors will not see it.")
101 end 101 end
102 102
103 - if @controller.send(:content_editor?)  
104 - result = filter_html(result, block)  
105 - end 103 + result = filter_html(result, block)
106 104
107 box_decorator.block_target(block.box, block) + 105 box_decorator.block_target(block.box, block) +
108 content_tag('div', 106 content_tag('div',
app/helpers/categories_helper.rb
@@ -3,10 +3,21 @@ module CategoriesHelper @@ -3,10 +3,21 @@ module CategoriesHelper
3 3
4 COLORS = [ 4 COLORS = [
5 [ N_('Do not display at the menu'), nil ], 5 [ N_('Do not display at the menu'), nil ],
6 - [ N_('Orange'), 1 ],  
7 - [ N_('Green'), 2 ],  
8 - [ N_('Purple'), 3 ],  
9 - [ N_('Red'), 4 ], 6 + [ N_('Orange'), 1],
  7 + [ N_('Green'), 2],
  8 + [ N_('Purple'), 3],
  9 + [ N_('Red'), 4],
  10 + [ N_('Dark Green'), 5],
  11 + [ N_('Blue Oil'), 6],
  12 + [ N_('Blue'), 7],
  13 + [ N_('Brown'), 8],
  14 + [ N_('Light Green'), 9],
  15 + [ N_('Light Blue'), 10],
  16 + [ N_('Dark Blue'), 11],
  17 + [ N_('Blue Pool'), 12],
  18 + [ N_('Beige'), 13],
  19 + [ N_('Yellow'), 14],
  20 + [ N_('Light Brown'), 15]
10 ] 21 ]
11 22
12 TYPES = [ 23 TYPES = [
app/helpers/cms_helper.rb
@@ -33,7 +33,7 @@ module CmsHelper @@ -33,7 +33,7 @@ module CmsHelper
33 link_to article_name, {:action => 'view', :id => article.id}, :class => icon_for_article(article) 33 link_to article_name, {:action => 'view', :id => article.id}, :class => icon_for_article(article)
34 else 34 else
35 if article.image? 35 if article.image?
36 - image_tag(icon_for_article(article)) + link_to(article_name, article.url) 36 + image_tag(icon_for_article(article)) + link_to(article_name, article.url)
37 else 37 else
38 link_to article_name, article.url, :class => icon_for_article(article) 38 link_to article_name, article.url, :class => icon_for_article(article)
39 end 39 end
app/helpers/content_viewer_helper.rb
@@ -17,7 +17,7 @@ module ContentViewerHelper @@ -17,7 +17,7 @@ module ContentViewerHelper
17 title = article.display_title if article.kind_of?(UploadedFile) && article.image? 17 title = article.display_title if article.kind_of?(UploadedFile) && article.image?
18 title = article.title if title.blank? 18 title = article.title if title.blank?
19 title = content_tag('h1', h(title), :class => 'title') 19 title = content_tag('h1', h(title), :class => 'title')
20 - if article.belongs_to_blog? 20 + if article.belongs_to_blog? || article.belongs_to_forum?
21 unless args[:no_link] 21 unless args[:no_link]
22 title = content_tag('h1', link_to(article.name, article.url), :class => 'title') 22 title = content_tag('h1', link_to(article.name, article.url), :class => 'title')
23 end 23 end
app/helpers/folder_helper.rb
@@ -21,6 +21,7 @@ module FolderHelper @@ -21,6 +21,7 @@ module FolderHelper
21 end 21 end
22 22
23 def display_article_in_listing(article, recursive = false, level = 0) 23 def display_article_in_listing(article, recursive = false, level = 0)
  24 + article = FilePresenter.for article
24 article_link = if article.image? 25 article_link = if article.image?
25 link_to('&nbsp;' * (level * 4) + image_tag(icon_for_article(article)) + short_filename(article.name), article.url.merge(:view => true)) 26 link_to('&nbsp;' * (level * 4) + image_tag(icon_for_article(article)) + short_filename(article.name), article.url.merge(:view => true))
26 else 27 else
@@ -40,12 +41,15 @@ module FolderHelper @@ -40,12 +41,15 @@ module FolderHelper
40 end 41 end
41 42
42 def icon_for_article(article) 43 def icon_for_article(article)
43 - icon = article.class.icon_name(article) 44 + article = FilePresenter.for article
  45 + icon = article.respond_to?(:icon_name) ?
  46 + article.icon_name :
  47 + article.class.icon_name(article)
44 if (icon =~ /\//) 48 if (icon =~ /\//)
45 icon 49 icon
46 else 50 else
47 - klasses = 'icon icon-' + icon  
48 - if article.kind_of?(UploadedFile) 51 + klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ')
  52 + if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter)
49 klasses += ' icon-upload-file' 53 klasses += ' icon-upload-file'
50 end 54 end
51 klasses 55 klasses
app/helpers/sweeper_helper.rb
@@ -44,4 +44,30 @@ module SweeperHelper @@ -44,4 +44,30 @@ module SweeperHelper
44 def expire_profile_index(profile) 44 def expire_profile_index(profile)
45 expire_timeout_fragment(profile.relationships_cache_key) 45 expire_timeout_fragment(profile.relationships_cache_key)
46 end 46 end
  47 +
  48 + def expire_blocks_cache(context, causes)
  49 + if context.kind_of?(Profile)
  50 + profile = context
  51 + environment = profile.environment
  52 + else
  53 + environment = context
  54 + profile = nil
  55 + end
  56 +
  57 + blocks_to_expire = []
  58 + if profile
  59 + profile.blocks.each {|block|
  60 + conditions = block.class.expire_on
  61 + blocks_to_expire << block unless (conditions[:profile] & causes).empty?
  62 + }
  63 + end
  64 + environment.blocks.each {|block|
  65 + conditions = block.class.expire_on
  66 + blocks_to_expire << block unless (conditions[:environment] & causes).empty?
  67 + }
  68 +
  69 + blocks_to_expire.uniq!
  70 + BlockSweeper.expire_blocks(blocks_to_expire)
  71 + end
  72 +
47 end 73 end
app/models/article.rb
@@ -156,8 +156,12 @@ class Article &lt; ActiveRecord::Base @@ -156,8 +156,12 @@ class Article &lt; ActiveRecord::Base
156 end 156 end
157 end 157 end
158 158
  159 + def css_class_list
  160 + [self.class.name.underscore.dasherize]
  161 + end
  162 +
159 def css_class_name 163 def css_class_name
160 - self.class.name.underscore.dasherize 164 + [css_class_list].flatten.compact.join(' ')
161 end 165 end
162 166
163 def pending_categorizations 167 def pending_categorizations
@@ -312,6 +316,10 @@ class Article &lt; ActiveRecord::Base @@ -312,6 +316,10 @@ class Article &lt; ActiveRecord::Base
312 def belongs_to_blog? 316 def belongs_to_blog?
313 self.parent and self.parent.blog? 317 self.parent and self.parent.blog?
314 end 318 end
  319 +
  320 + def belongs_to_forum?
  321 + self.parent and self.parent.forum?
  322 + end
315 323
316 def info_from_last_update 324 def info_from_last_update
317 last_comment = comments.last 325 last_comment = comments.last
@@ -327,7 +335,7 @@ class Article &lt; ActiveRecord::Base @@ -327,7 +335,7 @@ class Article &lt; ActiveRecord::Base
327 end 335 end
328 336
329 def view_url 337 def view_url
330 - @view_url ||= image? ? url.merge(:view => true) : url 338 + @view_url ||= is_a?(UploadedFile) ? url.merge(:view => true) : url
331 end 339 end
332 340
333 def comment_url_structure(comment, action = :edit) 341 def comment_url_structure(comment, action = :edit)
@@ -675,6 +683,10 @@ class Article &lt; ActiveRecord::Base @@ -675,6 +683,10 @@ class Article &lt; ActiveRecord::Base
675 683
676 delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true 684 delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
677 685
  686 + def has_macro?
  687 + true
  688 + end
  689 +
678 private 690 private
679 691
680 def sanitize_tag_list 692 def sanitize_tag_list
app/models/article_block.rb
@@ -12,7 +12,7 @@ class ArticleBlock &lt; Block @@ -12,7 +12,7 @@ class ArticleBlock &lt; Block
12 block = self 12 block = self
13 lambda do 13 lambda do
14 block_title(block.title) + 14 block_title(block.title) +
15 - (block.article ? article_to_html(block.article, 15 + (block.article ? article_to_html(FilePresenter.for(block.article),
16 :gallery_view => false, 16 :gallery_view => false,
17 :inside_block => block, # For Blogs and folders 17 :inside_block => block, # For Blogs and folders
18 :format => block.visualization_format # For Articles and contents 18 :format => block.visualization_format # For Articles and contents
@@ -23,7 +23,7 @@ class ArticleBlock &lt; Block @@ -23,7 +23,7 @@ class ArticleBlock &lt; Block
23 def article_id 23 def article_id
24 self.settings[:article_id] 24 self.settings[:article_id]
25 end 25 end
26 - 26 +
27 def article_id= value 27 def article_id= value
28 self.settings[:article_id] = value.blank? ? nil : value.to_i 28 self.settings[:article_id] = value.blank? ? nil : value.to_i
29 end 29 end
@@ -63,4 +63,9 @@ class ArticleBlock &lt; Block @@ -63,4 +63,9 @@ class ArticleBlock &lt; Block
63 end 63 end
64 64
65 settings_items :visualization_format, :type => :string, :default => 'short' 65 settings_items :visualization_format, :type => :string, :default => 'short'
  66 +
  67 + def self.expire_on
  68 + { :profile => [:article], :environment => [:article] }
  69 + end
  70 +
66 end 71 end
app/models/block.rb
@@ -138,4 +138,19 @@ class Block &lt; ActiveRecord::Base @@ -138,4 +138,19 @@ class Block &lt; ActiveRecord::Base
138 4.hours 138 4.hours
139 end 139 end
140 140
  141 + def has_macro?
  142 + false
  143 + end
  144 +
  145 + # Override in your subclasses.
  146 + # Define which events and context should cause the block cache to expire
  147 + # Possible events are: :article, :profile, :friendship, :category
  148 + # Possible contexts are: :profile, :environment
  149 + def self.expire_on
  150 + {
  151 + :profile => [],
  152 + :environment => []
  153 + }
  154 + end
  155 +
141 end 156 end
app/models/blog_archives_block.rb
@@ -45,4 +45,7 @@ class BlogArchivesBlock &lt; Block @@ -45,4 +45,7 @@ class BlogArchivesBlock &lt; Block
45 content_tag('div', link_to(_('Subscribe RSS Feed'), owner_blog.feed.url), :class => 'subscribe-feed') 45 content_tag('div', link_to(_('Subscribe RSS Feed'), owner_blog.feed.url), :class => 'subscribe-feed')
46 end 46 end
47 47
  48 + def self.expire_on
  49 + { :profile => [:article], :environment => [:article] }
  50 + end
48 end 51 end
app/models/categories_block.rb
@@ -35,4 +35,7 @@ class CategoriesBlock &lt; Block @@ -35,4 +35,7 @@ class CategoriesBlock &lt; Block
35 end 35 end
36 end 36 end
37 37
  38 + def self.expire_on
  39 + { :profile => [], :environment => [:category] }
  40 + end
38 end 41 end
app/models/category.rb
@@ -12,7 +12,7 @@ class Category &lt; ActiveRecord::Base @@ -12,7 +12,7 @@ class Category &lt; ActiveRecord::Base
12 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n 12 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n
13 belongs_to :environment 13 belongs_to :environment
14 14
15 - validates_inclusion_of :display_color, :in => [ 1, 2, 3, 4, nil ] 15 + validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true
16 validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('%{fn} was already assigned to another category.').fix_i18n 16 validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('%{fn} was already assigned to another category.').fix_i18n
17 17
18 # Finds all top level categories for a given environment. 18 # Finds all top level categories for a given environment.
app/models/comment.rb
@@ -16,9 +16,7 @@ class Comment &lt; ActiveRecord::Base @@ -16,9 +16,7 @@ class Comment &lt; ActiveRecord::Base
16 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy 16 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
17 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id' 17 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id'
18 18
19 - named_scope :without_spam, :conditions => ['spam IS NULL OR spam = ?', false]  
20 named_scope :without_reply, :conditions => ['reply_of_id IS NULL'] 19 named_scope :without_reply, :conditions => ['reply_of_id IS NULL']
21 - named_scope :spam, :conditions => ['spam = ?', true]  
22 20
23 # unauthenticated authors: 21 # unauthenticated authors:
24 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) 22 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? })
@@ -108,6 +106,17 @@ class Comment &lt; ActiveRecord::Base @@ -108,6 +106,17 @@ class Comment &lt; ActiveRecord::Base
108 106
109 include Noosfero::Plugin::HotSpot 107 include Noosfero::Plugin::HotSpot
110 108
  109 + include Spammable
  110 +
  111 + def after_spam!
  112 + SpammerLogger.log(ip_address, self)
  113 + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam))
  114 + end
  115 +
  116 + def after_ham!
  117 + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham))
  118 + end
  119 +
111 def verify_and_notify 120 def verify_and_notify
112 check_for_spam 121 check_for_spam
113 unless spam? 122 unless spam?
@@ -115,10 +124,6 @@ class Comment &lt; ActiveRecord::Base @@ -115,10 +124,6 @@ class Comment &lt; ActiveRecord::Base
115 end 124 end
116 end 125 end
117 126
118 - def check_for_spam  
119 - plugins.dispatch(:check_comment_for_spam, self)  
120 - end  
121 -  
122 def notify_by_mail 127 def notify_by_mail
123 if source.kind_of?(Article) && article.notify_comments? 128 if source.kind_of?(Article) && article.notify_comments?
124 if !notification_emails.empty? 129 if !notification_emails.empty?
@@ -205,37 +210,6 @@ class Comment &lt; ActiveRecord::Base @@ -205,37 +210,6 @@ class Comment &lt; ActiveRecord::Base
205 @rejected = true 210 @rejected = true
206 end 211 end
207 212
208 - def spam?  
209 - !spam.nil? && spam  
210 - end  
211 -  
212 - def ham?  
213 - !spam.nil? && !spam  
214 - end  
215 -  
216 - def spam!  
217 - self.spam = true  
218 - self.save!  
219 - SpammerLogger.log(ip_address, self)  
220 - Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam))  
221 - self  
222 - end  
223 -  
224 - def ham!  
225 - self.spam = false  
226 - self.save!  
227 - Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham))  
228 - self  
229 - end  
230 -  
231 - def marked_as_spam  
232 - plugins.dispatch(:comment_marked_as_spam, self)  
233 - end  
234 -  
235 - def marked_as_ham  
236 - plugins.dispatch(:comment_marked_as_ham, self)  
237 - end  
238 -  
239 def need_moderation? 213 def need_moderation?
240 article.moderate_comments? && (author.nil? || article.author != author) 214 article.moderate_comments? && (author.nil? || article.author != author)
241 end 215 end
app/models/environment.rb
@@ -127,7 +127,9 @@ class Environment &lt; ActiveRecord::Base @@ -127,7 +127,9 @@ class Environment &lt; ActiveRecord::Base
127 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'), 127 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'),
128 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'), 128 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'),
129 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'), 129 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
130 - 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login') 130 + 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'),
  131 + 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'),
  132 + 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage')
131 } 133 }
132 end 134 end
133 135
app/models/link_list_block.rb
@@ -33,6 +33,12 @@ class LinkListBlock &lt; Block @@ -33,6 +33,12 @@ class LinkListBlock &lt; Block
33 ['chat', N_('Chat')] 33 ['chat', N_('Chat')]
34 ] 34 ]
35 35
  36 + TARGET_OPTIONS = [
  37 + [N_('Same page'), '_self'],
  38 + [N_('New tab'), '_blank'],
  39 + [N_('New window'), '_new'],
  40 + ]
  41 +
36 settings_items :links, Array, :default => [] 42 settings_items :links, Array, :default => []
37 43
38 before_save do |block| 44 before_save do |block|
@@ -57,7 +63,7 @@ class LinkListBlock &lt; Block @@ -57,7 +63,7 @@ class LinkListBlock &lt; Block
57 def link_html(link) 63 def link_html(link)
58 klass = 'icon-' + link[:icon] if link[:icon] 64 klass = 'icon-' + link[:icon] if link[:icon]
59 sanitize_link( 65 sanitize_link(
60 - link_to(link[:name], expand_address(link[:address]), :class => klass) 66 + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass)
61 ) 67 )
62 end 68 end
63 69
app/models/raw_html_block.rb
@@ -10,4 +10,7 @@ class RawHTMLBlock &lt; Block @@ -10,4 +10,7 @@ class RawHTMLBlock &lt; Block
10 (title.blank? ? '' : block_title(title)).html_safe + html.to_s.html_safe 10 (title.blank? ? '' : block_title(title)).html_safe + html.to_s.html_safe
11 end 11 end
12 12
  13 + def has_macro?
  14 + true
  15 + end
13 end 16 end
app/models/recent_documents_block.rb
@@ -30,4 +30,7 @@ class RecentDocumentsBlock &lt; Block @@ -30,4 +30,7 @@ class RecentDocumentsBlock &lt; Block
30 end 30 end
31 end 31 end
32 32
  33 + def self.expire_on
  34 + { :profile => [:article], :environment => [:article] }
  35 + end
33 end 36 end
app/models/spammer_logger.rb
@@ -6,6 +6,8 @@ class SpammerLogger &lt; Logger @@ -6,6 +6,8 @@ class SpammerLogger &lt; Logger
6 if object 6 if object
7 if object.kind_of?(Comment) 7 if object.kind_of?(Comment)
8 @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n" 8 @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n"
  9 + elsif object.kind_of?(SuggestArticle)
  10 + @logger << "[#{Time.now.strftime('%F %T %z')}] SuggestArticle-id: #{object.id} IP: #{spammer_ip}\n"
9 end 11 end
10 else 12 else
11 @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n" 13 @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n"
app/models/suggest_article.rb
@@ -11,6 +11,17 @@ class SuggestArticle &lt; Task @@ -11,6 +11,17 @@ class SuggestArticle &lt; Task
11 settings_items :source, :type => String 11 settings_items :source, :type => String
12 settings_items :source_name, :type => String 12 settings_items :source_name, :type => String
13 settings_items :highlighted, :type => :boolean, :default => false 13 settings_items :highlighted, :type => :boolean, :default => false
  14 + settings_items :ip_address, :type => String
  15 + settings_items :user_agent, :type => String
  16 + settings_items :referrer, :type => String
  17 +
  18 + after_create :schedule_spam_checking
  19 +
  20 + def schedule_spam_checking
  21 + self.delay.check_for_spam
  22 + end
  23 +
  24 + include Noosfero::Plugin::HotSpot
14 25
15 def sender 26 def sender
16 "#{name} (#{email})" 27 "#{name} (#{email})"
@@ -61,4 +72,12 @@ class SuggestArticle &lt; Task @@ -61,4 +72,12 @@ class SuggestArticle &lt; Task
61 _('You need to login on %{system} in order to approve or reject this article.') % { :system => target.environment.name } 72 _('You need to login on %{system} in order to approve or reject this article.') % { :system => target.environment.name }
62 end 73 end
63 74
  75 + def after_spam!
  76 + SpammerLogger.log(ip_address, self)
  77 + self.delay.marked_as_spam
  78 + end
  79 +
  80 + def after_ham!
  81 + self.delay.marked_as_ham
  82 + end
64 end 83 end
app/models/tags_block.rb
@@ -59,4 +59,8 @@ class TagsBlock &lt; Block @@ -59,4 +59,8 @@ class TagsBlock &lt; Block
59 15.minutes 59 15.minutes
60 end 60 end
61 61
  62 + def self.expire_on
  63 + { :profile => [:article], :environment => [:article] }
  64 + end
  65 +
62 end 66 end
app/models/task.rb
@@ -235,6 +235,8 @@ class Task &lt; ActiveRecord::Base @@ -235,6 +235,8 @@ class Task &lt; ActiveRecord::Base
235 end 235 end
236 end 236 end
237 237
  238 + include Spammable
  239 +
238 protected 240 protected
239 241
240 # This method must be overrided in subclasses, and its implementation must do 242 # This method must be overrided in subclasses, and its implementation must do
@@ -275,6 +277,7 @@ class Task &lt; ActiveRecord::Base @@ -275,6 +277,7 @@ class Task &lt; ActiveRecord::Base
275 named_scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} } 277 named_scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} }
276 named_scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} } 278 named_scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} }
277 279
  280 +
278 named_scope :to, lambda { |profile| 281 named_scope :to, lambda { |profile|
279 environment_condition = nil 282 environment_condition = nil
280 if profile.person? 283 if profile.person?
app/models/uploaded_file.rb
@@ -41,7 +41,25 @@ class UploadedFile &lt; Article @@ -41,7 +41,25 @@ class UploadedFile &lt; Article
41 end 41 end
42 42
43 def self.max_size 43 def self.max_size
44 - UploadedFile.attachment_options[:max_size] 44 + default = 5.megabytes
  45 +
  46 + multipliers = {
  47 + :KB => :kilobytes,
  48 + :MB => :megabytes,
  49 + :GB => :gigabytes,
  50 + :TB => :terabytes,
  51 + }
  52 + max_upload_size = NOOSFERO_CONF['max_upload_size']
  53 +
  54 + if max_upload_size =~ /^(\d+(\.\d+)?)\s*(KB|MB|GB|TB)?$/
  55 + number = $1.to_f
  56 + unit = $3 || :MB
  57 + multiplier = multipliers[unit.to_sym]
  58 +
  59 + number.send(multiplier).to_i
  60 + else
  61 + default
  62 + end
45 end 63 end
46 64
47 # FIXME need to define min/max file size 65 # FIXME need to define min/max file size
@@ -52,20 +70,28 @@ class UploadedFile &lt; Article @@ -52,20 +70,28 @@ class UploadedFile &lt; Article
52 has_attachment :storage => :file_system, 70 has_attachment :storage => :file_system,
53 :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' }, 71 :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
54 :thumbnail_class => Thumbnail, 72 :thumbnail_class => Thumbnail,
55 - :max_size => 5.megabytes # remember to update validate message below 73 + :max_size => self.max_size
56 74
57 - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n 75 + validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n
58 76
59 delay_attachment_fu_thumbnails 77 delay_attachment_fu_thumbnails
60 78
61 postgresql_attachment_fu 79 postgresql_attachment_fu
62 80
  81 + # Use this method only to get the generic icon for this kind of content.
  82 + # If you want the specific icon for a file type or the iconified version
  83 + # of an image, use FilePresenter.for(uploaded_file).icon_name
63 def self.icon_name(article = nil) 84 def self.icon_name(article = nil)
64 - if article  
65 - article.image? ? article.public_filename(:icon) : (article.mime_type ? article.mime_type.gsub(/[\/+.]/, '-') : 'upload-file')  
66 - else  
67 - 'upload-file' 85 + unless article.nil?
  86 + warn = ('='*80) + "\n" +
  87 + 'The method `UploadedFile.icon_name(obj)` is deprecated. ' +
  88 + 'You must to encapsulate UploadedFile with `FilePresenter.for()`.' +
  89 + "\n" + ('='*80)
  90 + raise NoMethodError, warn if ENV['RAILS_ENV'] == 'test'
  91 + Rails.logger.warn warn if Rails.logger
  92 + puts warn if ENV['RAILS_ENV'] == 'development'
68 end 93 end
  94 + 'upload-file'
69 end 95 end
70 96
71 def mime_type 97 def mime_type
@@ -91,40 +117,27 @@ class UploadedFile &lt; Article @@ -91,40 +117,27 @@ class UploadedFile &lt; Article
91 end 117 end
92 118
93 def to_html(options = {}) 119 def to_html(options = {})
  120 + warn = ('='*80) + "\n" +
  121 + 'The method `UploadedFile#to_html()` is deprecated. ' +
  122 + 'You must to encapsulate UploadedFile with `FilePresenter.for()`.' +
  123 + "\n" + ('='*80)
  124 + raise NoMethodError, warn if ENV['RAILS_ENV'] == 'test'
  125 + Rails.logger.warn warn if Rails.logger
  126 + puts warn if ENV['RAILS_ENV'] == 'development'
94 article = self 127 article = self
95 if image? 128 if image?
96 lambda do 129 lambda do
97 - if article.gallery? && options[:gallery_view]  
98 - images = article.parent.images  
99 - current_index = images.index(article)  
100 - total_of_images = images.count  
101 -  
102 - link_to_previous = if current_index >= 1  
103 - link_to(_('&laquo; Previous'), images[current_index - 1].view_url, :class => 'left')  
104 - else  
105 - content_tag('span', _('&laquo; Previous'), :class => 'left')  
106 - end  
107 -  
108 - link_to_next = if current_index < total_of_images - 1  
109 - link_to(_('Next &raquo;'), images[current_index + 1].view_url, :class => 'right')  
110 - else  
111 - content_tag('span', _('Next &raquo;'), :class => 'right')  
112 - end  
113 -  
114 - content_tag(  
115 - 'div',  
116 - link_to_previous + (content_tag('span', _('image %d of %d'), :class => 'total-of-images') % [current_index + 1, total_of_images]).html_safe + link_to_next,  
117 - :class => 'gallery-navigation'  
118 - )  
119 - end.to_s +  
120 - image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') +  
121 - content_tag('p', article.abstract, :class => 'uploaded-file-description')  
122 - 130 + image_tag(article.public_filename(:display),
  131 + :class => article.css_class_name,
  132 + :style => 'max-width: 100%') +
  133 + content_tag('div', article.abstract, :class => 'uploaded-file-description')
123 end 134 end
124 else 135 else
125 lambda do 136 lambda do
126 - content_tag('ul', content_tag('li', link_to(article.name, article.url, :class => article.css_class_name))) +  
127 - content_tag('p', article.abstract, :class => 'uploaded-file-description') 137 + content_tag('div',
  138 + link_to(article.name, article.url),
  139 + :class => article.css_class_name) +
  140 + content_tag('div', article.abstract, :class => 'uploaded-file-description')
128 end 141 end
129 end 142 end
130 end 143 end
app/presenters/generic.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +# Made to encapsulate any UploadedFile
  2 +class FilePresenter::Generic < FilePresenter
  3 + # if returns low priority, because it is generic.
  4 + def self.accepts?(f)
  5 + 1 if f.is_a? UploadedFile
  6 + end
  7 +end
app/presenters/image.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class FilePresenter::Image < FilePresenter
  2 + def self.accepts?(f)
  3 + return nil unless f.respond_to? :image?
  4 + f.image? ? 10 : nil
  5 + end
  6 +
  7 + def icon_name
  8 + public_filename :icon
  9 + end
  10 +
  11 + def short_description
  12 + _('Image (%s)') % content_type.split('/')[1].upcase
  13 + end
  14 +end
app/sweepers/article_sweeper.rb
@@ -16,15 +16,15 @@ class ArticleSweeper &lt; ActiveRecord::Observer @@ -16,15 +16,15 @@ class ArticleSweeper &lt; ActiveRecord::Observer
16 end 16 end
17 end 17 end
18 18
  19 +
19 protected 20 protected
20 21
21 def expire_caches(article) 22 def expire_caches(article)
  23 + expire_blocks_cache(article.profile, [:article])
  24 +
22 return if !article.environment 25 return if !article.environment
  26 +
23 article.hierarchy(true).each { |a| a.touch if a != article } 27 article.hierarchy(true).each { |a| a.touch if a != article }
24 - blocks = article.profile.blocks  
25 - blocks += article.profile.environment.blocks if article.profile.environment  
26 - blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}}  
27 - BlockSweeper.expire_blocks(blocks)  
28 env = article.profile.environment 28 env = article.profile.environment
29 if env && (env.portal_community == article.profile) 29 if env && (env.portal_community == article.profile)
30 article.environment.locales.keys.each do |locale| 30 article.environment.locales.keys.each do |locale|
app/sweepers/category_sweeper.rb
@@ -3,7 +3,13 @@ class CategorySweeper &lt; ActiveRecord::Observer @@ -3,7 +3,13 @@ class CategorySweeper &lt; ActiveRecord::Observer
3 include SweeperHelper 3 include SweeperHelper
4 4
5 def after_save(category) 5 def after_save(category)
  6 + expire_blocks_cache(category.environment, [:category])
  7 +
  8 + # Needed for environments with application layout
6 expire_fragment(category.environment.id.to_s + "_categories_menu") 9 expire_fragment(category.environment.id.to_s + "_categories_menu")
7 end 10 end
8 11
  12 + def after_destroy(category)
  13 + expire_blocks_cache(category.environment, [:category])
  14 + end
9 end 15 end
app/views/box_organizer/_link_list_block.rhtml
1 <strong><%= _('Links') %></strong> 1 <strong><%= _('Links') %></strong>
2 <div id='edit-link-list-block' style='width:450px'> 2 <div id='edit-link-list-block' style='width:450px'>
3 <table id='links' class='noborder'> 3 <table id='links' class='noborder'>
4 - <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr> 4 + <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th><th><%= _('Target') %></th></tr>
5 <% for link in @block.links do %> 5 <% for link in @block.links do %>
6 <tr> 6 <tr>
7 <td> 7 <td>
@@ -9,6 +9,9 @@ @@ -9,6 +9,9 @@
9 </td> 9 </td>
10 <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td> 10 <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td>
11 <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td> 11 <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td>
  12 + <td>
  13 + <%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %>
  14 + </td>
12 </tr> 15 </tr>
13 <% end %> 16 <% end %>
14 </table> 17 </table>
@@ -18,7 +21,9 @@ @@ -18,7 +21,9 @@
18 page.insert_html :bottom, 'links', content_tag('tr', 21 page.insert_html :bottom, 'links', content_tag('tr',
19 content_tag('td', icon_selector('ok')) + 22 content_tag('td', icon_selector('ok')) +
20 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) + 23 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
21 - content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'cel-address')) 24 + content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') +
  25 + content_tag('td', select_tag('block[links][][target]',
  26 +options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])))
22 ) + 27 ) +
23 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight") 28 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")
24 end %> 29 end %>
app/views/cms/view.rhtml
@@ -40,13 +40,16 @@ @@ -40,13 +40,16 @@
40 </tr> 40 </tr>
41 <% end %> 41 <% end %>
42 42
43 - <% @articles.each do |article| %> 43 + <% @articles.each do |article| article = FilePresenter.for article %>
44 <tr title="<%= article.title%>" > 44 <tr title="<%= article.title%>" >
45 - <td> 45 + <td class="article-name">
46 <%= link_to_article(article) %> 46 <%= link_to_article(article) %>
47 </td> 47 </td>
48 - <td>  
49 - <%= article.class.short_description %> 48 + <% short_description = article.respond_to?(:short_description) ?
  49 + article.short_description :
  50 + article.class.short_description %>
  51 + <td class="article-mime" title=<%= short_description.to_json %>>
  52 + <%= short_description %>
50 </td> 53 </td>
51 <td class="article-controls"> 54 <td class="article-controls">
52 <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %> 55 <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %>
app/views/file_presenter/_generic.html.erb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<span class="download-link">
  2 + <span>Download</span>
  3 + <strong><%= link_to generic.filename, generic.public_filename %></strong>
  4 +</span>
  5 +
  6 +<div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>">
  7 + <%= generic.abstract %>
  8 +</div>
  9 +
app/views/file_presenter/_image.html.erb 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +<% if image.gallery? && options[:gallery_view] %>
  2 +<%
  3 + images = image.parent.images
  4 + current_index = images.index(image.encapsulated_file)
  5 + total_of_images = images.count
  6 + link_to_previous = if current_index >= 1
  7 + link_to(_('&laquo; Previous'), images[current_index - 1].view_url, :class => 'previous')
  8 + else
  9 + content_tag('span', _('&laquo; Previous'), :class => 'previous')
  10 + end
  11 +
  12 + link_to_next = if current_index < total_of_images - 1
  13 + link_to(_('Next &raquo;'), images[current_index + 1].view_url, :class => 'next')
  14 + else
  15 + content_tag('span', _('Next &raquo;'), :class => 'next')
  16 + end
  17 +%>
  18 +
  19 +<div class="gallery-navigation">
  20 + <%= link_to_previous %>
  21 + <span class="total-of-images">
  22 + <%= _('image %d of %d') % [current_index + 1, total_of_images] %>
  23 + </span>
  24 + <%= link_to_next %>
  25 +</div>
  26 +
  27 +<% end %>
  28 +
  29 +<%# image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') %>
  30 +
  31 +<img src="<%=image.public_filename(:display)%>" class="<%=image.css_class_name%>">
  32 +
  33 +<div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>">
  34 + <%= image.abstract %>
  35 +</div>
  36 +
app/views/memberships/new_community.rhtml
@@ -46,9 +46,11 @@ @@ -46,9 +46,11 @@
46 46
47 <%= template_options(Community, 'community')%> 47 <%= template_options(Community, 'community')%>
48 48
  49 + <%= hidden_field_tag('back_to', @back_to) %>
  50 +
49 <% button_bar do %> 51 <% button_bar do %>
50 <%= submit_button(:save, _('Create')) %> 52 <%= submit_button(:save, _('Create')) %>
51 - <%= button(:cancel, _('Cancel'), :action => 'index') %> 53 + <%= button(:cancel, _('Cancel'), @back_to ) %>
52 <% end %> 54 <% end %>
53 55
54 <% end %> 56 <% end %>
app/views/shared/_manage_enterprises.rhtml
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -<div id='manage-enterprises'>  
2 - <a href="#" id='manage-enterprises-link' class='simplemenu-trigger' title='<%= _('Manage enterprises') %>'><i class="icon-menu-enterprise"></i><strong><%= ui_icon('ui-icon-triangle-1-s') + _('My enterprises') %></strong></a>  
3 - <ul class='simplemenu-submenu'>  
4 - <% enterprises_link.each do |link| %>  
5 - <li class='simplemenu-item'><%= link %></li>  
6 - <% end %>  
7 - </ul>  
8 -</div>  
app/views/shared/_manage_link.html.erb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<div id=<%= "manage-#{kind}" %> class="manage-groups">
  2 + <a href="#" id=<%= "manage-#{kind}-link" %> class="simplemenu-trigger" title="<%= _('Manage %s') % kind %>"><i class=<%= "icon-menu-#{kind.singularize}" %>></i><strong><%= ui_icon('ui-icon-triangle-1-s') + _('My %s') % kind %></strong></a>
  3 + <ul class="simplemenu-submenu">
  4 + <% link.each do |link| %>
  5 + <li class="simplemenu-item"><%= link %></li>
  6 + <% end %>
  7 + </ul>
  8 +</div>
app/views/spam/_comment_spam.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %>
  2 +<div id='article'>
  3 + <div class="comments" id="comments_list">
  4 + <ul class="article-comments-list">
  5 + <%= render :partial => 'comment/comment', :collection => @comment_spam %>
  6 + </ul>
  7 + </div>
  8 +</div>
  9 +
  10 +<%= pagination_links @comment_spam, :param_name => :comments_page %>
  11 +
app/views/spam/_suggest_article.html.erb 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<% render :layout => 'task', :locals => { :task => task } do %>
  2 + <% content_for :extra_buttons do %>
  3 + <%= button_to_function('down', _('Show details'), "toggleDetails(this, '#{_('Hide details')}', '#{_('Show details')}')" ) %>
  4 + <% end %>
  5 +
  6 + <% content_for :extra_content do %>
  7 + <ul class="suggest-article-details" style="display: none">
  8 + <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li>
  9 + <li><strong><%=_('Email')%></strong>: <%=task.email%> </li>
  10 + <li><strong><%=_('Source')%></strong>: <%=task.source_name%> </li>
  11 + <li><strong><%=_('Source URL')%></strong>: <%=task.source%> </li>
  12 + <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>
  13 + <li><strong><%=_('Lead')%></strong>: <%=task.article_abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_abstract%> </li>
  14 + <li><strong><%=_('Body')%></strong>:
  15 + <div class='suggest-article-body'>
  16 + <%= task.article_body %>
  17 + </div>
  18 + </li>
  19 + </ul>
  20 + <% end %>
  21 +<% end %>
app/views/spam/_task.rhtml 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<div class="task_box" id="task-<%= task.id %>">
  2 + <%= render :partial => 'tasks/task_icon', :locals => {:task => task} %>
  3 + <%= render :partial => 'tasks/task_title', :locals => {:task => task} %>
  4 + <div class="task-information">
  5 + <%= task_information(task) %>
  6 + </div>
  7 +
  8 + <%= yield %> <% # ??? %>
  9 +
  10 + <% button_bar do %>
  11 + <%= button_to_function('new', _('Mark as NOT SPAM'), 'removeTaskBox(this, %s, "%s", "")' % [url_for(:mark_task_as_ham => task.id).to_json, "task-#{task.id}"]) %>
  12 + <%= yield :extra_buttons %>
  13 + <%= button_to_function('delete', _('Remove'), 'removeTaskBox(this, %s, "%s", %s)' % [url_for(:profile => params[:profile], :remove_task => task.id).to_json, "task-#{task.id}", _('Are you sure you want to remove this article suggestion?').to_json]) %>
  14 +
  15 + <% end %>
  16 +
  17 + <%= yield :extra_content %>
  18 +</div>
app/views/spam/_task_spam.rhtml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<% @task_spam.each do |t| %>
  2 + <%= render :partial => partial_for_class(t.class), :locals => { :task => t } %>
  3 +<% end %>
  4 +<%= pagination_links @task_spam, :param_name => :tasks_page %>
app/views/spam/index.rhtml
  1 +<%= stylesheet('tasks') %>
  2 +
1 <h1><%= _('Manage SPAM') %></h1> 3 <h1><%= _('Manage SPAM') %></h1>
2 4
  5 +<% no_tabs = @comment_spam.blank? && @task_spam.blank? %>
  6 +
  7 +<%= _('There are no spams to review.') if no_tabs %>
  8 +
3 <% button_bar do %> 9 <% button_bar do %>
4 <%= button :back, _('Back to control panel'), :controller => :profile_editor %> 10 <%= button :back, _('Back to control panel'), :controller => :profile_editor %>
5 <% end %> 11 <% end %>
6 12
7 <%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %> 13 <%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %>
8 -<div id='article'>  
9 - <div class="comments" id="comments_list">  
10 - <ul class="article-comments-list">  
11 - <%= render :partial => 'comment/comment', :collection => @spam %>  
12 - </ul>  
13 - </div>  
14 -</div>  
15 14
16 -<%= pagination_links @spam %> 15 +<% tabs = [] %>
  16 +<% tabs << {:title => _('Comment Spam'), :id => 'comment-spam',
  17 + :content => (render :partial => 'comment_spam')} if @comment_spam.present? %>
  18 +<% tabs << {:title => _('Task Spam'), :id => 'task-spam',
  19 + :content => (render :partial => 'task_spam') } if @task_spam.present? %>
  20 +<%= render_tabs(tabs) %>
17 21
18 -<% button_bar do %>  
19 - <%= button :back, _('Back to control panel'), :controller => :profile_editor %> 22 +<% unless no_tabs %>
  23 + <% button_bar do %>
  24 + <%= button :back, _('Back to control panel'), :controller => :profile_editor %>
  25 + <% end %>
20 <% end %> 26 <% end %>
  27 +
  28 +<%= javascript_include_tag 'spam' %>
app/views/tasks/_task.rhtml
1 <div class="task_box" id="task-<%= task.id %>"> 1 <div class="task_box" id="task-<%= task.id %>">
2 2
3 - <div class="task_icon">  
4 - <%  
5 - icon_info = task.icon  
6 - if icon_info[:type] == :profile_image  
7 - icon = profile_image(icon_info[:profile], :minor)  
8 - elsif icon_info[:type] == :defined_image  
9 - icon = "<img src='#{icon_info[:src]}' alt='#{icon_info[:name]}' />"  
10 - end  
11 - %>  
12 - <%=  
13 - if icon_info[:url]  
14 - link_to(icon, icon_info[:url])  
15 - else  
16 - icon  
17 - end  
18 - %>  
19 -  
20 - </div> 3 + <%= render :partial => 'task_icon', :locals => {:task => task} %>
21 4
22 <div class="task_decisions"> 5 <div class="task_decisions">
23 <%= 6 <%=
@@ -39,9 +22,7 @@ @@ -39,9 +22,7 @@
39 %> 22 %>
40 </div><!-- class="task_decisions" --> 23 </div><!-- class="task_decisions" -->
41 24
42 - <strong class="task_title">  
43 - <%= task.title %>  
44 - </strong> 25 + <%= render :partial => 'task_title', :locals => {:task => task} %>
45 26
46 <div class="task_information"> 27 <div class="task_information">
47 <%= task_information(task) %> 28 <%= task_information(task) %>
app/views/tasks/_task_icon.rhtml 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +<%
  2 + icon_info = task.icon
  3 + if icon_info[:type] == :profile_image
  4 + icon = profile_image(icon_info[:profile], :minor)
  5 + elsif icon_info[:type] == :defined_image
  6 + icon = "<img src='#{icon_info[:src]}' alt='#{icon_info[:name]}' />"
  7 + end
  8 +
  9 + if icon_info[:url]
  10 + icon = link_to(icon, icon_info[:url])
  11 + end
  12 +%>
  13 +
  14 +<div class="task_icon">
  15 + <%= icon %>
  16 +</div>
app/views/tasks/_task_title.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<strong class="task_title">
  2 + <%= task.title %>
  3 +</strong>
config/initializers/plugins.rb
@@ -4,4 +4,5 @@ require &#39;noosfero/plugin/manager&#39; @@ -4,4 +4,5 @@ require &#39;noosfero/plugin/manager&#39;
4 require 'noosfero/plugin/active_record' 4 require 'noosfero/plugin/active_record'
5 require 'noosfero/plugin/mailer_base' 5 require 'noosfero/plugin/mailer_base'
6 require 'noosfero/plugin/settings' 6 require 'noosfero/plugin/settings'
  7 +require 'noosfero/plugin/spammable'
7 Noosfero::Plugin.init_system if $NOOSFERO_LOAD_PLUGINS 8 Noosfero::Plugin.init_system if $NOOSFERO_LOAD_PLUGINS
config/noosfero.yml.dist
@@ -8,6 +8,7 @@ development: @@ -8,6 +8,7 @@ development:
8 gravatar: wavatar 8 gravatar: wavatar
9 googlemaps_initial_zoom: 4 9 googlemaps_initial_zoom: 4
10 exception_recipients: [admin@example.com] 10 exception_recipients: [admin@example.com]
  11 + max_upload_size: 5MB
11 12
12 test: 13 test:
13 14
db/migrate/20131011164400_add_spam_to_task.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class AddSpamToTask < ActiveRecord::Migration
  2 + def self.up
  3 + change_table :tasks do |t|
  4 + t.boolean :spam, :default => false
  5 + end
  6 + Task.update_all ["spam = ?", false]
  7 + add_index :tasks, [:spam]
  8 + end
  9 +
  10 + def self.down
  11 + remove_column :tasks, :spam
  12 + end
  13 +end
db/migrate/20131011172930_add_image_to_article.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class AddImageToArticle < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + add_column :articles, :image_id, :integer
  5 + add_column :article_versions, :image_id, :integer
  6 + end
  7 +
  8 + def self.down
  9 + remove_column :articles, :image_id
  10 + remove_column :article_versions, :image_id
  11 + end
  12 +
  13 +end
db/migrate/20131015161830_add_position_to_article.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class AddPositionToArticle < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + add_column :articles, :position, :integer
  5 + add_column :article_versions, :position, :integer
  6 + end
  7 +
  8 + def self.down
  9 + remove_column :articles, :position
  10 + remove_column :article_versions, :position
  11 + end
  12 +
  13 +end
db/migrate/20131113151730_add_image_to_article.rb
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -class AddImageToArticle < ActiveRecord::Migration  
2 -  
3 - def self.up  
4 - add_column :articles, :image_id, :integer  
5 - add_column :article_versions, :image_id, :integer  
6 - end  
7 -  
8 - def self.down  
9 - remove_column :articles, :image_id  
10 - remove_column :article_versions, :image_id  
11 - end  
12 -  
13 -end  
db/migrate/20131113151835_add_position_to_article.rb
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -class AddPositionToArticle < ActiveRecord::Migration  
2 -  
3 - def self.up  
4 - add_column :articles, :position, :integer  
5 - add_column :article_versions, :position, :integer  
6 - end  
7 -  
8 - def self.down  
9 - remove_column :articles, :position  
10 - remove_column :article_versions, :position  
11 - end  
12 -  
13 -end  
db/migrate/20131116165327_enable_enterprises_list_on_user_menu.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class EnableEnterprisesListOnUserMenu < ActiveRecord::Migration
  2 + def self.up
  3 + # The enterprises were always listed on user menu.
  4 + # As now it is configured by admin, the running environments should not need to enable it
  5 + select_all("select id from environments").each do |environment|
  6 + env = Environment.find(environment['id'])
  7 + env.enable(:display_my_enterprises_on_user_menu)
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + #nothing to be done
  13 + end
  14 +end
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # 9 #
10 # It's strongly recommended to check this file into your version control system. 10 # It's strongly recommended to check this file into your version control system.
11 11
12 -ActiveRecord::Schema.define(:version => 20130711213046) do 12 +ActiveRecord::Schema.define(:version => 20131116165327) do
13 13
14 create_table "abuse_reports", :force => true do |t| 14 create_table "abuse_reports", :force => true do |t|
15 t.integer "reporter_id" 15 t.integer "reporter_id"
@@ -86,6 +86,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do @@ -86,6 +86,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do
86 t.string "language" 86 t.string "language"
87 t.string "source_name" 87 t.string "source_name"
88 t.integer "license_id" 88 t.integer "license_id"
  89 + t.integer "image_id"
  90 + t.integer "position"
89 end 91 end
90 92
91 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id" 93 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id"
@@ -129,6 +131,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do @@ -129,6 +131,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do
129 t.string "language" 131 t.string "language"
130 t.string "source_name" 132 t.string "source_name"
131 t.integer "license_id" 133 t.integer "license_id"
  134 + t.integer "image_id"
  135 + t.integer "position"
132 end 136 end
133 137
134 add_index "articles", ["name"], :name => "index_articles_on_name" 138 add_index "articles", ["name"], :name => "index_articles_on_name"
@@ -547,8 +551,11 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do @@ -547,8 +551,11 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do
547 t.datetime "created_at" 551 t.datetime "created_at"
548 t.string "target_type" 552 t.string "target_type"
549 t.integer "image_id" 553 t.integer "image_id"
  554 + t.boolean "spam", :default => false
550 end 555 end
551 556
  557 + add_index "tasks", ["spam"], :name => "index_tasks_on_spam"
  558 +
552 create_table "thumbnails", :force => true do |t| 559 create_table "thumbnails", :force => true do |t|
553 t.integer "size" 560 t.integer "size"
554 t.string "content_type" 561 t.string "content_type"
features/browse_catalogs.feature
@@ -9,7 +9,7 @@ Feature: browse catalogs @@ -9,7 +9,7 @@ Feature: browse catalogs
9 And the following enterprises 9 And the following enterprises
10 | identifier | owner | name | enabled | 10 | identifier | owner | name | enabled |
11 | artebonito | joaosilva | Associação de Artesanato de Bonito | true | 11 | artebonito | joaosilva | Associação de Artesanato de Bonito | true |
12 - And feature "disable_products_for_enterprises" is disabled on environment 12 + And feature "products_for_enterprises" is enabled on environment
13 And the following product_categories 13 And the following product_categories
14 | name | 14 | name |
15 | categ1 | 15 | categ1 |
features/browse_enterprises.feature
@@ -6,7 +6,7 @@ Background: @@ -6,7 +6,7 @@ Background:
6 Given the following enterprises 6 Given the following enterprises
7 | identifier | name | 7 | identifier | name |
8 | shop1 | Shoes Shop | 8 | shop1 | Shoes Shop |
9 - And feature "disable_products_for_enterprises" is disabled on environment 9 + And feature "products_for_enterprises" is enabled on environment
10 And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment 10 And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment
11 11
12 Scenario: show all enterprises 12 Scenario: show all enterprises
features/enterprise_homepage.feature
@@ -21,6 +21,7 @@ Feature: enterprise homepage @@ -21,6 +21,7 @@ Feature: enterprise homepage
21 And the following product 21 And the following product
22 | name | category | owner | 22 | name | category | owner |
23 | Natural Handmade | soap | mayhem | 23 | Natural Handmade | soap | mayhem |
  24 + And feature "products_for_enterprises" is enabled on environment
24 25
25 26
26 Scenario: display profile info 27 Scenario: display profile info
features/manage_inputs.feature
@@ -19,7 +19,7 @@ Feature: manage inputs @@ -19,7 +19,7 @@ Feature: manage inputs
19 And the following product 19 And the following product
20 | owner | category | name | 20 | owner | category | name |
21 | redemoinho | rock | Abbey Road | 21 | redemoinho | rock | Abbey Road |
22 - And feature "disable_products_for_enterprises" is disabled on environment 22 + And feature "products_for_enterprises" is enabled on environment
23 And the following units 23 And the following units
24 | singular | plural | 24 | singular | plural |
25 | Meter | Meters | 25 | Meter | Meters |
features/manage_product_price_details.feature
@@ -19,7 +19,7 @@ Feature: manage product price details @@ -19,7 +19,7 @@ Feature: manage product price details
19 And the following product 19 And the following product
20 | owner | category | name | price | 20 | owner | category | name | price |
21 | redemoinho | rock | Abbey Road | 80.0 | 21 | redemoinho | rock | Abbey Road | 80.0 |
22 - And feature "disable_products_for_enterprises" is disabled on environment 22 + And feature "products_for_enterprises" is enabled on environment
23 And the following inputs 23 And the following inputs
24 | product | category | price_per_unit | amount_used | 24 | product | category | price_per_unit | amount_used |
25 | Abbey Road | Rock | 10.0 | 2 | 25 | Abbey Road | Rock | 10.0 | 2 |
features/manage_products.feature
@@ -9,7 +9,7 @@ Feature: manage products @@ -9,7 +9,7 @@ Feature: manage products
9 And the following enterprises 9 And the following enterprises
10 | identifier | owner | name | enabled | 10 | identifier | owner | name | enabled |
11 | redemoinho | joaosilva | Rede Moinho | true | 11 | redemoinho | joaosilva | Rede Moinho | true |
12 - And feature "disable_products_for_enterprises" is disabled on environment 12 + And feature "products_for_enterprises" is enabled on environment
13 13
14 Scenario: display "create new product" button 14 Scenario: display "create new product" button
15 Given I am logged in as "joaosilva" 15 Given I am logged in as "joaosilva"
lib/feed_updater.rb
@@ -20,14 +20,20 @@ end @@ -20,14 +20,20 @@ end
20 class FeedUpdater 20 class FeedUpdater
21 21
22 class ExceptionNotification < ActionMailer::Base 22 class ExceptionNotification < ActionMailer::Base
23 - def mail error 23 + def mail container, error
24 environment = Environment.default 24 environment = Environment.default
25 25
26 recipients NOOSFERO_CONF['exception_recipients'] 26 recipients NOOSFERO_CONF['exception_recipients']
27 from environment.contact_email 27 from environment.contact_email
28 reply_to environment.contact_email 28 reply_to environment.contact_email
29 subject "[#{environment.name}] Feed-updater: #{error.message}" 29 subject "[#{environment.name}] Feed-updater: #{error.message}"
30 - body render(:text => error.backtrace.join("\n")) 30 + body render(:text => "
  31 +Container:
  32 +#{container.inspect}
  33 +
  34 +Backtrace:
  35 +#{error.backtrace.join("\n")}
  36 + ")
31 end 37 end
32 end 38 end
33 39
@@ -88,11 +94,13 @@ class FeedUpdater @@ -88,11 +94,13 @@ class FeedUpdater
88 if !running 94 if !running
89 break 95 break
90 end 96 end
91 - feed_handler.process(container) 97 + begin
  98 + feed_handler.process(container)
  99 + rescue Exception => e
  100 + FeedUpdater::ExceptionNotification.deliver_mail container, e if NOOSFERO_CONF['exception_recipients'].present?
  101 + end
92 end 102 end
93 end 103 end
94 - rescue Exception => e  
95 - FeedUpdater::ExceptionNotification.deliver_mail e if NOOSFERO_CONF['exception_recipients'].present?  
96 end 104 end
97 end 105 end
98 106
lib/file_presenter.rb 0 → 100644
@@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
  1 +# All file presenters must extends `FilePresenter` not only to ensure the
  2 +# same interface, but also to make `FilePresenter.for(file)` to work.
  3 +class FilePresenter
  4 +
  5 + # Will return a encapsulated `UploadedFile` or the same object if no
  6 + # one accepts it. That behave allow to give any model to this class,
  7 + # like a Article and have no trouble with that.
  8 + def self.for(f)
  9 + return f if f.is_a? FilePresenter
  10 + klass = FilePresenter.subclasses.sort_by {|class_name|
  11 + class_name.constantize.accepts?(f) || 0
  12 + }.last.constantize
  13 + klass.accepts?(f) ? klass.new(f) : f
  14 + end
  15 +
  16 + def initialize(f)
  17 + @file = f
  18 + end
  19 +
  20 + # Allows to use the original `UploadedFile` reference.
  21 + def encapsulated_file
  22 + @file
  23 + end
  24 +
  25 + def id
  26 + @file.id
  27 + end
  28 +
  29 + def reload
  30 + @file.reload
  31 + self
  32 + end
  33 +
  34 + # This method must be overridden in subclasses.
  35 + #
  36 + # If the class accepts the file, return a number that represents the
  37 + # priority the class should be given to handle that file. Higher numbers
  38 + # mean higher priority.
  39 + #
  40 + # If the class does not accept the file, return false.
  41 + def self.accepts?(f)
  42 + nil
  43 + end
  44 +
  45 + def short_description
  46 + _("File (%s)") % content_type.sub(/^application\//, '').sub(/^x-/, '').sub(/^image\//, '')
  47 + end
  48 +
  49 + # Define the css classes to style the page fragment with the file related
  50 + # content. If you want other classes to identify this area to your
  51 + # customized presenter, so do this:
  52 + # def css_class_list
  53 + # [super, 'myclass'].flatten
  54 + # end
  55 + def css_class_list
  56 + [ @file.css_class_list,
  57 + 'file-' + self.class.to_s.split(/:+/).map(&:underscore)[1..-1].join('-'),
  58 + 'content-type_' + self.content_type.split('/')[0],
  59 + 'content-type_' + self.content_type.gsub(/[^a-z0-9]/i,'-')
  60 + ].flatten
  61 + end
  62 +
  63 + # Enable file presenter to customize the css classes on view_page.rhtml
  64 + # You may not overwrite this method on your customized presenter.
  65 + def css_class_name
  66 + [css_class_list].flatten.compact.join(' ')
  67 + end
  68 +
  69 + # The generic icon class-name or the specific file path.
  70 + # You may replace this method on your custom FilePresenter.
  71 + # See the current used icons class-names in public/designs/icons/tango/style.css
  72 + def icon_name
  73 + if mime_type
  74 + [ mime_type.split('/')[0], mime_type.gsub(/[^a-z0-9]/i, '-') ]
  75 + else
  76 + 'upload-file'
  77 + end
  78 + end
  79 +
  80 + # Automatic render `file_presenter/<custom>.html.erb` to display your
  81 + # custom presenter html content.
  82 + # You may not overwrite this method on your customized presenter.
  83 + # A variable with the same presenter name will be created to refer
  84 + # to the file object.
  85 + # Example:
  86 + # The `FilePresenter::Image` render `file_presenter/image.html.erb`
  87 + # inside the `file_presenter/image.html.erb` you can access the
  88 + # required `FilePresenter::Image` instance in the `image` variable.
  89 + def to_html(options = {})
  90 + file = self
  91 + lambda do
  92 + render :partial => file.class.to_s.underscore,
  93 + :locals => { :options => options },
  94 + :object => file
  95 + end
  96 + end
  97 +
  98 + # That makes the presenter to works like any other `UploadedFile` instance.
  99 + def method_missing(m, *args)
  100 + @file.send(m, *args)
  101 + end
  102 +end
  103 +
  104 +# Preload FilePresenters to allow `FilePresenter.for()` to work
  105 +Dir.glob(File.join('app', 'presenters', '*.rb')) do |file|
  106 + load file
  107 +end
lib/noosfero/plugin.rb
@@ -155,6 +155,7 @@ class Noosfero::Plugin @@ -155,6 +155,7 @@ class Noosfero::Plugin
155 155
156 # Here the developer may specify the events to which the plugins can 156 # Here the developer may specify the events to which the plugins can
157 # register and must return true or false. The default value must be false. 157 # register and must return true or false. The default value must be false.
  158 + # Must also explicitly define its returning variables.
158 159
159 # -> If true, noosfero will include plugin_dir/public/style.css into 160 # -> If true, noosfero will include plugin_dir/public/style.css into
160 # application 161 # application
@@ -162,10 +163,6 @@ class Noosfero::Plugin @@ -162,10 +163,6 @@ class Noosfero::Plugin
162 false 163 false
163 end 164 end
164 165
165 - # Here the developer should specify the events to which the plugins can  
166 - # register to. Must be explicitly defined its returning  
167 - # variables.  
168 -  
169 # -> Adds buttons to the control panel 166 # -> Adds buttons to the control panel
170 # returns = { :title => title, :icon => icon, :url => url } 167 # returns = { :title => title, :icon => icon, :url => url }
171 # title = name that will be displayed. 168 # title = name that will be displayed.
@@ -175,6 +172,13 @@ class Noosfero::Plugin @@ -175,6 +172,13 @@ class Noosfero::Plugin
175 nil 172 nil
176 end 173 end
177 174
  175 + # -> Customize profile block design and behavior
  176 + # (overwrites profile_image_link function)
  177 + # returns = lambda block that creates html code.
  178 + def profile_image_link(profile, size, tag, extra_info)
  179 + nil
  180 + end
  181 +
178 # -> Adds tabs to the profile 182 # -> Adds tabs to the profile
179 # returns = { :title => title, :id => id, :content => content, :start => start } 183 # returns = { :title => title, :id => id, :content => content, :start => start }
180 # title = name that will be displayed. 184 # title = name that will be displayed.
@@ -304,45 +308,16 @@ class Noosfero::Plugin @@ -304,45 +308,16 @@ class Noosfero::Plugin
304 scope 308 scope
305 end 309 end
306 310
307 - # This method is called by the CommentHandler background job before sending  
308 - # the notification email. If the comment is marked as spam (i.e. by calling  
309 - # <tt>comment.spam!</tt>), then the notification email will *not* be sent.  
310 - #  
311 - # example:  
312 - #  
313 - # def check_comment_for_spam(comment)  
314 - # if anti_spam_service.is_spam?(comment)  
315 - # comment.spam!  
316 - # end  
317 - # end  
318 - #  
319 - def check_comment_for_spam(comment) 311 + # -> Allows plugins to check weather object is a spam
  312 + def check_for_spam(object)
320 end 313 end
321 314
322 - # This method is called when the user manually marks a comment as SPAM. A  
323 - # plugin implementing this method should train its spam detection mechanism  
324 - # by submitting this comment as a confirmed spam.  
325 - #  
326 - # example:  
327 - #  
328 - # def comment_marked_as_spam(comment)  
329 - # anti_spam_service.train_with_spam(comment)  
330 - # end  
331 - #  
332 - def comment_marked_as_spam(comment) 315 + # -> Allows plugins to know when an object is marked as a spam
  316 + def marked_as_spam(object)
333 end 317 end
334 318
335 - # This method is called when the user manually marks a comment a NOT SPAM. A  
336 - # plugin implementing this method should train its spam detection mechanism  
337 - # by submitting this coimment as a confirmed ham.  
338 - #  
339 - # example:  
340 - #  
341 - # def comment_marked_as_ham(comment)  
342 - # anti_spam_service.train_with_ham(comment)  
343 - # end  
344 - #  
345 - def comment_marked_as_ham(comment) 319 + # -> Allows plugins to know when an object is marked as a ham
  320 + def marked_as_ham(object)
346 end 321 end
347 322
348 # Adds extra actions for comments 323 # Adds extra actions for comments
lib/noosfero/plugin/manager.rb
@@ -34,18 +34,20 @@ class Noosfero::Plugin::Manager @@ -34,18 +34,20 @@ class Noosfero::Plugin::Manager
34 alias :dispatch_scopes :dispatch_without_flatten 34 alias :dispatch_scopes :dispatch_without_flatten
35 35
36 def dispatch_first(event, *args) 36 def dispatch_first(event, *args)
37 - result = nil 37 + default = Noosfero::Plugin.new.send(event, *args)
  38 + result = default
38 each do |plugin| 39 each do |plugin|
39 result = plugin.send(event, *args) 40 result = plugin.send(event, *args)
40 - break if result.present? 41 + break if result != default
41 end 42 end
42 result 43 result
43 end 44 end
44 45
45 def fetch_first_plugin(event, *args) 46 def fetch_first_plugin(event, *args)
  47 + default = Noosfero::Plugin.new.send(event, *args)
46 result = nil 48 result = nil
47 each do |plugin| 49 each do |plugin|
48 - if plugin.send(event, *args) 50 + if plugin.send(event, *args) != default
49 result = plugin.class 51 result = plugin.class
50 break 52 break
51 end 53 end
lib/noosfero/plugin/spammable.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +Spammable.module_eval do
  2 + def marked_as_spam
  3 + plugins.dispatch(:marked_as_spam, self)
  4 + end
  5 +
  6 + def marked_as_ham
  7 + plugins.dispatch(:marked_as_ham, self)
  8 + end
  9 +
  10 + def check_for_spam
  11 + plugins.dispatch(:check_for_spam, self)
  12 + end
  13 +end
lib/spammable.rb 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +module Spammable
  2 + def self.included(recipient)
  3 + #TODO This line crashes the migration which includes the spam attribute to
  4 + # Task... =P
  5 + # No fail-safe until someone find out how to use this without crashing
  6 + # the migration process
  7 + #raise "This model (#{recipient.to_s}) should have a spam attribute!" if !recipient.new.respond_to?('spam=')
  8 + recipient.extend(ClassMethods)
  9 + end
  10 +
  11 + module ClassMethods
  12 + def self.extended (base)
  13 + if base.respond_to?(:named_scope)
  14 + base.class_eval do
  15 + named_scope :without_spam, :conditions => ['spam IS NULL OR spam = ?', false]
  16 + named_scope :spam, :conditions => ['spam = ?', true]
  17 + end
  18 + end
  19 + end
  20 + end
  21 +
  22 + def spam?
  23 + !spam.nil? && spam
  24 + end
  25 +
  26 + def ham?
  27 + !spam.nil? && !spam
  28 + end
  29 +
  30 + def spam!
  31 + before_spam!
  32 + self.spam = true
  33 + self.save!
  34 + after_spam!
  35 + self
  36 + end
  37 +
  38 + def ham!
  39 + before_ham!
  40 + self.spam = false
  41 + self.save!
  42 + after_ham!
  43 + self
  44 + end
  45 +
  46 + def after_spam!; end
  47 + def before_spam!; end
  48 +
  49 + def after_ham!; end
  50 + def before_ham!; end
  51 +end
plugins/anti_spam/lib/anti_spam_plugin.rb
@@ -5,38 +5,37 @@ class AntiSpamPlugin &lt; Noosfero::Plugin @@ -5,38 +5,37 @@ class AntiSpamPlugin &lt; Noosfero::Plugin
5 end 5 end
6 6
7 def self.plugin_description 7 def self.plugin_description
8 - _("Checks comments against a spam checking service compatible with the Akismet API") 8 + _("Tests comments and suggested articles against a spam checking service compatible with the Akismet API")
9 end 9 end
10 10
11 def self.host_default_setting 11 def self.host_default_setting
12 'api.antispam.typepad.com' 12 'api.antispam.typepad.com'
13 end 13 end
14 14
15 - def check_comment_for_spam(comment)  
16 - if rakismet_call(comment, :spam?)  
17 - comment.spam = true  
18 - comment.save! 15 + def check_for_spam(object)
  16 + if rakismet_call AntiSpamPlugin::Wrapper.wrap(object), object.environment, :spam?
  17 + object.spam = true
  18 + object.save!
19 end 19 end
20 end 20 end
21 21
22 - def comment_marked_as_spam(comment)  
23 - rakismet_call(comment, :spam!) 22 + def marked_as_spam(object)
  23 + rakismet_call AntiSpamPlugin::Wrapper.wrap(object), object.environment, :spam!
24 end 24 end
25 25
26 - def comment_marked_as_ham(comment)  
27 - rakismet_call(comment, :ham!) 26 + def marked_as_ham(object)
  27 + rakismet_call AntiSpamPlugin::Wrapper.wrap(object), object.environment, :ham!
28 end 28 end
29 29
30 protected 30 protected
31 31
32 - def rakismet_call(comment, op)  
33 - settings = Noosfero::Plugin::Settings.new(comment.environment, self.class) 32 + def rakismet_call(submission, environment, op)
  33 + settings = Noosfero::Plugin::Settings.new(environment, self.class)
34 34
35 Rakismet.host = settings.host 35 Rakismet.host = settings.host
36 Rakismet.key = settings.api_key 36 Rakismet.key = settings.api_key
37 - Rakismet.url = comment.environment.top_url 37 + Rakismet.url = environment.top_url
38 38
39 - submission = AntiSpamPlugin::CommentWrapper.new(comment)  
40 submission.send(op) 39 submission.send(op)
41 end 40 end
42 41
plugins/anti_spam/lib/anti_spam_plugin/comment_wrapper.rb
1 -class AntiSpamPlugin::CommentWrapper < Struct.new(:comment)  
2 -  
3 - delegate :author_name, :author_email, :title, :body, :ip_address, :user_agent, :referrer, :to => :comment  
4 -  
5 - include Rakismet::Model  
6 -  
7 - alias :author :author_name  
8 - alias :user_ip :ip_address  
9 - alias :content :body  
10 - 1 +class AntiSpamPlugin::CommentWrapper < AntiSpamPlugin::Wrapper
  2 + alias_attribute :author, :author_name
  3 + alias_attribute :user_ip, :ip_address
  4 + alias_attribute :content, :body
  5 +
  6 + def self.wraps?(object)
  7 + object.kind_of?(Comment)
  8 + end
11 end 9 end
plugins/anti_spam/lib/anti_spam_plugin/suggest_article_wrapper.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class AntiSpamPlugin::SuggestArticleWrapper < AntiSpamPlugin::Wrapper
  2 + alias_attribute :author, :name
  3 + alias_attribute :author_email, :email
  4 + alias_attribute :user_ip, :ip_address
  5 + alias_attribute :content, :article_body
  6 +
  7 + def self.wraps?(object)
  8 + object.kind_of?(SuggestArticle)
  9 + end
  10 +end
plugins/anti_spam/lib/anti_spam_plugin/wrapper.rb 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +class AntiSpamPlugin::Wrapper < SimpleDelegator
  2 + include Rakismet::Model
  3 +
  4 + @@wrappers = []
  5 +
  6 + def self.wrap(object)
  7 + wrapper = @@wrappers.find { |wrapper| wrapper.wraps?(object) }
  8 + wrapper ? wrapper.new(object) : object
  9 + end
  10 +
  11 + def self.wraps?(object)
  12 + false
  13 + end
  14 +
  15 + def self.inherited(child)
  16 + @@wrappers << child
  17 + end
  18 +end
plugins/anti_spam/test/unit/anti_spam_plugin/comment_wrapper_test.rb
1 require 'test_helper' 1 require 'test_helper'
2 2
3 -class AntiSpamPluginCommentWrapperTest < ActiveSupport::TestCase 3 +class AntiSpamPlugin::CommentWrapperTest < ActiveSupport::TestCase
4 4
5 def setup 5 def setup
6 @comment = Comment.new( 6 @comment = Comment.new(
@@ -15,10 +15,6 @@ class AntiSpamPluginCommentWrapperTest &lt; ActiveSupport::TestCase @@ -15,10 +15,6 @@ class AntiSpamPluginCommentWrapperTest &lt; ActiveSupport::TestCase
15 @wrapper = AntiSpamPlugin::CommentWrapper.new(@comment) 15 @wrapper = AntiSpamPlugin::CommentWrapper.new(@comment)
16 end 16 end
17 17
18 - should 'use Rakismet::Model' do  
19 - assert_includes @wrapper.class.included_modules, Rakismet::Model  
20 - end  
21 -  
22 should 'get contents' do 18 should 'get contents' do
23 assert_equal @comment.body, @wrapper.content 19 assert_equal @comment.body, @wrapper.content
24 end 20 end
plugins/anti_spam/test/unit/anti_spam_plugin/suggest_article_wrapper_test.rb 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +require 'test_helper'
  2 +
  3 +class AntiSpamPlugin::SuggestArticleWrapperTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @suggest_article = SuggestArticle.new(
  7 + :article_body => 'comment body',
  8 + :name => 'author',
  9 + :email => 'foo@example.com',
  10 + :ip_address => '1.2.3.4',
  11 + :user_agent => 'Some Good Browser (I hope)',
  12 + :referrer => 'http://noosfero.org/'
  13 + )
  14 + @wrapper = AntiSpamPlugin::SuggestArticleWrapper.new(@suggest_article)
  15 + end
  16 +
  17 + should 'get contents' do
  18 + assert_equal @suggest_article.article_body, @wrapper.content
  19 + end
  20 +
  21 + should 'get author name' do
  22 + assert_equal @suggest_article.name, @wrapper.author
  23 + end
  24 +
  25 + should 'get author email' do
  26 + assert_equal @suggest_article.email, @wrapper.author_email
  27 + end
  28 +
  29 + should 'get IP address' do
  30 + assert_equal @suggest_article.ip_address, @wrapper.user_ip
  31 + end
  32 +
  33 + should 'get User-Agent' do
  34 + assert_equal @suggest_article.user_agent, @wrapper.user_agent
  35 + end
  36 +
  37 + should 'get get Referrer' do
  38 + assert_equal @suggest_article.referrer, @wrapper.referrer
  39 + end
  40 +
  41 +end
plugins/anti_spam/test/unit/anti_spam_plugin/wrapper_test.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +require 'test_helper'
  2 +require 'anti_spam_plugin/wrapper'
  3 +
  4 +class AntiSpamPluginWrapperTest < ActiveSupport::TestCase
  5 + should 'use Rakismet::Model' do
  6 + wrapped = AntiSpamPlugin::Wrapper.new(mock)
  7 + assert_includes wrapped.class.included_modules, Rakismet::Model
  8 + end
  9 +
  10 + should 'wrap object according to wraps? method' do
  11 + class EvenWrapper < AntiSpamPlugin::Wrapper
  12 + def self.wraps?(object)
  13 + object % 2 == 0
  14 + end
  15 + end
  16 + class OddWrapper < AntiSpamPlugin::Wrapper
  17 + def self.wraps?(object)
  18 + object % 2 != 0
  19 + end
  20 + end
  21 +
  22 + assert AntiSpamPlugin::Wrapper.wrap(5).kind_of?(OddWrapper)
  23 + assert AntiSpamPlugin::Wrapper.wrap(6).kind_of?(EvenWrapper)
  24 + end
  25 +end
plugins/anti_spam/test/unit/anti_spam_plugin_test.rb
@@ -2,35 +2,36 @@ require &#39;test_helper&#39; @@ -2,35 +2,36 @@ require &#39;test_helper&#39;
2 2
3 class AntiSpamPluginTest < ActiveSupport::TestCase 3 class AntiSpamPluginTest < ActiveSupport::TestCase
4 4
5 - def setup  
6 - profile = fast_create(Profile)  
7 - article = fast_create(TextileArticle, :profile_id => profile.id)  
8 - @comment = fast_create(Comment, :source_id => article.id, :source_type => 'Article') 5 + class SpammableContent
  6 + attr_accessor :spam
  7 + include Spammable
9 8
10 - @settings = Noosfero::Plugin::Settings.new(@comment.environment, AntiSpamPlugin)  
11 - @settings.api_key = 'b8b80ddb8084062d0c9119c945ce3bc3'  
12 - @settings.save! 9 + def save!; end
  10 + def environment; Environment.default; end
  11 + end
13 12
  13 + def setup
  14 + @spammable = SpammableContent.new
14 @plugin = AntiSpamPlugin.new 15 @plugin = AntiSpamPlugin.new
15 - @plugin.context = @comment  
16 end 16 end
17 17
18 - should 'check for spam and mark comment as spam if server says it is spam' do  
19 - AntiSpamPlugin::CommentWrapper.any_instance.expects(:spam?).returns(true)  
20 - @comment.expects(:save!) 18 + attr_accessor :spammable
21 19
22 - @plugin.check_comment_for_spam(@comment)  
23 - assert @comment.spam  
24 - end 20 + should 'check for spam and mark as spam if server says it is spam' do
  21 + spammable.expects(:spam?).returns(true)
  22 + spammable.expects(:save!)
25 23
26 - should 'report spam' do  
27 - AntiSpamPlugin::CommentWrapper.any_instance.expects(:spam!)  
28 - @plugin.comment_marked_as_spam(@comment) 24 + @plugin.check_for_spam(spammable)
  25 + assert spammable.spam
29 end 26 end
30 27
31 - should 'report ham' do  
32 - AntiSpamPlugin::CommentWrapper.any_instance.expects(:ham!)  
33 - @plugin.comment_marked_as_ham(@comment) 28 + should 'report comment spam' do
  29 + spammable.expects(:spam!)
  30 + @plugin.marked_as_spam(spammable)
34 end 31 end
35 32
  33 + should 'report comment ham' do
  34 + spammable.expects(:ham!)
  35 + @plugin.marked_as_ham(spammable)
  36 + end
36 end 37 end
plugins/community_track/controllers/myprofile/community_track_plugin_myprofile_controller.rb 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +class CommunityTrackPluginMyprofileController < MyProfileController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  3 +
  4 + before_filter :allow_edit_track, :only => :save_order
  5 +
  6 + def save_order
  7 + track = profile.articles.find(params[:track])
  8 + track.reorder_steps(params[:step_ids])
  9 + redirect_to track.url
  10 + end
  11 +
  12 + protected
  13 +
  14 + def allow_edit_track
  15 + render_access_denied unless profile.articles.find(params[:track]).allow_edit?(user)
  16 + end
  17 +
  18 +end
plugins/community_track/controllers/public/community_track_plugin_public_controller.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +class CommunityTrackPluginPublicController < PublicController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  3 +
  4 + no_design_blocks
  5 +
  6 + before_filter :login_required, :only => :select_community
  7 +
  8 + def view_tracks
  9 + block = Block.find(params[:id])
  10 + p = params[:page].to_i
  11 + per_page = params[:per_page]
  12 + per_page ||= block.limit
  13 + per_page = per_page.to_i
  14 + tracks = block.tracks(p, per_page)
  15 +
  16 + render :update do |page|
  17 + page.insert_html :bottom, "track_list_#{block.id}", :partial => "blocks/#{block.track_partial}", :collection => tracks, :locals => {:block => block}
  18 +
  19 + if block.has_page?(p+1, per_page)
  20 + page.replace_html "track_list_more_#{block.id}", :partial => 'blocks/track_list_more', :locals => {:block => block, :page => p+1, :force_same_page => params[:force_same_page], :per_page => per_page}
  21 + else
  22 + page.replace_html "track_list_more_#{block.id}", ''
  23 + end
  24 + end
  25 + end
  26 +
  27 + def all_tracks
  28 + @per_page = 5 #FIXME
  29 + @block = Block.find(params[:id])
  30 + @tracks = @block.tracks(1, @per_page)
  31 + @show_more = @block.has_page?(2, @per_page)
  32 + end
  33 +
  34 + def select_community
  35 + @communities = user.memberships.select{ |community| user.has_permission?('post_content', community) }
  36 + @back_to = request.url
  37 + if request.post?
  38 + community_identifier = params[:community_identifier]
  39 + if community_identifier.nil?
  40 + @failed = [_('Select one community to proceed')]
  41 + else
  42 + redirect_to :controller => 'cms', :action => 'new', :type => "CommunityTrackPlugin::Track", :profile => community_identifier
  43 + end
  44 + end
  45 + end
  46 +
  47 +end
plugins/community_track/lib/community_track_plugin.rb 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +class CommunityTrackPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + 'Community Track'
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("New kind of content for communities.")
  9 + end
  10 +
  11 + def stylesheet?
  12 + true
  13 + end
  14 +
  15 + def content_types
  16 + if context.respond_to?(:params) && context.params
  17 + types = []
  18 + parent_id = context.params[:parent_id]
  19 + types << CommunityTrackPlugin::Track if context.profile.community? && !parent_id
  20 + parent = parent_id ? context.profile.articles.find(parent_id) : nil
  21 + types << CommunityTrackPlugin::Step if parent.kind_of?(CommunityTrackPlugin::Track)
  22 + types
  23 + else
  24 + [CommunityTrackPlugin::Track, CommunityTrackPlugin::Step]
  25 + end
  26 + end
  27 +
  28 + def self.extra_blocks
  29 + { CommunityTrackPlugin::TrackListBlock => {:position => 1}, CommunityTrackPlugin::TrackCardListBlock => {} }
  30 + end
  31 +
  32 + def content_remove_new(page)
  33 + page.kind_of?(CommunityTrackPlugin::Track)
  34 + end
  35 +
  36 +end
plugins/community_track/lib/community_track_plugin/step.rb 0 → 100644
@@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
  1 +class CommunityTrackPlugin::Step < Folder
  2 +
  3 + settings_items :hidden, :type => :boolean, :default => false
  4 +
  5 + alias :tools :children
  6 +
  7 + acts_as_list :scope => :parent
  8 +
  9 + def belong_to_track
  10 + errors.add(:parent, "Step not allowed at this parent.") if !parent.kind_of?(CommunityTrackPlugin::Track)
  11 + end
  12 +
  13 + validate :belong_to_track
  14 + validates_presence_of :start_date, :end_date
  15 + validate :end_date_equal_or_after_start_date
  16 +
  17 + after_save :schedule_activation
  18 +
  19 + before_create do |step|
  20 + step.published = false
  21 + true
  22 + end
  23 +
  24 + before_create :set_hidden_position
  25 + before_save :set_hidden_position
  26 +
  27 + def set_hidden_position
  28 + if hidden
  29 + decrement_positions_on_lower_items
  30 + self[:position] = 0
  31 + elsif position == 0
  32 + add_to_list_bottom
  33 + end
  34 + end
  35 +
  36 + def end_date_equal_or_after_start_date
  37 + if end_date && start_date
  38 + errors.add(:end_date, _('must be equal or after start date.')) unless end_date >= start_date
  39 + end
  40 + end
  41 +
  42 + def self.short_description
  43 + _("Step")
  44 + end
  45 +
  46 + def self.description
  47 + _('Defines a step.')
  48 + end
  49 +
  50 + def accept_comments?
  51 + false
  52 + end
  53 +
  54 + def enabled_tools
  55 + {TinyMceArticle => {:name => _('Article')}, Forum => {:name => _('Forum')}}
  56 + end
  57 +
  58 + def to_html(options = {})
  59 + step = self
  60 + lambda do
  61 + render :file => 'content_viewer/step.rhtml', :locals => {:step => step}
  62 + end
  63 + end
  64 +
  65 + def active?
  66 + (start_date..end_date).include?(Date.today)
  67 + end
  68 +
  69 + def finished?
  70 + Date.today > end_date
  71 + end
  72 +
  73 + def waiting?
  74 + Date.today < start_date
  75 + end
  76 +
  77 + def schedule_activation
  78 + return if !changes['start_date'] && !changes['end_date'] && !changes['published']
  79 + today = Date.today
  80 + if today <= end_date || published
  81 + schedule_date = !published ? start_date : end_date + 1.day
  82 + CommunityTrackPlugin::ActivationJob.find(id).destroy_all
  83 + Delayed::Job.enqueue(CommunityTrackPlugin::ActivationJob.new(self.id), 0, schedule_date)
  84 + end
  85 + end
  86 +
  87 + def publish
  88 + self[:published] = active? && !hidden
  89 + save!
  90 + end
  91 +
  92 + class CommunityTrackPlugin::ActivationJob < Struct.new(:step_id)
  93 +
  94 + def self.find(step_id)
  95 + Delayed::Job.where(:handler => "--- !ruby/struct:CommunityTrackPlugin::ActivationJob \nstep_id: #{step_id}\n")
  96 + end
  97 +
  98 + def perform
  99 + step = CommunityTrackPlugin::Step.find(step_id)
  100 + step.publish
  101 + end
  102 +
  103 + end
  104 +
  105 +end
plugins/community_track/lib/community_track_plugin/step_helper.rb 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +module CommunityTrackPlugin::StepHelper
  2 +
  3 + def self.status_descriptions
  4 + [_('Finished'), _('In progress'), _('Waiting')]
  5 + end
  6 +
  7 + def self.status_classes
  8 + ['step_finished', 'step_active', 'step_waiting']
  9 + end
  10 +
  11 + def status_description(step)
  12 + CommunityTrackPlugin::StepHelper.status_descriptions[status_index(step)]
  13 + end
  14 +
  15 + def status_class(step)
  16 + CommunityTrackPlugin::StepHelper.status_classes[status_index(step)]
  17 + end
  18 +
  19 + def custom_options_for_article(article)
  20 + #no options for step?
  21 + nil
  22 + end
  23 +
  24 + protected
  25 +
  26 + def status_index(step)
  27 + [step.finished?, step.active?, step.waiting?].find_index(true)
  28 + end
  29 +
  30 +end
plugins/community_track/lib/community_track_plugin/track.rb 0 → 100644
@@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
  1 +class CommunityTrackPlugin::Track < Folder
  2 +
  3 + settings_items :goals, :type => :string
  4 + settings_items :expected_results, :type => :string
  5 +
  6 + def self.icon_name(article = nil)
  7 + 'community-track'
  8 + end
  9 +
  10 + def self.short_description
  11 + _("Track")
  12 + end
  13 +
  14 + def self.description
  15 + _('Defines a track.')
  16 + end
  17 +
  18 + def steps
  19 + #XXX article default order is name (acts_as_filesystem) -> should use reorder (rails3)
  20 + steps_unsorted.sort_by(&:position).select{|s| !s.hidden}
  21 + end
  22 +
  23 + def hidden_steps
  24 + steps_unsorted.select{|s| s.hidden}
  25 + end
  26 +
  27 + def reorder_steps(step_ids)
  28 + transaction do
  29 + step_ids.each_with_index do |step_id, i|
  30 + step = steps_unsorted.find(step_id)
  31 + step.update_attribute(:position, step.position = i + 1)
  32 + end
  33 + end
  34 + end
  35 +
  36 + def steps_unsorted
  37 + children.where(:type => 'CommunityTrackPlugin::Step')
  38 + end
  39 +
  40 + def accept_comments?
  41 + false
  42 + end
  43 +
  44 + def comments_count
  45 + steps_unsorted.joins(:children).sum('childrens_articles.comments_count')
  46 + end
  47 +
  48 + def css_class_name
  49 + "community-track-plugin-track"
  50 + end
  51 +
  52 + #FIXME make this test
  53 + def first_paragraph
  54 + paragraphs = Hpricot(body).search('p')
  55 + paragraphs.empty? ? '' : paragraphs.first.to_html
  56 + end
  57 +
  58 + def category_name
  59 + category = categories.first
  60 + category ? category.name : ''
  61 + end
  62 +
  63 + def to_html(options = {})
  64 + track = self
  65 + lambda do
  66 + render :file => 'content_viewer/track.rhtml', :locals => {:track => track}
  67 + end
  68 + end
  69 +
  70 +end
plugins/community_track/lib/community_track_plugin/track_card_list_block.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +class CommunityTrackPlugin::TrackCardListBlock < CommunityTrackPlugin::TrackListBlock
  2 +
  3 + def self.description
  4 + _('Track Card List')
  5 + end
  6 +
  7 + def help
  8 + _('This block displays a list of most relevant tracks as cards.')
  9 + end
  10 +
  11 + def track_partial
  12 + 'track_card'
  13 + end
  14 +
  15 +end
plugins/community_track/lib/community_track_plugin/track_helper.rb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +module CommunityTrackPlugin::TrackHelper
  2 +
  3 + def category_class(track)
  4 + 'category_' + (track.categories.empty? ? 'not_defined' : track.categories.first.name.to_slug)
  5 + end
  6 +
  7 + def track_card_lead(track)
  8 + lead_stripped = strip_tags(track.lead)
  9 + excerpt(lead_stripped, lead_stripped.first(3), track.image ? 180 : 300)
  10 + end
  11 +
  12 +end
plugins/community_track/lib/community_track_plugin/track_list_block.rb 0 → 100644
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +class CommunityTrackPlugin::TrackListBlock < Block
  2 +
  3 + include CommunityTrackPlugin::StepHelper
  4 +
  5 + settings_items :limit, :type => :integer, :default => 3
  6 + settings_items :more_another_page, :type => :boolean, :default => false
  7 + settings_items :category_ids, :type => Array, :default => []
  8 +
  9 + def self.description
  10 + _('Track List')
  11 + end
  12 +
  13 + def help
  14 + _('This block displays a list of most relevant tracks.')
  15 + end
  16 +
  17 + def track_partial
  18 + 'track'
  19 + end
  20 +
  21 + def tracks(page=1, per_page=limit)
  22 + all_tracks.order('hits DESC').paginate(:per_page => per_page, :page => page)
  23 + end
  24 +
  25 + def count_tracks
  26 + all_tracks.count
  27 + end
  28 +
  29 + def accept_category?(cat)
  30 + true #accept all?
  31 + end
  32 +
  33 + def category_ids=(ids)
  34 + settings[:category_ids] = ids.uniq.map{|item| item.to_i unless item.to_i.zero?}.compact
  35 + end
  36 +
  37 + def all_tracks
  38 + tracks = owner.articles.where(:type => 'CommunityTrackPlugin::Track')
  39 + if !category_ids.empty?
  40 + tracks = tracks.joins(:article_categorizations).where(:articles_categories => {:category_id => category_ids})
  41 + end
  42 + tracks
  43 + end
  44 +
  45 + def content(args={})
  46 + block = self
  47 + lambda do
  48 + render :file => 'blocks/track_list.rhtml', :locals => {:block => block}
  49 + end
  50 + end
  51 +
  52 + def has_page?(page, per_page=limit)
  53 + return (page-1) * per_page < count_tracks
  54 + end
  55 +
  56 + def footer
  57 + block = self
  58 + return nil if !has_page?(2)
  59 + lambda do
  60 + render :partial => 'blocks/track_list_more', :locals => {:block => block, :page => 2, :per_page => block.limit}
  61 + end
  62 + end
  63 +
  64 +end
plugins/community_track/public/icons/community-track.png 0 → 100644

1.49 KB

plugins/community_track/public/style.css 0 → 100644
@@ -0,0 +1,195 @@ @@ -0,0 +1,195 @@
  1 +.icon-newcommunity-track,
  2 +.icon-community-track {
  3 + background-image: url(/plugins/community_track/icons/community-track.png)
  4 +}
  5 +
  6 +.step_active, #article .step_active a {
  7 + background-color: #CCEBD6;
  8 + color: #338533;
  9 +}
  10 +
  11 +.step_waiting, #article .step_waiting a {
  12 + background-color: #FFFFD1;
  13 + color: #D17519;
  14 +}
  15 +
  16 +.step_finished, #article .step_finished a {
  17 + background-color: #D1FFFF;
  18 + color: #00297A;
  19 +}
  20 +
  21 +.step_status_description {
  22 + float: right;
  23 +}
  24 +
  25 +.step {
  26 + font-weight: bold;
  27 +}
  28 +
  29 +.track_list .item .step {
  30 + padding: 8px 5px;
  31 +}
  32 +
  33 +#article .step a {
  34 + text-decoration: none;
  35 +}
  36 +
  37 +.track_list .item .track_content .lead {
  38 + float: left;
  39 + width: 50%;
  40 +}
  41 +
  42 +.track_list .item .track_content .steps {
  43 + float: right;
  44 + width: 50%;
  45 +}
  46 +
  47 +.track_list .item {
  48 + border-bottom: 1px solid #DDDDDD;
  49 +}
  50 +
  51 +.track_stats, .track_content {
  52 + clear: both;
  53 +}
  54 +
  55 +.track_stats .comments {
  56 + float: left;
  57 +}
  58 +
  59 +.track_stats .hits {
  60 + float: right;
  61 +}
  62 +
  63 +.track_list .item_card {
  64 + width: 155px;
  65 + border: 1px solid #DDDDDD;
  66 + float: left;
  67 + padding: 0px 8px;
  68 + margin-left: 3px;
  69 + margin-right: 3px;
  70 + margin-bottom: 8px;
  71 +}
  72 +
  73 +.steps .step {
  74 + margin-top: 3px;
  75 + margin-bottom: 3px;
  76 +}
  77 +
  78 +.track_list .item_card .track_stats {
  79 + border-top: 1px solid #DDDDDD;
  80 +}
  81 +
  82 +.track_list .item_card a, .track_list .item_card a:hover, .track_list .item_card a:visited {
  83 + text-decoration: none;
  84 + color: #444;
  85 +}
  86 +
  87 +.track_list .item_card:hover {
  88 + background: #EEE;
  89 +}
  90 +
  91 +.track_list .title {
  92 + font-size: 16px;
  93 + font-weight: bold;
  94 + border-bottom: 1px solid #DDDDDD;
  95 + padding: 2px 0px;
  96 + margin-bottom: 5px;
  97 + min-height: 10px;
  98 +}
  99 +
  100 +.track_list .image img {
  101 + max-width: 100%;
  102 + max-height: 100px;
  103 + display: block;
  104 + margin-left: auto;
  105 + margin-right: auto;
  106 +}
  107 +
  108 +.track_list .name {
  109 + padding-top: 5px;
  110 +}
  111 +
  112 +.track_list .item_card {
  113 + height: 270px;
  114 +}
  115 +
  116 +.track_list .track_content {
  117 + height: 250px;
  118 +}
  119 +
  120 +#track .step_list {
  121 + list-style-type: none;
  122 + margin: 0;
  123 + padding: 0;
  124 +}
  125 +
  126 +#track .position {
  127 + font-size: 24px;
  128 + font-weight: bold;
  129 + float: left;
  130 + margin: 0 10px;
  131 +}
  132 +
  133 +#track .step .name, #track .step .name a {
  134 + font-weight: bold;
  135 + color: #333;
  136 +}
  137 +
  138 +#track .step .name a:hover {
  139 + color: #555;
  140 +}
  141 +
  142 +#track .step .date {
  143 + font-size: 12px;
  144 + color: #AAA;
  145 +}
  146 +
  147 +#track .step .lead {
  148 + margin: 0px 10px;
  149 + color: #555;
  150 +}
  151 +
  152 +#track .content {
  153 + margin: 6px 0px;
  154 + border-bottom: 1px solid #DDDDDD;
  155 +}
  156 +
  157 +#track .ui-state-default .content {
  158 + border-bottom: 0px;
  159 +}
  160 +
  161 +.track_list .item .step .position {
  162 + float: left;
  163 + padding-right: 5px;
  164 +}
  165 +
  166 +#track .actions .save_button {
  167 + display: none;
  168 +}
  169 +
  170 +#track .actions, #step .actions {
  171 + margin-bottom: 20px;
  172 +}
  173 +
  174 +#edit-track-list-block .categorie_box a {
  175 + float: left;
  176 +}
  177 +
  178 +.all_tracks .more_button {
  179 + text-align: center;
  180 +}
  181 +
  182 +#step .tools .item .name a, #step .tools .item .name a:hover {
  183 + border: none;
  184 + background-color: transparent;
  185 + color: #666;
  186 + font-weight: bold;
  187 +}
  188 +
  189 +#step .tools .item .name a:hover {
  190 + color: #888;
  191 +}
  192 +
  193 +.community-track textarea {
  194 + width: 100%;
  195 +}
plugins/community_track/test/functional/community_track_plugin_cms_controller_test.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class CmsController; def rescue_action(e) raise e end; end
  5 +
  6 +class CmsControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @profile = fast_create(Community)
  10 + @track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track', :profile => @profile)
  11 + @step = CommunityTrackPlugin::Step.create!(:name => 'step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  12 +
  13 + user = create_user('testinguser')
  14 + @profile.add_admin(user.person)
  15 + login_as(user.login)
  16 + end
  17 +
  18 + should 'be able to edit track' do
  19 + get :edit, :id => @track.id, :profile => @profile.identifier
  20 + assert_tag :tag => 'input', :attributes => { :id => 'article_name' }
  21 + end
  22 +
  23 + should 'be able to edit step' do
  24 + get :edit, :id => @step.id, :profile => @profile.identifier
  25 + assert_tag :tag => 'input', :attributes => { :id => 'article_name' }
  26 + end
  27 +
  28 + should 'be able to save track' do
  29 + get :edit, :id => @track.id, :profile => @profile.identifier
  30 + post :edit, :id => @track.id, :profile => @profile.identifier, :article => {:name => 'changed'}
  31 + @track.reload
  32 + assert_equal 'changed', @track.name
  33 + end
  34 +
  35 + should 'be able to save step' do
  36 + get :edit, :id => @step.id, :profile => @profile.identifier
  37 + post :edit, :id => @step.id, :profile => @profile.identifier, :article => {:name => 'changed'}
  38 + @step.reload
  39 + assert_equal 'changed', @step.name
  40 + end
  41 +
  42 + should 'do not be able to edit visibility of step' do
  43 + get :edit, :id => @step.id, :profile => @profile.identifier
  44 + assert_no_tag :tag => 'input', :attributes => { :name => 'article[published]' }
  45 + end
  46 +
  47 +end
plugins/community_track/test/functional/community_track_plugin_content_viewer_controller_test.rb 0 → 100644
@@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class ContentViewerController
  4 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  5 + def rescue_action(e)
  6 + raise e
  7 + end
  8 +end
  9 +
  10 +class ContentViewerControllerTest < ActionController::TestCase
  11 +
  12 + def setup
  13 + @profile = fast_create(Community)
  14 + @track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track', :profile => @profile)
  15 + category = fast_create(Category, :name => "education")
  16 + @track.add_category(category)
  17 +
  18 + @step = CommunityTrackPlugin::Step.create!(:name => 'step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  19 +
  20 + user = create_user('testinguser')
  21 + login_as(user.login)
  22 + @profile.add_admin(user.person)
  23 + end
  24 +
  25 + should 'show actions for tracks when user has permission for edit' do
  26 + get :view_page, @track.url
  27 + assert_tag :tag => 'div', :attributes => {:id => 'track' }, :descendant => { :tag => 'div', :attributes => { :class => 'actions' } }
  28 + end
  29 +
  30 + should 'do not show actions for tracks when user has not permission for edit' do
  31 + user = create_user('intruder')
  32 + logout
  33 + login_as(user.login)
  34 + get :view_page, @track.url
  35 + assert_no_tag :tag => 'div', :attributes => {:id => 'track' }, :descendant => { :tag => 'div', :attributes => { :class => 'actions' } }
  36 + end
  37 +
  38 + should 'do not show new button at article toolbar for tracks' do
  39 + user = create_user('intruder')
  40 + logout
  41 + login_as(user.login)
  42 + get :view_page, @track.url
  43 + assert_no_tag :tag => 'div', :attributes => {:id => 'article-actions'}, :descendant => { :tag => 'div', :attributes => { :id => 'icon-new' } }
  44 + end
  45 +
  46 + should 'display steps for tracks' do
  47 + get :view_page, @track.url
  48 + assert_tag :tag => 'ul', :attributes => { :id => 'sortable' }, :descendant => {:tag => 'li', :attributes => { :class => 'step' } }
  49 + end
  50 +
  51 + should 'display hidden field with step id' do
  52 + get :view_page, @track.url
  53 + assert_tag :tag => 'input', :attributes => { :name => 'step_ids[]' }
  54 + end
  55 +
  56 + should 'show step' do
  57 + get :view_page, @step.url
  58 + assert_tag :tag => 'div', :attributes => { :id => 'step' }
  59 + end
  60 +
  61 + should 'show tools for a step' do
  62 + Article.create!(:profile => @profile, :name => 'article', :parent => @step)
  63 + get :view_page, @step.url
  64 + assert_tag :tag => 'div', :attributes => { :class => 'tools' }, :descendant => { :tag => 'div', :attributes => { :class => 'item' } }
  65 + end
  66 +
  67 + should 'show actions for steps when user has permission for edit' do
  68 + get :view_page, @step.url
  69 + assert_tag :tag => 'div', :attributes => {:id => 'step' }, :descendant => { :tag => 'div', :attributes => { :class => 'actions' } }
  70 + end
  71 +
  72 + should 'show actions for enabled tools in step' do
  73 + get :view_page, @step.url
  74 + assert_tag 'div', :attributes => {:class => 'actions' }, :descendant => { :tag => 'a', :attributes => { :class => 'button with-text icon-new icon-newforum' } }
  75 + assert_tag 'div', :attributes => {:class => 'actions' }, :descendant => { :tag => 'a', :attributes => { :class => 'button with-text icon-new icon-newtext-html' } }
  76 + end
  77 +
  78 + should 'do not show actions for steps when user has not permission for edit' do
  79 + user = create_user('intruder')
  80 + logout
  81 + login_as(user.login)
  82 + get :view_page, @step.url
  83 + assert_no_tag :tag => 'div', :attributes => {:id => 'step' }, :descendant => { :tag => 'div', :attributes => { :class => 'actions' } }
  84 + end
  85 +
  86 + should 'render a div with block id for track list block' do
  87 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  88 + @block = CommunityTrackPlugin::TrackListBlock.create!(:box => box)
  89 + @profile.boxes << box
  90 + get :view_page, @step.url
  91 + assert_tag :tag => 'div', :attributes => { :class => 'track_list', :id => "track_list_#{@block.id}" }
  92 + end
  93 +
  94 + should 'render a div with block id for track card list block' do
  95 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  96 + @block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  97 + @profile.boxes << box
  98 + get :view_page, @step.url
  99 + assert_tag :tag => 'div', :attributes => { :class => 'track_list', :id => "track_list_#{@block.id}" }
  100 + end
  101 +
  102 + should 'render tracks in track list block' do
  103 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  104 + @block = CommunityTrackPlugin::TrackListBlock.create!(:box => box)
  105 + @profile.boxes << box
  106 + get :view_page, @step.url
  107 + assert_tag :tag => 'div', :attributes => { :class => 'item category_education' }, :descendant => { :tag => 'div', :attributes => { :class => 'steps' }, :descendant => { :tag => 'div', :attributes => { :class => "step #{@block.status_class(@step)}" } } }
  108 + end
  109 +
  110 + should 'render tracks in track card list block' do
  111 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  112 + @block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  113 + @profile.boxes << box
  114 + get :view_page, @step.url
  115 + assert_tag :tag => 'div', :attributes => { :class => 'item_card category_education' }, :descendant => { :tag => 'div', :attributes => { :class => 'track_content' } }
  116 + assert_tag :tag => 'div', :attributes => { :class => 'item_card category_education' }, :descendant => { :tag => 'div', :attributes => { :class => 'track_stats' } }
  117 + end
  118 +
  119 + should 'render link to display more tracks in track list block' do
  120 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  121 + @block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  122 + @profile.boxes << box
  123 +
  124 + (@block.limit+1).times do |i|
  125 + CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @profile)
  126 + end
  127 +
  128 + get :view_page, @step.url
  129 + assert_tag :tag => 'div', :attributes => { :id => "track_list_more_#{@block.id}" }, :descendant => { :tag => 'div', :attributes => { :class => 'more' } }
  130 + end
  131 +
  132 + should 'render link to show all tracks in track list block' do
  133 + box = fast_create(Box, :owner_id => @profile.id, :owner_type => @profile.class.name)
  134 + @block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  135 + @profile.boxes << box
  136 + @block.more_another_page = true
  137 + @block.save!
  138 +
  139 + (@block.limit+1).times do |i|
  140 + CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @profile)
  141 + end
  142 +
  143 + get :view_page, @step.url
  144 + assert_tag :tag => 'div', :attributes => { :id => "track_list_more_#{@block.id}" }, :descendant => { :tag => 'div', :attributes => { :class => 'view_all' } }
  145 + end
  146 +
  147 +end
plugins/community_track/test/functional/community_track_plugin_environment_design_controller_test.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class EnvironmentDesignController; def rescue_action(e) raise e end; end
  5 +
  6 +class EnvironmentDesignControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + Environment.delete_all
  10 + @environment = Environment.new(:name => 'testenv', :is_default => true)
  11 + @environment.enabled_plugins = ['CommunityTrackPlugin']
  12 + @environment.save!
  13 +
  14 + user = create_user('testinguser')
  15 + @environment.add_admin(user.person)
  16 + login_as(user.login)
  17 +
  18 + box = Box.create!(:owner => @environment)
  19 + @block = CommunityTrackPlugin::TrackListBlock.create!(:box => box)
  20 + @block_card = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  21 + end
  22 +
  23 + should 'be able to edit TrackListBlock' do
  24 + get :edit, :id => @block.id
  25 + assert_tag :tag => 'input', :attributes => { :id => 'block_title' }
  26 + end
  27 +
  28 + should 'be able to save TrackListBlock' do
  29 + get :edit, :id => @block.id
  30 + post :save, :id => @block.id, :block => {:title => 'Tracks' }
  31 + @block.reload
  32 + assert_equal 'Tracks', @block.title
  33 + end
  34 +
  35 + should 'be able to edit TrackCardListBlock' do
  36 + get :edit, :id => @block_card.id
  37 + assert_tag :tag => 'input', :attributes => { :id => 'block_title' }
  38 + end
  39 +
  40 + should 'be able to save TrackCardListBlock' do
  41 + get :edit, :id => @block_card.id
  42 + post :save, :id => @block_card.id, :block => {:title => 'Tracks' }
  43 + @block_card.reload
  44 + assert_equal 'Tracks', @block_card.title
  45 + end
  46 +
  47 +end
plugins/community_track/test/functional/community_track_plugin_myprofile_controller_test.rb 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/myprofile/community_track_plugin_myprofile_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class CommunityTrackPluginMyprofileController; def rescue_action(e) raise e end; end
  6 +
  7 +class CommunityTrackPluginMyprofileControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @controller = CommunityTrackPluginMyprofileController.new
  11 + @request = ActionController::TestRequest.new
  12 + @response = ActionController::TestResponse.new
  13 +
  14 + @profile = fast_create(Community)
  15 + @track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track', :profile => @profile)
  16 +
  17 + @user = create_user('testinguser')
  18 + login_as(@user.login)
  19 + @profile.add_admin(@user.person)
  20 + end
  21 +
  22 + should 'redirect to track on save order' do
  23 + get :save_order, :profile => @profile.identifier, :track => @track.id, :step_ids => []
  24 + assert_redirected_to @track.url
  25 + end
  26 +
  27 + should 'save new step positions on save order' do
  28 + step1 = CommunityTrackPlugin::Step.create!(:name => 'step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  29 + step2 = CommunityTrackPlugin::Step.create!(:name => 'step2', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  30 + assert_equal [step1, step2], @track.steps
  31 + get :save_order, :profile => @profile.identifier, :track => @track.id, :step_ids => [step2.id, step1.id]
  32 + assert_equal [step2, step1], @track.steps
  33 + end
  34 +
  35 + should 'do not allow a user without permission to save order' do
  36 + logout
  37 + user = create_user('intruder')
  38 + login_as(user.login)
  39 + get :save_order, :profile => @profile.identifier, :track => @track.id, :step_ids => []
  40 + assert_response 403
  41 + end
  42 +
  43 + should 'redirect to login page if there is no user logged in' do
  44 + logout
  45 + get :save_order, :profile => @profile.identifier, :track => @track.id, :step_ids => []
  46 + assert_response 302
  47 + end
  48 +
  49 +end
plugins/community_track/test/functional/community_track_plugin_public_controller_test.rb 0 → 100644
@@ -0,0 +1,109 @@ @@ -0,0 +1,109 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +require File.dirname(__FILE__) + '/../../controllers/public/community_track_plugin_public_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class CommunityTrackPluginPublicController; def rescue_action(e) raise e end; end
  6 +
  7 +class CommunityTrackPluginPublicControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @community = fast_create(Community)
  11 + @track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track', :profile => @community)
  12 +
  13 + box = fast_create(Box, :owner_id => @community.id, :owner_type => 'Community')
  14 + @card_block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  15 + @block = CommunityTrackPlugin::TrackListBlock.create!(:box => box)
  16 + end
  17 +
  18 + should 'display tracks for card block' do
  19 + xhr :get, :view_tracks, :id => @card_block.id, :page => 1
  20 + assert_match /track_list_#{@card_block.id}/, @response.body
  21 + end
  22 +
  23 + should 'display tracks for list block' do
  24 + xhr :get, :view_tracks, :id => @block.id, :page => 1
  25 + assert_match /track_list_#{@block.id}/, @response.body
  26 + end
  27 +
  28 + should 'display tracks with page size' do
  29 + 20.times do |i|
  30 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  31 + end
  32 + xhr :get, :view_tracks, :id => @block.id, :page => 1, :per_page => 10
  33 + assert_equal 10, @response.body.scan(/item/).size
  34 + end
  35 +
  36 + should 'default page size is the block limit' do
  37 + 20.times do |i|
  38 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  39 + end
  40 + xhr :get, :view_tracks, :id => @block.id, :page => 1
  41 + assert_equal @block.limit, @response.body.scan(/item/).size
  42 + end
  43 +
  44 + should 'display page for all tracks' do
  45 + get :all_tracks, :id => @block.id
  46 + assert_match /track_list_#{@block.id}/, @response.body
  47 + end
  48 +
  49 + should 'show more link in all tracks if there is no more tracks to show' do
  50 + 10.times do |i|
  51 + CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  52 + end
  53 + get :all_tracks, :id => @block.id
  54 + assert assigns['show_more']
  55 + assert_match /track_list_more_#{@block.id}/, @response.body
  56 + end
  57 +
  58 + should 'do not show more link in all tracks if there is no more tracks to show' do
  59 + CommunityTrackPlugin::Track.destroy_all
  60 + get :all_tracks, :id => @block.id
  61 + assert !assigns['show_more']
  62 + assert_no_match /track_list_more_#{@block.id}/, @response.body
  63 + end
  64 +
  65 + should 'show select community page if user is logged in' do
  66 + user = create_user('testinguser')
  67 + login_as(user.login)
  68 + get :select_community
  69 + assert_template 'select_community'
  70 + end
  71 +
  72 + should 'redirect to login page if user try to access community selection' do
  73 + logout
  74 + get :select_community
  75 + assert_redirected_to :controller => 'account', :action => 'login'
  76 + end
  77 +
  78 + should 'display for selection communities where user has permission to post content' do
  79 + user = create_user('testinguser')
  80 + login_as(user.login)
  81 + @community.add_member(user.person)
  82 + get :select_community
  83 + assert_tag :tag => 'li', :attributes => {:class => 'search-profile-item'}
  84 + assert_tag :tag => 'input', :attributes => {:id => "community_identifier_#{@community.identifier}"}
  85 + end
  86 +
  87 + should 'do not display communities where user has not permission to post content' do
  88 + user = create_user('testinguser')
  89 + login_as(user.login)
  90 + get :select_community
  91 + assert_no_tag :tag => 'input', :attributes => {:id => "community_identifier_#{@community.identifier}"}
  92 + end
  93 +
  94 + should 'redirect to new content with track content type' do
  95 + user = create_user('testinguser')
  96 + login_as(user.login)
  97 + post :select_community, :profile => user.person.identifier, :community_identifier => @community.identifier
  98 + assert_redirected_to :controller => 'cms', :action => 'new', :type => "CommunityTrackPlugin::Track", :profile => @community.identifier
  99 + end
  100 +
  101 + should 'return error message if user do not select a community' do
  102 + user = create_user('testinguser')
  103 + login_as(user.login)
  104 + post :select_community, :profile => user.person.identifier, :community_identifier => nil
  105 + assert_equal 1, assigns(:failed).count
  106 + assert_tag :tag => 'div', :attributes => {:id => 'errorExplanation'}
  107 + end
  108 +
  109 +end
plugins/community_track/test/test_helper.rb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
plugins/community_track/test/unit/community_track_plugin/step_helper_test.rb 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class StepHelperTest < ActiveSupport::TestCase
  4 +
  5 + include CommunityTrackPlugin::StepHelper
  6 +
  7 + def setup
  8 + @step = CommunityTrackPlugin::Step.new
  9 + @step.stubs(:active?).returns(false)
  10 + @step.stubs(:finished?).returns(false)
  11 + @step.stubs(:waiting?).returns(false)
  12 + end
  13 +
  14 + should 'return active class when step is active' do
  15 + @step.stubs(:active?).returns(true)
  16 + assert_equal 'step_active', status_class(@step)
  17 + end
  18 +
  19 + should 'return finished class when step is finished' do
  20 + @step.stubs(:finished?).returns(true)
  21 + assert_equal 'step_finished', status_class(@step)
  22 + end
  23 +
  24 + should 'return waiting class when step is active' do
  25 + @step.stubs(:waiting?).returns(true)
  26 + assert_equal 'step_waiting', status_class(@step)
  27 + end
  28 +
  29 + should 'return a description for status' do
  30 + @step.stubs(:waiting?).returns(true)
  31 + assert_equal _('Waiting'), status_description(@step)
  32 + end
  33 +
  34 + should 'return nil at custom_options_for_article' do
  35 + assert !custom_options_for_article(fast_create(Article))
  36 + end
  37 +
  38 +end
plugins/community_track/test/unit/community_track_plugin/step_test.rb 0 → 100644
@@ -0,0 +1,265 @@ @@ -0,0 +1,265 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class StepTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @profile = fast_create(Community)
  7 + @track = CommunityTrackPlugin::Track.create(:profile_id => @profile.id, :name => 'track')
  8 + @step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  9 + Delayed::Job.destroy_all
  10 + end
  11 +
  12 + should 'describe yourself' do
  13 + assert CommunityTrackPlugin::Step.description
  14 + end
  15 +
  16 + should 'has a short description' do
  17 + assert CommunityTrackPlugin::Step.short_description
  18 + end
  19 +
  20 + should 'set published to false on create' do
  21 + today = Date.today
  22 + step = CommunityTrackPlugin::Step.create(:name => 'Step', :body => 'body', :profile => @profile, :parent => @track, :start_date => today, :end_date => today, :published => true)
  23 + assert !step.published
  24 + end
  25 +
  26 + should 'do not allow step creation with a parent that is not a track' do
  27 + today = Date.today
  28 + blog = fast_create(Blog)
  29 + step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => blog, :start_date => today, :end_date => today, :published => true)
  30 + assert !step.save
  31 + end
  32 +
  33 + should 'do not allow step creation without a parent' do
  34 + today = Date.today
  35 + step = CommunityTrackPlugin::Step.new(:name => 'Step', :body => 'body', :profile => @profile, :parent => nil, :start_date => today, :end_date => today, :published => true)
  36 + assert !step.save
  37 + end
  38 +
  39 + should 'create step if end date is equal to start date' do
  40 + @step.start_date = Date.today
  41 + @step.end_date = Date.today
  42 + assert @step.save
  43 + end
  44 +
  45 + should 'create step if end date is after start date' do
  46 + @step.start_date = Date.today
  47 + @step.end_date = Date.today + 1.day
  48 + assert @step.save
  49 + end
  50 +
  51 + should 'do not create step if end date is before start date' do
  52 + @step.start_date = Date.today
  53 + @step.end_date = Date.today - 1.day
  54 + assert !@step.save
  55 + end
  56 +
  57 + should 'do not validate date period if start date is nil' do
  58 + @step.start_date = nil
  59 + @step.end_date_equal_or_after_start_date.inspect
  60 + assert [], @step.errors
  61 + end
  62 +
  63 + should 'do not validate date period if end date is nil' do
  64 + @step.end_date = nil
  65 + @step.end_date_equal_or_after_start_date.inspect
  66 + assert [], @step.errors
  67 + end
  68 +
  69 + should 'be active if today is between start and end dates' do
  70 + @step.start_date = Date.today
  71 + @step.end_date = Date.today + 1.day
  72 + assert @step.active?
  73 + end
  74 +
  75 + should 'be finished if today is after the end date' do
  76 + @step.start_date = Date.today - 2.day
  77 + @step.end_date = Date.today - 1.day
  78 + assert @step.finished?
  79 + end
  80 +
  81 + should 'be waiting if today is before the end date' do
  82 + @step.start_date = Date.today + 1.day
  83 + @step.end_date = Date.today + 2.day
  84 + assert @step.waiting?
  85 + end
  86 +
  87 + should 'return delayed job created with a specific step_id' do
  88 + step_id = 0
  89 + CommunityTrackPlugin::ActivationJob.new(step_id)
  90 + assert CommunityTrackPlugin::ActivationJob.find(step_id)
  91 + end
  92 +
  93 + should 'create delayed job' do
  94 + @step.start_date = Date.today
  95 + @step.end_date = Date.today
  96 + @step.schedule_activation
  97 + assert_equal 1, Delayed::Job.count
  98 + assert_equal @step.start_date, Delayed::Job.first.run_at.to_date
  99 + end
  100 +
  101 + should 'do not duplicate delayed job' do
  102 + @step.start_date = Date.today
  103 + @step.end_date = Date.today
  104 + @step.schedule_activation
  105 + @step.schedule_activation
  106 + assert_equal 1, Delayed::Job.count
  107 + end
  108 +
  109 + should 'create delayed job when a step is saved' do
  110 + @step.start_date = Date.today
  111 + @step.end_date = Date.today
  112 + @step.save!
  113 + assert_equal @step.start_date, Delayed::Job.first.run_at.to_date
  114 + end
  115 +
  116 + should 'create delayed job even if start date has passed' do
  117 + @step.start_date = Date.today - 2.days
  118 + @step.end_date = Date.today
  119 + @step.schedule_activation
  120 + assert_equal @step.start_date, Delayed::Job.first.run_at.to_date
  121 + end
  122 +
  123 + should 'do not create delayed job if end date has passed and step is not published' do
  124 + @step.start_date = Date.today - 5.days
  125 + @step.end_date = Date.today - 2.days
  126 + @step.published = false
  127 + @step.schedule_activation
  128 + assert_equal 0, Delayed::Job.count
  129 + end
  130 +
  131 + should 'create delayed job if end date has passed and step is published' do
  132 + @step.start_date = Date.today - 5.days
  133 + @step.end_date = Date.today - 2.days
  134 + @step.published = true
  135 + @step.schedule_activation
  136 + assert_equal @step.end_date + 1.day, Delayed::Job.first.run_at.to_date
  137 + end
  138 +
  139 + should 'change publish to true on perform delayed job in a active step' do
  140 + @step.start_date = Date.today
  141 + @step.end_date = Date.today + 2.days
  142 + @step.published = false
  143 + @step.save!
  144 + CommunityTrackPlugin::ActivationJob.new(@step.id).perform
  145 + @step.reload
  146 + assert @step.published
  147 + end
  148 +
  149 + should 'reschedule delayed job after change publish to true' do
  150 + @step.start_date = Date.today
  151 + @step.end_date = Date.today + 2.days
  152 + @step.published = false
  153 + @step.save!
  154 + assert_equal @step.start_date, Delayed::Job.first.run_at.to_date
  155 + process_delayed_job_queue
  156 + assert_equal @step.end_date + 1.day, Delayed::Job.first.run_at.to_date
  157 + end
  158 +
  159 + should 'do not schedule delayed job if save but do not modify date fields and published status' do
  160 + @step.start_date = Date.today
  161 + @step.end_date = Date.today
  162 + @step.published = false
  163 + @step.save!
  164 + assert_equal 1, Delayed::Job.count
  165 + Delayed::Job.destroy_all
  166 + @step.name = 'changed name'
  167 + @step.save!
  168 + assert_equal 0, Delayed::Job.count
  169 + end
  170 +
  171 + should 'set position on save' do
  172 + assert !@step.position
  173 + @step.save!
  174 + assert_equal 1, @step.position
  175 + step2 = CommunityTrackPlugin::Step.new(:name => 'Step2', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  176 + step2.save!
  177 + assert_equal 2, step2.position
  178 + end
  179 +
  180 + should 'publish step if it is active' do
  181 + @step.start_date = Date.today
  182 + @step.save!
  183 + assert !@step.published
  184 + @step.publish
  185 + @step.reload
  186 + assert @step.published
  187 + end
  188 +
  189 + should 'do not publish step if it is not active' do
  190 + @step.start_date = Date.today + 2.days
  191 + @step.end_date = Date.today + 3.days
  192 + @step.save!
  193 + assert !@step.published
  194 + @step.publish
  195 + @step.reload
  196 + assert !@step.published
  197 + end
  198 +
  199 + should 'unpublish step if it is not active anymore' do
  200 + @step.start_date = Date.today
  201 + @step.save!
  202 + @step.publish
  203 + @step.reload
  204 + assert @step.published
  205 +
  206 + @step.start_date = Date.today - 2.days
  207 + @step.end_date = Date.today - 1.day
  208 + @step.save!
  209 + @step.publish
  210 + @step.reload
  211 + assert !@step.published
  212 + end
  213 +
  214 + should 'set position to zero if step is hidden' do
  215 + @step.hidden = true
  216 + @step.save!
  217 + assert_equal 0, @step.position
  218 + end
  219 +
  220 + should 'change position to zero if step becomes hidden' do
  221 + @step.save!
  222 + assert_equal 1, @step.position
  223 + @step.hidden = true
  224 + @step.save!
  225 + assert_equal 0, @step.position
  226 + end
  227 +
  228 + should 'change position to botton if a hidden step becomes visible' do
  229 + step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  230 + step1.save!
  231 + @step.hidden = true
  232 + @step.save!
  233 + assert_equal 0, @step.position
  234 + @step.hidden = false
  235 + @step.save!
  236 + assert_equal 2, @step.position
  237 + end
  238 +
  239 + should 'decrement lower items positions if a step becomes hidden' do
  240 + @step.save!
  241 + step1 = CommunityTrackPlugin::Step.new(:name => 'Step1', :body => 'body', :profile => @profile, :parent => @track, :published => false, :end_date => Date.today, :start_date => Date.today)
  242 + step1.save!
  243 + assert_equal 2, step1.position
  244 + @step.hidden = true
  245 + @step.save!
  246 + step1.reload
  247 + assert_equal 1, step1.position
  248 + end
  249 +
  250 + should 'do not publish a hidden step' do
  251 + @step.start_date = Date.today
  252 + @step.hidden = true
  253 + @step.save!
  254 + assert !@step.published
  255 + @step.publish
  256 + @step.reload
  257 + assert !@step.published
  258 + end
  259 +
  260 + should 'return enabled tools for a step' do
  261 + assert_includes @step.enabled_tools, TinyMceArticle
  262 + assert_includes @step.enabled_tools, Forum
  263 + end
  264 +
  265 +end
plugins/community_track/test/unit/community_track_plugin/track_card_list_block_test.rb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class TrackCardListBlockTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @community = fast_create(Community)
  7 + box = fast_create(Box, :owner_id => @community.id, :owner_type => @community.class.name)
  8 + @block = CommunityTrackPlugin::TrackCardListBlock.create!(:box => box)
  9 + end
  10 +
  11 + should 'describe yourself' do
  12 + assert CommunityTrackPlugin::TrackCardListBlock.description
  13 + end
  14 +
  15 + should 'return track_card as track partial' do
  16 + assert_equal 'track_card', @block.track_partial
  17 + end
  18 +
  19 +end
plugins/community_track/test/unit/community_track_plugin/track_helper_test.rb 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class TrackHelperTest < ActiveSupport::TestCase
  4 +
  5 + include CommunityTrackPlugin::TrackHelper
  6 + include NoosferoTestHelper
  7 + include ActionView::Helpers::TextHelper
  8 +
  9 + def setup
  10 + @track = CommunityTrackPlugin::Track.new
  11 + end
  12 +
  13 + should 'return css class for track with category' do
  14 + category = fast_create(Category, :name => 'education')
  15 + @track.categories << category
  16 + assert_equal 'category_education', category_class(@track)
  17 + end
  18 +
  19 + should 'return default css class for a track without category' do
  20 + assert_equal 'category_not_defined', category_class(@track)
  21 + end
  22 +
  23 + should 'return css class for first category that the class belongs' do
  24 + category1 = fast_create(Category, :name => 'education')
  25 + @track.categories << category1
  26 + category2 = fast_create(Category, :name => 'tech')
  27 + @track.categories << category2
  28 + assert_equal 'category_education', category_class(@track)
  29 + end
  30 +
  31 + should 'return css class with category name properly formated' do
  32 + category = fast_create(Category, :name => 'not defined')
  33 + @track.categories << category
  34 + assert_equal 'category_not-defined', category_class(@track)
  35 + end
  36 +
  37 + should 'return lead for track removing html tags' do
  38 + @track.abstract = "display <div>pure text</div>"
  39 + assert_equal "display pure text", track_card_lead(@track)
  40 + end
  41 +
  42 + should 'limit lead char length' do
  43 + @track.abstract = ""
  44 + 400.times { @track.abstract += "a" }
  45 + assert_equal 306, track_card_lead(@track).length
  46 + end
  47 +
  48 + should 'display a shorter lead if track has a image' do
  49 + @track.abstract = ""
  50 + @track.image = Image.new
  51 + 400.times { @track.abstract += "a" }
  52 + assert_equal 186, track_card_lead(@track).length
  53 + end
  54 +
  55 +end
plugins/community_track/test/unit/community_track_plugin/track_list_block_test.rb 0 → 100644
@@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class TrackListBlockTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @community = fast_create(Community)
  7 + @track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track', :profile => @community)
  8 +
  9 + box = fast_create(Box, :owner_id => @community.id, :owner_type => @community.class.name)
  10 + @block = CommunityTrackPlugin::TrackListBlock.create!(:box => box)
  11 + end
  12 +
  13 + should 'describe yourself' do
  14 + assert CommunityTrackPlugin::TrackListBlock.description
  15 + end
  16 +
  17 + should 'return track as track partial' do
  18 + assert_equal 'track', @block.track_partial
  19 + end
  20 +
  21 + should 'load more at another page default to false' do
  22 + assert !@block.more_another_page
  23 + end
  24 +
  25 + should 'list articles only of track type' do
  26 + article = fast_create(Article, :profile_id => @community.id)
  27 + assert_includes @community.articles, article
  28 + assert_equal [@track], @block.tracks
  29 + end
  30 +
  31 + should 'list of articles be limited by block configuration' do
  32 + (@block.limit + 1).times do |i|
  33 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  34 + end
  35 + assert_equal @block.limit, @block.tracks.count
  36 + end
  37 +
  38 + should 'return more link if has more tracks to show' do
  39 + @block.limit.times do |i|
  40 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  41 + end
  42 + assert @block.footer
  43 + end
  44 +
  45 + should 'do not return more link if there is no more tracks to show' do
  46 + (@block.limit-1).times do |i|
  47 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  48 + end
  49 + assert !@block.footer
  50 + end
  51 +
  52 + should 'count all tracks' do
  53 + @block.owner.articles.destroy_all
  54 + tracks_to_insert = @block.limit + 1
  55 + tracks_to_insert.times do |i|
  56 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  57 + end
  58 + article = fast_create(Article, :profile_id => @block.owner.id)
  59 + @block.reload
  60 + assert_includes @block.owner.articles, article
  61 + assert_equal tracks_to_insert, @block.count_tracks
  62 + end
  63 +
  64 + should 'have a second page if there is more tracks than limit' do
  65 + @block.owner.articles.destroy_all
  66 + (@block.limit+1).times do |i|
  67 + track = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => "track#{i}", :profile => @community)
  68 + end
  69 + assert @block.has_page?(2)
  70 + assert !@block.has_page?(3)
  71 + end
  72 +
  73 + should 'filter tracks by category' do
  74 + @block.owner.articles.destroy_all
  75 + category = fast_create(Category)
  76 + category2 = fast_create(Category)
  77 + track1 = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track1', :profile => @community)
  78 + track2 = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track2', :profile => @community)
  79 + track3 = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track3', :profile => @community)
  80 + track1.add_category(category)
  81 + @block.category_ids = [category.id]
  82 + assert_equal [track1], @block.all_tracks
  83 + end
  84 +
  85 + should 'return all tracks if block does not filter by category' do
  86 + @block.owner.articles.destroy_all
  87 + category = fast_create(Category)
  88 + track1 = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track1', :profile => @community)
  89 + track2 = CommunityTrackPlugin::Track.create!(:abstract => 'abstract', :body => 'body', :name => 'track2', :profile => @community)
  90 + track1.add_category(category)
  91 + assert_includes @block.all_tracks, track1
  92 + assert_includes @block.all_tracks, track2
  93 + end
  94 +
  95 + should 'accept any categories' do
  96 + assert @block.accept_category?(nil)
  97 + assert @block.accept_category?(fast_create(Category))
  98 + end
  99 +
  100 + should 'format category ids array avoiding duplicates and zeros' do
  101 + @block.category_ids = ["0", "0", "1", "1", "2", nil]
  102 + assert_equal [1, 2], @block.category_ids
  103 + end
  104 +
  105 +end
plugins/community_track/test/unit/community_track_plugin/track_test.rb 0 → 100644
@@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
  1 +require File.dirname(__FILE__) + '/../../test_helper'
  2 +
  3 +class TrackTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + profile = fast_create(Community)
  7 + @track = CommunityTrackPlugin::Track.create!(:profile => profile, :name => 'track')
  8 + @step = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => 'step', :profile => profile)
  9 + @tool = fast_create(Article, :parent_id => @step.id, :profile_id => profile.id)
  10 + end
  11 +
  12 + should 'describe yourself' do
  13 + assert CommunityTrackPlugin::Track.description
  14 + end
  15 +
  16 + should 'has a short descriptionf' do
  17 + assert CommunityTrackPlugin::Track.short_description
  18 + end
  19 +
  20 + should 'has a css class name' do
  21 + assert_equal 'community-track-plugin-track', @track.css_class_name
  22 + end
  23 +
  24 + should 'return comments count of children tools' do
  25 + assert_equal 0, @track.comments_count
  26 + owner = create_user('testuser').person
  27 + article = create(Article, :name => 'article', :parent_id => @step.id, :profile_id => owner.id)
  28 + comment = create(Comment, :source => article, :author_id => owner.id)
  29 + assert_equal 1, @track.comments_count
  30 + end
  31 +
  32 + should 'return children steps' do
  33 + assert_equal [@step], @track.steps_unsorted
  34 + end
  35 +
  36 + should 'do not return other articles type at steps' do
  37 + article = fast_create(Article, :parent_id => @track.id, :profile_id => @track.profile.id)
  38 + assert_includes @track.children, article
  39 + assert_equal [@step], @track.steps_unsorted
  40 + end
  41 +
  42 + should 'return category name' do
  43 + category = fast_create(Category, :name => 'category')
  44 + @track.add_category(category, true)
  45 + assert_equal 'category', @track.category_name
  46 + end
  47 +
  48 + should 'return empty for category name if it has no category' do
  49 + @track.categories.delete_all
  50 + assert_equal '', @track.category_name
  51 + end
  52 +
  53 + should 'return category name of first category' do
  54 + category = fast_create(Category, :name => 'category')
  55 + @track.add_category(category, true)
  56 + category2 = fast_create(Category, :name => 'category2')
  57 + @track.add_category(category2, true)
  58 + assert_equal 'category', @track.category_name
  59 + end
  60 +
  61 + should 'return steps with insert order' do
  62 + @track.children.destroy_all
  63 + step1 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step1", :profile => @track.profile)
  64 + step2 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step2", :profile => @track.profile)
  65 + step3 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step3", :profile => @track.profile)
  66 + assert_equal 1, step1.position
  67 + assert_equal 2, step2.position
  68 + assert_equal 3, step3.position
  69 + assert_equal [step1, step2, step3], @track.steps
  70 + end
  71 +
  72 + should 'return steps with order defined by position attribute' do
  73 + @track.children.destroy_all
  74 + step1 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step1", :profile => @track.profile)
  75 + step2 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step2", :profile => @track.profile)
  76 + step3 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step3", :profile => @track.profile)
  77 + step1.position = 3
  78 + step1.save!
  79 + step2.position = 1
  80 + step2.save!
  81 + step3.position = 2
  82 + step3.save!
  83 + assert_equal [step2, step3, step1], @track.steps
  84 + end
  85 +
  86 + should 'save steps in a new order' do
  87 + @track.children.destroy_all
  88 +
  89 + step1 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step1", :profile => @track.profile)
  90 + step2 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step2", :profile => @track.profile)
  91 + step3 = CommunityTrackPlugin::Step.create!(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => "step3", :profile => @track.profile)
  92 +
  93 + assert_equal [step1.id, step2.id, step3.id], @track.steps.map(&:id)
  94 + @track.reorder_steps([step3.id, step1.id, step2.id])
  95 + @track.reload
  96 + assert_equal [step3.id, step1.id, step2.id], @track.steps.map(&:id)
  97 + end
  98 +
  99 + should 'do not return hidden steps' do
  100 + hidden_step = CommunityTrackPlugin::Step.new(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => 'hidden step', :profile => @track.profile)
  101 + hidden_step.hidden = true
  102 + hidden_step.save!
  103 + assert_equal [@step], @track.steps
  104 + end
  105 +
  106 + should 'return hidden steps' do
  107 + hidden_step = CommunityTrackPlugin::Step.new(:parent => @track, :start_date => Date.today, :end_date => Date.today, :name => 'hidden step', :profile => @track.profile)
  108 + hidden_step.hidden = true
  109 + hidden_step.save!
  110 + assert_equal [hidden_step], @track.hidden_steps
  111 + end
  112 +
  113 +end
plugins/community_track/test/unit/community_track_plugin_test.rb 0 → 100644
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class CommunityTrackPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = CommunityTrackPlugin.new
  7 + @profile = fast_create(Community)
  8 + @params = {}
  9 + @plugin.stubs(:context).returns(self)
  10 + end
  11 +
  12 + attr_reader :profile, :params
  13 +
  14 + should 'has name' do
  15 + assert CommunityTrackPlugin.plugin_name
  16 + end
  17 +
  18 + should 'describe yourself' do
  19 + assert CommunityTrackPlugin.plugin_description
  20 + end
  21 +
  22 + should 'has stylesheet' do
  23 + assert @plugin.stylesheet?
  24 + end
  25 +
  26 + should 'return Track as a content type if profile is a community' do
  27 + assert_includes @plugin.content_types, CommunityTrackPlugin::Track
  28 + end
  29 +
  30 + should 'do not return Track as a content type if profile is not a community' do
  31 + @profile = Organization.new
  32 + assert_not_includes @plugin.content_types, CommunityTrackPlugin::Track
  33 + end
  34 +
  35 + should 'do not return Track as a content type if there is a parent' do
  36 + parent = fast_create(Blog, :profile_id => @profile.id)
  37 + @params[:parent_id] = parent.id
  38 + assert_not_includes @plugin.content_types, CommunityTrackPlugin::Track
  39 + end
  40 +
  41 + should 'return Step as a content type if parent is a Track' do
  42 + parent = fast_create(CommunityTrackPlugin::Track, :profile_id => @profile.id)
  43 + @params[:parent_id] = parent.id
  44 + assert_includes @plugin.content_types, CommunityTrackPlugin::Step
  45 + end
  46 +
  47 + should 'do not return Step as a content type if parent is not a Track' do
  48 + parent = fast_create(Blog, :profile_id => @profile.id)
  49 + @params[:parent_id] = parent.id
  50 + assert_not_includes @plugin.content_types, CommunityTrackPlugin::Step
  51 + end
  52 +
  53 + should 'return Track and Step as a content type if context has no params' do
  54 + parent = fast_create(Blog, :profile_id => @profile.id)
  55 + expects(:respond_to?).with(:params).returns(false)
  56 + assert_equivalent [CommunityTrackPlugin::Step, CommunityTrackPlugin::Track], @plugin.content_types
  57 + end
  58 +
  59 + should 'return Track and Step as a content type if params is nil' do
  60 + parent = fast_create(Blog, :profile_id => @profile.id)
  61 + @params = nil
  62 + assert_equivalent [CommunityTrackPlugin::Step, CommunityTrackPlugin::Track], @plugin.content_types
  63 + end
  64 +
  65 + should 'return track card as an extra block' do
  66 + assert_includes CommunityTrackPlugin.extra_blocks, CommunityTrackPlugin::TrackListBlock
  67 + end
  68 +
  69 + should 'return true at content_remove_new if page is a track' do
  70 + assert @plugin.content_remove_new(CommunityTrackPlugin::Track.new)
  71 + end
  72 +
  73 + should 'return false at content_remove_new if page is not a track' do
  74 + assert !@plugin.content_remove_new(CommunityTrackPlugin::Step.new)
  75 + assert !@plugin.content_remove_new(Article.new)
  76 + end
  77 +
  78 +end
plugins/community_track/views/blocks/_track.rhtml 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<% extend CommunityTrackPlugin::TrackHelper %>
  2 +<div class="item <%= category_class(track) %>">
  3 + <div class="track_content">
  4 + <div class="lead">
  5 + <h3><%= link_to track.name, track.url %></h3>
  6 + <div class="content">
  7 + <%= track.lead %>
  8 + </div>
  9 + </div>
  10 + <div class="steps">
  11 + <h3><%= _("Steps") %></h3>
  12 + <% track.steps.each do |step| %>
  13 + <div class="step <%= block.status_class(step) %>">
  14 + <div class="position"><%= step.position %></div>
  15 + <%= link_to step.name, step.url %>
  16 + </div>
  17 + <% end %>
  18 + </div>
  19 + </div>
  20 +</div>
  21 +<br style="clear: both;"/>
plugins/community_track/views/blocks/_track_card.rhtml 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +<% extend CommunityTrackPlugin::TrackHelper %>
  2 +<div class="item_card <%= category_class(track_card) %>">
  3 + <a href="<%= url_for track_card.url %>">
  4 + <div class="track_content">
  5 + <div class="title">
  6 + <%= track_card.category_name %>
  7 + </div>
  8 + <div class="image">
  9 + <%= image_tag track_card.image.public_filename if track_card.image %>
  10 + </div>
  11 + <div class="name">
  12 + <%= track_card.name %>
  13 + </div>
  14 + <div class="lead">
  15 + <%= track_card_lead(track_card) %>
  16 + </div>
  17 + </div>
  18 + <div class="track_stats">
  19 + <div class="comments">
  20 + <%= "#{track_card.comments_count} comments" %>
  21 + </div>
  22 + <div class="hits">
  23 + <%= "#{track_card.hits} hits" %>
  24 + </div>
  25 + </div>
  26 + </a>
  27 +</div>
plugins/community_track/views/blocks/_track_list_more.rhtml 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<% force_same_page ||= false %>
  2 +<div id="track_list_more_<%= block.id %>" class="more_button">
  3 + <% if block.more_another_page && !force_same_page %>
  4 + <div class="view_all">
  5 + <%= link_to _('View All'), :id => block.id, :controller => 'community_track_plugin_public', :action => 'all_tracks' %>
  6 + </div>
  7 + <% else %>
  8 + <div class="more">
  9 + <%= link_to_remote(_('More'), :url => {:id => block.id, :controller => 'community_track_plugin_public', :action => 'view_tracks', :page => page, :per_page => per_page, :force_same_page => force_same_page}, :loaded => visual_effect(:highlight, "track_card_list_#{block.id}")) %>
  10 + </div>
  11 + <% end %>
  12 +</div>
plugins/community_track/views/blocks/track_list.rhtml 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<%= block_title(block.title) %>
  2 +
  3 +<div class="track_list" id="track_list_<%= block.id %>">
  4 + <%= render :partial => "blocks/#{block.track_partial}", :collection => block.tracks, :locals => {:block => block} %>
  5 +</div>
  6 +<br style="clear: both;"/>
plugins/community_track/views/box_organizer/community_track_plugin/_track_list_block.rhtml 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<div id='edit-track-list-block'>
  2 + <%= labelled_form_field _('Limit of items'), text_field(:block, :limit, :size => 3) %>
  3 + <%= labelled_form_field check_box(:block, :more_another_page) + _('Show more at another page'), '' %>
  4 + <%= select_categories(:block, _('Select Categories')) %>
  5 +<br/>
  6 +</div>
plugins/community_track/views/cms/community_track_plugin/_step.rhtml 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<%= required_fields_message %>
  2 +
  3 +<%= render :file => 'shared/tiny_mce' %>
  4 +
  5 +<div>
  6 + <%= required f.text_field('name', :size => '64', :maxlength => 150) %>
  7 + <%= labelled_form_field(_('Start date'), pick_date(:article, :start_date)) %>
  8 + <%= labelled_form_field(_('End date'), pick_date(:article, :end_date)) %>
  9 +</div>
  10 +
  11 +<%= labelled_form_field check_box(:article, :hidden) + _('Hidden Step'), '' %>
  12 +
  13 +<%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :body_label => 'Description:'} %>
plugins/community_track/views/cms/community_track_plugin/_track.rhtml 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +<div class='community-track'>
  2 + <%= required_fields_message %>
  3 +
  4 + <%= render :file => 'shared/tiny_mce' %>
  5 +
  6 + <div>
  7 + <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64', :maxlength => 150)) %>
  8 + </div>
  9 +
  10 + <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :body_label => 'Description:'} %>
  11 +
  12 + <div>
  13 + <% f.fields_for :image_builder, @article.image do |i| %>
  14 + <%= file_field_or_thumbnail(_('Image:'), @article.image, i) %>
  15 + <% end %>
  16 +
  17 + <%= labelled_form_field(_('Goals:'), text_area(:article, :goals, :rows => 3, :cols => 64)) %>
  18 + <%= labelled_form_field(_('Expected Results:'), text_area(:article, :expected_results, :rows => 3, :cols => 64)) %>
  19 + </div>
  20 +</div>
plugins/community_track/views/community_track_plugin_public/all_tracks.rhtml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<h1><%= _('Tracks') %></h1>
  2 +<div class="all_tracks">
  3 + <div class="track_list track_card_list" id="track_list_<%= @block.id %>">
  4 + <%= render :partial => "blocks/#{@block.track_partial}", :collection => @tracks, :locals => {:block => @block} %>
  5 + </div>
  6 + <br style="clear: both;"/>
  7 + <% if @show_more %>
  8 + <%= render :partial => "blocks/track_list_more", :locals => {:block => @block, :force_same_page => true, :page => 2, :per_page => @per_page} %>
  9 + <% end %>
  10 +</div>
plugins/community_track/views/community_track_plugin_public/select_community.rhtml 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +<div>
  2 +
  3 +<h1><%= _('Select Community') %></h1>
  4 +
  5 +<% if !@failed.blank? %>
  6 + <div class="errorExplanation" id="errorExplanation">
  7 + <div style="color: #c00;">
  8 + <% @failed.each do |error|%>
  9 + <strong> <%= error %></strong>
  10 + <% end %>
  11 + </div>
  12 + </div>
  13 +<% end %>
  14 +
  15 +<% button_bar do %>
  16 + <%= button(:add, __('Create a new community'), :controller => 'memberships', :action => 'new_community', :profile => user.identifier, :back_to => @back_to) %>
  17 +<% end %>
  18 +
  19 +<% form_tag({:controller => 'community_track_plugin_public', :action => 'select_community', :profile => user.identifier}) do %>
  20 +<div class="common-profile-list-block">
  21 + <ul>
  22 + <% @communities.each do |community| %>
  23 + <li class="search-profile-item">
  24 + <div class="common-profile-list-block">
  25 + <div class="vcard">
  26 + <a href="#" onclick="jQuery('<%= "#community_identifier_#{community.identifier}" %>').attr('checked', true);">
  27 + <span class="profile-image"><%= profile_image(community) %></span>
  28 + <span class="org"><%= community.name %></span>
  29 + <span class="select_community"><%= radio_button_tag(:community_identifier, community.identifier) %></span>
  30 + </a>
  31 + </div>
  32 + </div>
  33 + </li>
  34 + <% end %>
  35 + </ul>
  36 + </div>
  37 + <div class="clear"></div>
  38 + <br/>
  39 + <%= submit_button :save, _('New Track') %>
  40 +<% end %>
  41 +</div>
plugins/community_track/views/content_viewer/step.rhtml 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +<div id="step">
  2 + <div class="event-info">
  3 + <ul class="event-data">
  4 + <li class="event-dates">
  5 + <span><%= _('When:') %></span><%= show_period(step.start_date, step.end_date) %>
  6 + </li>
  7 + </ul>
  8 + </div>
  9 + <div>
  10 + <%= step.body %>
  11 + </div>
  12 + <h3><%= _("Tools") %></h3>
  13 + <% if step.allow_create?(user) %>
  14 + <div class="actions">
  15 + <% step.enabled_tools.each do |klass, attrs| %>
  16 + <% content_tag('a', :href => url_for({:controller => 'cms', :action => 'new', :type => klass.name, :parent_id => @page}), :class => "button with-text icon-new icon-new#{klass.icon_name}") do %>
  17 + <%= _("New #{attrs[:name]}") %>
  18 + <% end %>
  19 + <% end %>
  20 + </div>
  21 + <% end %>
  22 + <div class="tools">
  23 + <% step.tools.each do |tool| %>
  24 + <div class="item">
  25 + <div class="name">
  26 + <%= link_to tool.name, tool.url, :class=>"button with-text icon-new icon-new#{tool.class.icon_name}" %>
  27 + </div>
  28 + </div>
  29 + <% end %>
  30 + </div>
  31 +</div>
plugins/community_track/views/content_viewer/track.rhtml 0 → 100644
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
  1 +<% extend CommunityTrackPlugin::StepHelper %>
  2 +
  3 +<% form_tag({:controller => 'community_track_plugin_myprofile', :action => 'save_order', :track => track}) do %>
  4 +<div id="track">
  5 + <div>
  6 + <%= track.body %>
  7 + </div>
  8 +
  9 + <h3><%= _("Steps") %></h3>
  10 +
  11 + <% if track.allow_create?(user) %>
  12 + <div class="actions">
  13 + <% content_tag('a', :href => url_for({:controller => 'cms', :action => 'new', :type => "CommunityTrackPlugin::Step", :parent_id => track.id}), :class => 'button with-text icon-add') do %>
  14 + <strong><%= _("New %s") % CommunityTrackPlugin::Step.short_description %></strong>
  15 + <% end %>
  16 + <a href="#" class="reorder_button button with-text icon-up" onclick="enableReorder();"><%= _('Reorder Steps') %></a>
  17 + <%= submit_button :save, _('Save Order'), :class => "save_button" %>
  18 + </div>
  19 + <script>
  20 + function enableReorder() {
  21 + jQuery(".reorder_button").hide();
  22 + jQuery(".save_button").show();
  23 + jQuery("#sortable li").addClass("ui-state-default");
  24 + jQuery("#sortable").sortable();
  25 + jQuery("#sortable").disableSelection();
  26 + }
  27 + </script>
  28 + <% end %>
  29 +
  30 + <ul id="sortable" class="step_list">
  31 + <% track.steps.each do |step| %>
  32 + <li class="step">
  33 + <%= hidden_field_tag "step_ids[]", step.id %>
  34 + <div class="position"><%= step.position %></div>
  35 + <div class="content">
  36 + <div class="date">
  37 + <%= show_period(step.start_date, step.end_date) %>
  38 + </div>
  39 + <div class="name"><%= link_to step.name, step.url %></div>
  40 + <div class="lead"><%= step.body %></div>
  41 + </div>
  42 + </li>
  43 + <% end %>
  44 + </ul>
  45 + <% if track.allow_create?(user) && !track.hidden_steps.empty? %>
  46 + <div id="hidden_steps">
  47 + <h3><%= _('Hidden Steps') %></h3>
  48 + <ul class="step_list">
  49 + <% track.hidden_steps.each do |step| %>
  50 + <li class="step">
  51 + <%= hidden_field_tag "step_ids[]", step.id %>
  52 + <div class="position"></div>
  53 + <div class="content">
  54 + <div class="date">
  55 + <%= show_period(step.start_date, step.end_date) %>
  56 + </div>
  57 + <div class="name"><%= link_to step.name, step.url %></div>
  58 + <div class="lead"><%= step.body %></div>
  59 + </div>
  60 + </li>
  61 + <% end %>
  62 + </ul>
  63 + </div>
  64 + <% end %>
  65 +</div>
  66 +<% end %>
  67 +</div>
plugins/community_track/views/environment_design/community_track_plugin 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +../box_organizer/community_track_plugin
0 \ No newline at end of file 2 \ No newline at end of file
plugins/community_track/views/profile_design/community_track_plugin 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +../box_organizer/community_track_plugin
0 \ No newline at end of file 2 \ No newline at end of file
plugins/custom_forms/test/functional/custom_forms_plugin_myprofile_controller_test.rb
@@ -140,5 +140,14 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase @@ -140,5 +140,14 @@ class CustomFormsPluginMyprofileControllerTest &lt; ActionController::TestCase
140 assert_equal 'Cool form', form.description 140 assert_equal 'Cool form', form.description
141 assert_equal 'Source', field.name 141 assert_equal 'Source', field.name
142 end 142 end
  143 +
  144 + should 'render TinyMce Editor for description' do
  145 + form = CustomFormsPlugin::Form.create!(:profile => profile, :name => 'Free Software')
  146 +
  147 + get :edit, :profile => profile.identifier, :id => form.id
  148 +
  149 + assert_tag :tag => 'textarea', :attributes => { :id => 'form_description', :class => 'mceEditor' }
  150 + end
  151 +
143 end 152 end
144 153
plugins/custom_forms/views/custom_forms_plugin_myprofile/_form.html.erb
1 <% self.extend(CustomFormsPlugin::Helper) %> 1 <% self.extend(CustomFormsPlugin::Helper) %>
  2 +<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
2 3
3 <%= error_messages_for :form %> 4 <%= error_messages_for :form %>
4 5
@@ -15,7 +16,7 @@ @@ -15,7 +16,7 @@
15 <% if profile.organization? %> 16 <% if profile.organization? %>
16 <%= labelled_form_field _('Triggered on membership'), f.check_box(:on_membership) %> 17 <%= labelled_form_field _('Triggered on membership'), f.check_box(:on_membership) %>
17 <% end %> 18 <% end %>
18 - <%= labelled_form_field _('Description'), f.text_area(:description, :style => 'width: 100%') %> 19 + <%= labelled_form_field _('Description'), f.text_area(:description, :style => 'width: 100%', :class => 'mceEditor') %>
19 20
20 <h2><%= _('Fields') %></h2> 21 <h2><%= _('Fields') %></h2>
21 <table class="action-table" id='fields-table'> 22 <table class="action-table" id='fields-table'>
plugins/display_content/lib/display_content_block.rb
@@ -111,4 +111,8 @@ class DisplayContentBlock &lt; Block @@ -111,4 +111,8 @@ class DisplayContentBlock &lt; Block
111 return parents 111 return parents
112 end 112 end
113 113
  114 + def self.expire_on
  115 + { :profile => [:article], :environment => [:article] }
  116 + end
  117 +
114 end 118 end
plugins/html5_video/lib/file_presenter/video.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class FilePresenter::Video < FilePresenter
  2 + def self.accepts?(f)
  3 + return nil if !f.respond_to?(:content_type) || f.content_type.nil?
  4 + ( f.content_type[0..4] == 'video' ) ? 10 : nil
  5 + end
  6 +
  7 + def short_description
  8 + _('Video (%s)') % content_type.split('/')[1].upcase
  9 + end
  10 +end
plugins/html5_video/lib/html5_video_plugin.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class Html5VideoPlugin < Noosfero::Plugin
  2 +
  3 + FilePresenter::Video
  4 +
  5 + def self.plugin_name
  6 + "HTML5 Video"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("A plugin to enable the video suport, with auto conversion for the web.")
  11 + end
  12 +
  13 +end
plugins/html5_video/test/functional/content_viewer_controler_test.rb 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +require 'content_viewer_controller'
  3 +
  4 +class ContentViewerController
  5 + # Re-raise errors caught by the controller.
  6 + def rescue_action(e) raise e end
  7 + append_view_path File.join(File.dirname(__FILE__) + '/../../views')
  8 +end
  9 +
  10 +class ContentViewerControllerTest < ActionController::TestCase
  11 +
  12 + all_fixtures
  13 +
  14 + def setup
  15 + @controller = ContentViewerController.new
  16 + @request = ActionController::TestRequest.new
  17 + @response = ActionController::TestResponse.new
  18 +
  19 + @profile = create_user('testinguser').person
  20 + @environment = @profile.environment
  21 + end
  22 + attr_reader :profile, :environment
  23 +
  24 + should 'add html5 video tag to the page of file type video' do
  25 + file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'video/ogg'), :profile => profile)
  26 + get :view_page, file.url.merge(:view=>:true)
  27 + assert_select '#article video'
  28 + end
  29 +
  30 +end
plugins/html5_video/views/file_presenter/_video.html.erb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<video class="video-js vjs-default-skin" controls poster="video.jpg" preload="auto" data-setup="{}">
  2 + <source type="video/ogg" src="<%= video.public_filename %>"/>
  3 +</video>
  4 +
  5 +<div class="uploaded-file-description <%= 'empty' if video.abstract.blank? %>">
  6 + <%= video.abstract %>
  7 +</div>
  8 +
plugins/video/README 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +README - Video (Video Plugin)
  2 +================================
  3 +
  4 +Video is a plugin that allow users to add a block where you can choose
  5 +any url from youtube, vimeo and url's of the following file formats:
  6 +mp4, ogg, ogv and webm.
  7 +
  8 +The Video block will be available for all layout columns of communities,
  9 +people, enterprises and environments.
  10 +
  11 +INSTALL
  12 +=======
  13 +
  14 +Enable Plugin
  15 +-------------
  16 +
  17 +Also, you need to enable Video Plugin on your Noosfero:
  18 +
  19 +cd <your_noosfero_dir>
  20 +./script/noosfero-plugins enable video
  21 +
  22 +Active Plugin
  23 +-------------
  24 +
  25 +As a Noosfero administrator user, go to administrator panel:
  26 +
  27 +- Click on "Enable/disable plugins" option
  28 +- Click on "Display Content Plugin" check-box
  29 +
  30 +Running Video tests
  31 +--------------------
  32 +
  33 +$ rake test:noosfero_plugins:video
  34 +
  35 +
  36 +Get Involved
  37 +============
  38 +
  39 +If you find any bug and/or want to collaborate, please send an e-mail to leandronunes@gmail.com
  40 +
  41 +LICENSE
  42 +=======
  43 +
  44 +Copyright (c) The Author developers.
  45 +
  46 +See Noosfero license.
  47 +
  48 +
  49 +AUTHORS
  50 +=======
  51 +
  52 + Leandro Nunes dos Santos (leandronunes at gmail.com)
  53 +
  54 +ACKNOWLEDGMENTS
  55 +===============
  56 +
  57 +The author have been supported by Serpro
plugins/video/lib/video_block.rb 0 → 100644
@@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
  1 +class VideoBlock < Block
  2 +
  3 + settings_items :url, :type => :string, :default => ""
  4 + settings_items :width, :type => :integer, :default => 400
  5 + settings_items :height, :type => :integer, :default => 315
  6 +
  7 + def is_youtube?
  8 + url.match(/.*(youtube.com.*v=[[:alnum:]]+|youtu.be\/[[:alnum:]]+).*/) ? true : false
  9 + end
  10 +
  11 + def is_vimeo?
  12 + url.match(/^(http[s]?:\/\/)?(www.)?(vimeo.com|player.vimeo.com\/video)\/[[:digit:]]+/) ? true : false
  13 + end
  14 +
  15 + def is_video_file?
  16 + url.match(/.*(mp4|ogg|ogv|webm)$/) ? true : false
  17 + end
  18 +
  19 + def format_embed_video_url_for_youtube
  20 + "//www.youtube-nocookie.com/embed/#{extract_youtube_id}?rel=0&wmode=transparent" if is_youtube?
  21 + end
  22 +
  23 + def format_embed_video_url_for_vimeo
  24 + "//player.vimeo.com/video/#{extract_vimeo_id}" if is_vimeo?
  25 + end
  26 +
  27 + def self.description
  28 + _('Display a Video')
  29 + end
  30 +
  31 + def help
  32 + _('This block presents a video from youtube, vimeo and some video formats (mp4, ogg, ogv and webm)')
  33 + end
  34 +
  35 + def content(args={})
  36 + block = self
  37 +
  38 + lambda do
  39 + render :file => 'video_block', :locals => { :block => block }
  40 + end
  41 + end
  42 +
  43 + private
  44 +
  45 + def extract_youtube_id
  46 + return nil unless is_youtube?
  47 + youtube_match = url.match('v=([[:alnum:]]*)')
  48 + youtube_match ||= url.match('youtu.be\/([[:alnum:]]*)')
  49 + youtube_match[1] unless youtube_match.nil?
  50 + end
  51 +
  52 + def extract_vimeo_id
  53 + return nil unless is_vimeo?
  54 + vimeo_match = url.match('([[:digit:]]*)$')
  55 + vimeo_match[1] unless vimeo_match.nil?
  56 + end
  57 +
  58 +end
plugins/video/lib/video_plugin.rb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +require_dependency File.dirname(__FILE__) + '/video_block'
  2 +
  3 +class VideoPlugin < Noosfero::Plugin
  4 +
  5 + def self.plugin_name
  6 + "Video Block Plugin"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("A plugin that adds a block where you can add videos from youtube, vimeo and html5.")
  11 + end
  12 +
  13 + def self.extra_blocks
  14 + {
  15 + VideoBlock => {}
  16 + }
  17 + end
  18 +
  19 +end
plugins/video/test/functional/video_plugin_environment_design_controller_test.rb 0 → 100644
@@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class EnvironmentDesignController; def rescue_action(e) raise e end; end
  5 +
  6 +class EnvironmentDesignControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @controller = EnvironmentDesignController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 +
  13 + Environment.delete_all
  14 + User.delete_all
  15 + @environment = Environment.create!(defaults_for_environment.merge(:is_default => true))
  16 + user = create_user('testinguser')
  17 + login_as(user.person.identifier)
  18 + @environment.add_admin(user.person)
  19 + @environment.save!
  20 +
  21 + @environment.enabled_plugins = ['VideoPlugin']
  22 + @environment.save!
  23 +
  24 + VideoBlock.delete_all
  25 +
  26 + @block = VideoBlock.new
  27 + @block.box = @environment.boxes.first
  28 + @block.save!
  29 + end
  30 +
  31 + attr_accessor :environment, :block
  32 +
  33 + should 'display video-block-data class in profile block edition' do
  34 + block.url='youtube.com/?v=XXXXX'
  35 + block.save!
  36 + get :index
  37 +
  38 + assert_tag :div, :attributes => {:class => 'video-block-data'}
  39 + end
  40 +
  41 + should "display iframe tag in profile block edition on youtube url's" do
  42 + block.url='youtube.com/?v=XXXXX'
  43 + block.save
  44 + get :index
  45 +
  46 + assert_tag :tag => 'iframe'
  47 + end
  48 +
  49 + should "the width in iframe tag be defined on youtube url's" do
  50 + block.url='youtube.com/?v=XXXXX'
  51 + block.save
  52 + get :index
  53 +
  54 + assert_tag :tag => 'iframe', :attributes => {:width => '400px'}
  55 + end
  56 +
  57 + should "display iframe tag in profile block edition on vimeo url's" do
  58 + block.url='http://vimeo.com/98979'
  59 + block.save
  60 + get :index
  61 +
  62 + assert_tag :tag => 'iframe'
  63 + end
  64 +
  65 + should "the width in iframe tag be defined on vimeo url's" do
  66 + block.url='http://vimeo.com/98979'
  67 + block.save
  68 + get :index
  69 +
  70 + assert_tag :tag => 'iframe', :attributes => {:width => '400px'}
  71 + end
  72 +
  73 + should "display video tag in profile block edition for any video url" do
  74 + block.url='http://www.vmsd.com/98979.mp4'
  75 + block.save
  76 + get :index
  77 +
  78 + assert_tag :tag => 'video'
  79 + end
  80 +
  81 + should "the width in video tag be defined for any video url" do
  82 + block.url='http://www.vmsd.com/98979.mp4'
  83 + block.save
  84 + get :index
  85 +
  86 + assert_tag :tag => 'video', :attributes => {:width => '400px'}
  87 + end
  88 +
  89 + should 'the heigth in iframe tag be defined' do
  90 + block.url='youtube.com/?v=XXXXX'
  91 + block.save
  92 + get :index
  93 +
  94 + assert_tag :tag => 'iframe', :attributes => {:height => '315px'}
  95 + end
  96 +
  97 + should 'display youtube videos' do
  98 + block.url='youtube.com/?v=XXXXX'
  99 + block.save
  100 + get :index
  101 +
  102 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'youtube'} }
  103 + end
  104 +
  105 + should 'display vimeo videos' do
  106 + block.url='http://vimeo.com/98979'
  107 + block.save
  108 + get :index
  109 +
  110 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'vimeo'} }
  111 + end
  112 +
  113 + should 'display other videos' do
  114 + block.url='http://www.vmsd.com/98979.mp4'
  115 + block.save
  116 + get :index
  117 +
  118 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'video'} }
  119 + end
  120 +
  121 + should 'display a message to register a new url' do
  122 + block.url='http://www.vmsd.com/test.pdf'
  123 + block.save
  124 + get :index
  125 +
  126 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'span', :attributes => {:class => 'alert-block'} }
  127 + end
  128 +
  129 +
  130 +end
plugins/video/test/functional/video_plugin_profile_design_controller_test.rb 0 → 100644
@@ -0,0 +1,132 @@ @@ -0,0 +1,132 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +# Re-raise errors caught by the controller.
  4 +class ProfileDesignController; def rescue_action(e) raise e end; end
  5 +
  6 +class ProfileDesignControllerTest < ActionController::TestCase
  7 +
  8 + def setup
  9 + @controller = ProfileDesignController.new
  10 + @request = ActionController::TestRequest.new
  11 + @response = ActionController::TestResponse.new
  12 +
  13 + user = create_user('testinguser')
  14 + login_as(user.login)
  15 + @profile = user.person
  16 + @environment = @profile.environment
  17 +
  18 + @environment.enabled_plugins = ['VideoPlugin']
  19 + @environment.save!
  20 +
  21 + VideoBlock.delete_all
  22 + @box1 = Box.create!(:owner => @profile)
  23 + @profile.boxes = [@box1]
  24 +
  25 + @block = VideoBlock.new
  26 + @block.box = @box1
  27 + @block.save!
  28 +
  29 + @profile.blocks<<@block
  30 + @profile.save!
  31 + end
  32 +
  33 + attr_accessor :profile, :block
  34 +
  35 + should 'display video-block-data class in profile block edition' do
  36 + block.url='youtube.com/?v=XXXXX'
  37 + block.save
  38 + get :index, :profile => profile.identifier
  39 +
  40 + assert_tag :div, :attributes => {:class => 'video-block-data'}
  41 + end
  42 +
  43 + should "display iframe tag in profile block edition on youtube url's" do
  44 + block.url='youtube.com/?v=XXXXX'
  45 + block.save
  46 + get :index, :profile => profile.identifier
  47 +
  48 + assert_tag :tag => 'iframe'
  49 + end
  50 +
  51 + should "the width in iframe tag be defined on youtube url's" do
  52 + block.url='youtube.com/?v=XXXXX'
  53 + block.save
  54 + get :index, :profile => profile.identifier
  55 +
  56 + assert_tag :tag => 'iframe', :attributes => {:width => '400px'}
  57 + end
  58 +
  59 + should "display iframe tag in profile block edition on vimeo url's" do
  60 + block.url='http://vimeo.com/98979'
  61 + block.save
  62 + get :index, :profile => profile.identifier
  63 +
  64 + assert_tag :tag => 'iframe'
  65 + end
  66 +
  67 + should "the width in iframe tag be defined on vimeo url's" do
  68 + block.url='http://vimeo.com/98979'
  69 + block.save
  70 + get :index, :profile => profile.identifier
  71 +
  72 + assert_tag :tag => 'iframe', :attributes => {:width => '400px'}
  73 + end
  74 +
  75 + should "display video tag in profile block edition for any video url" do
  76 + block.url='http://www.vmsd.com/98979.mp4'
  77 + block.save
  78 + get :index, :profile => profile.identifier
  79 +
  80 + assert_tag :tag => 'video'
  81 + end
  82 +
  83 + should "the width in video tag be defined for any video url" do
  84 + block.url='http://www.vmsd.com/98979.mp4'
  85 + block.save
  86 + get :index, :profile => profile.identifier
  87 +
  88 + assert_tag :tag => 'video', :attributes => {:width => '400px'}
  89 + end
  90 +
  91 + should 'the heigth in iframe tag be defined' do
  92 + block.url='youtube.com/?v=XXXXX'
  93 + block.save
  94 + get :index, :profile => profile.identifier
  95 +
  96 + assert_tag :tag => 'iframe', :attributes => {:height => '315px'}
  97 + end
  98 +
  99 + should 'display youtube videos' do
  100 + block.url='youtube.com/?v=XXXXX'
  101 + block.save
  102 + get :index, :profile => profile.identifier
  103 +
  104 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'youtube'} }
  105 + end
  106 +
  107 + should 'display vimeo videos' do
  108 + block.url='http://vimeo.com/98979'
  109 + block.save
  110 + get :index, :profile => profile.identifier
  111 +
  112 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'vimeo'} }
  113 + end
  114 +
  115 + should 'display other videos' do
  116 + block.url='http://www.vmsd.com/98979.mp4'
  117 + block.save
  118 + get :index, :profile => profile.identifier
  119 +
  120 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'div', :attributes => {:class => 'video'} }
  121 + end
  122 +
  123 + should 'display a messagem to register a new url' do
  124 + block.url='http://www.vmsd.com/test.pdf'
  125 + block.save
  126 + get :index, :profile => profile.identifier
  127 +
  128 + assert_tag :tag => 'div', :attributes => {:class => 'video-block-data'}, :descendant => { :tag => 'span', :attributes => {:class => 'alert-block'} }
  129 + end
  130 +
  131 +
  132 +end
plugins/video/test/test_helper.rb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
plugins/video/test/unit/video_block_test.rb 0 → 100644
@@ -0,0 +1,218 @@ @@ -0,0 +1,218 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +class VideoBlockTest < ActiveSupport::TestCase
  3 +
  4 + ### Tests for YouTube
  5 +
  6 + should "is_youtube return true when the url contains http://youtube.com" do
  7 + block = VideoBlock.new
  8 + block.url = "http://youtube.com/?v=XXXXX"
  9 + assert block.is_youtube?
  10 + end
  11 +
  12 + should "is_youtube return true when the url contains https://youtube.com" do
  13 + block = VideoBlock.new
  14 + block.url = "https://youtube.com/?v=XXXXX"
  15 + assert block.is_youtube?
  16 + end
  17 +
  18 + should "is_youtube return true when the url contains https://www.youtube.com" do
  19 + block = VideoBlock.new
  20 + block.url = "https://www.youtube.com/?v=XXXXX"
  21 + assert block.is_youtube?
  22 + end
  23 +
  24 + should "is_youtube return true when the url contains www.youtube.com" do
  25 + block = VideoBlock.new
  26 + block.url = "www.youtube.com/?v=XXXXX"
  27 + assert block.is_youtube?
  28 + end
  29 +
  30 + should "is_youtube return true when the url contains youtube.com" do
  31 + block = VideoBlock.new
  32 + block.url = "youtube.com/?v=XXXXX"
  33 + assert block.is_youtube?
  34 + end
  35 +
  36 + should "is_youtube return false when the url not contains youtube video ID" do
  37 + block = VideoBlock.new
  38 + block.url = "youtube.com/"
  39 + assert !block.is_youtube?
  40 + end
  41 +
  42 + should "is_youtube return false when the url contains empty youtube video ID" do
  43 + block = VideoBlock.new
  44 + block.url = "youtube.com/?v="
  45 + assert !block.is_youtube?
  46 + end
  47 +
  48 + should "is_youtube return false when the url contains an invalid youtube link" do
  49 + block = VideoBlock.new
  50 + block.url = "http://www.yt.com/?v=XXXXX"
  51 + assert !block.is_youtube?
  52 + end
  53 +
  54 + should "format embed video for youtube videos" do
  55 + block = VideoBlock.new
  56 + block.url = "youtube.com/?v=XXXXX"
  57 + assert_match /\/\/www.youtube-nocookie.com\/embed/, block.format_embed_video_url_for_youtube
  58 + end
  59 +
  60 + should "format embed video return nil if is not a youtube url" do
  61 + block = VideoBlock.new
  62 + block.url = "http://www.yt.com/?v=XXXXX"
  63 + assert_nil block.format_embed_video_url_for_youtube
  64 + end
  65 +
  66 + should "extract youtube id from youtube video url's if it's a valid youtube full url" do
  67 + block = VideoBlock.new
  68 + id = 'oi43jre2d2'
  69 + block.url = "youtube.com/?v=#{id}"
  70 + assert_equal id, block.send('extract_youtube_id')
  71 + end
  72 +
  73 + should "extract youtube id from youtube video url's if it's a valid youtube short url" do
  74 + block = VideoBlock.new
  75 + id = 'oi43jre2d2'
  76 + block.url = "youtu.be/#{id}"
  77 + assert_equal id, block.send('extract_youtube_id')
  78 + end
  79 +
  80 + should "extract_youtube_id return nil if the url it's not a valid youtube url" do
  81 + block = VideoBlock.new
  82 + block.url = "http://www.yt.com/?v=XXXXX"
  83 + assert_nil block.send('extract_youtube_id')
  84 + end
  85 +
  86 + should "extract_youtube_id return nil if youtue url there is no id" do
  87 + block = VideoBlock.new
  88 + block.url = "youtube.com/"
  89 + assert_nil block.send('extract_youtube_id')
  90 + end
  91 +
  92 + #### Tests for Vimeo Videos
  93 +
  94 + should "is_vimeo return true when the url contains http://vimeo.com" do
  95 + block = VideoBlock.new
  96 + block.url = "http://vimeo.com/98979"
  97 + assert block.is_vimeo?
  98 + end
  99 +
  100 + should "is_vimeo return true when the url contains https://vimeo.com" do
  101 + block = VideoBlock.new
  102 + block.url = "https://vimeo.com/989798"
  103 + assert block.is_vimeo?
  104 + end
  105 +
  106 + should "is_vimeo return true when the url contains https://www.vimeo.com" do
  107 + block = VideoBlock.new
  108 + block.url = "https://www.vimeo.com/98987"
  109 + assert block.is_vimeo?
  110 + end
  111 +
  112 + should "is_vimeo return true when the url contains www.vimeo.com" do
  113 + block = VideoBlock.new
  114 + block.url = "www.vimeo.com/989798"
  115 + assert block.is_vimeo?
  116 + end
  117 +
  118 + should "is_vimeo return true when the url contains vimeo.com" do
  119 + block = VideoBlock.new
  120 + block.url = "vimeo.com/09898"
  121 + assert block.is_vimeo?
  122 + end
  123 +
  124 + should "is_vimeo return false when the url not contains vimeo video ID" do
  125 + block = VideoBlock.new
  126 + block.url = "vimeo.com/home"
  127 + assert !block.is_vimeo?
  128 + end
  129 +
  130 + should "is_vimeo return false when the url contains empty vimeo video ID" do
  131 + block = VideoBlock.new
  132 + block.url = "vimeo.com/"
  133 + assert !block.is_vimeo?
  134 + end
  135 +
  136 + should "is_vimeo return false when the url contains an invalid vimeo link" do
  137 + block = VideoBlock.new
  138 + block.url = "http://www.vmsd.com/98979"
  139 + assert !block.is_vimeo?
  140 + end
  141 +
  142 + should "format embed video for vimeo videos" do
  143 + block = VideoBlock.new
  144 + block.url = "vimeo.com/09898"
  145 + assert_match /\/\/player.vimeo.com\/video\/[[:digit:]]+/, block.format_embed_video_url_for_vimeo
  146 + end
  147 +
  148 + should "format embed video return nil if is not a vimeo url" do
  149 + block = VideoBlock.new
  150 + block.url = "http://www.yt.com/?v=XXXXX"
  151 + assert_nil block.format_embed_video_url_for_vimeo
  152 + end
  153 +
  154 + should "extract vimeo id from vimeo video url's if it's a valid vimeo url" do
  155 + block = VideoBlock.new
  156 + id = '23048239432'
  157 + block.url = "vimeo.com/#{id}"
  158 + assert_equal id, block.send('extract_vimeo_id')
  159 + end
  160 +
  161 + should "extract_vimeo_id return nil if the url it's not a valid vimeo url" do
  162 + block = VideoBlock.new
  163 + block.url = "http://www.yt.com/XXXXX"
  164 + assert_nil block.send('extract_vimeo_id')
  165 + end
  166 +
  167 + should "extract_vimeo_id return nil if vimeo url there is no id" do
  168 + block = VideoBlock.new
  169 + block.url = "vimeo.com/"
  170 + assert_nil block.send('extract_youtube_id')
  171 + end
  172 +
  173 + # Other video formats
  174 + should "is_video return true if url ends with mp4" do
  175 + block = VideoBlock.new
  176 + block.url = "http://www.vmsd.com/98979.mp4"
  177 + assert block.is_video_file?
  178 + end
  179 +
  180 + should "is_video return true if url ends with ogg" do
  181 + block = VideoBlock.new
  182 + block.url = "http://www.vmsd.com/98979.ogg"
  183 + assert block.is_video_file?
  184 + end
  185 +
  186 + should "is_video return true if url ends with ogv" do
  187 + block = VideoBlock.new
  188 + block.url = "http://www.vmsd.com/98979.ogv"
  189 + assert block.is_video_file?
  190 + end
  191 +
  192 + should "is_video return true if url ends with webm" do
  193 + block = VideoBlock.new
  194 + block.url = "http://www.vmsd.com/98979.webm"
  195 + assert block.is_video_file?
  196 + end
  197 +
  198 + should "is_video return false if url ends without mp4, ogg, ogv, webm" do
  199 + block = VideoBlock.new
  200 + block.url = "http://www.vmsd.com/98979.mp4r"
  201 + assert !block.is_video_file?
  202 + block.url = "http://www.vmsd.com/98979.oggr"
  203 + assert !block.is_video_file?
  204 + block.url = "http://www.vmsd.com/98979.ogvr"
  205 + assert !block.is_video_file?
  206 + block.url = "http://www.vmsd.com/98979.webmr"
  207 + assert !block.is_video_file?
  208 + end
  209 +
  210 + should 'display video block partial' do
  211 + block = VideoBlock.new
  212 + self.expects(:render).with(:file => 'video_block', :locals => {
  213 + :block => block
  214 + })
  215 + instance_eval(& block.content)
  216 + end
  217 +
  218 +end
plugins/video/test/unit/video_plugin_test.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +class VideoPluginTest < ActiveSupport::TestCase
  3 +
  4 + should "return VideoBlock in extra_blocks class method" do
  5 + assert VideoPlugin.extra_blocks.keys.include?(VideoBlock)
  6 + end
  7 +
  8 +end
plugins/video/views/box_organizer/_html5_video_block.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<video controls preload="auto" width='<%="#{width}px"%>' height='<%="#{height}px"%>'>
  2 + <source src=<%= "#{url}" %>>
  3 +</video>
plugins/video/views/box_organizer/_iframe_video_block.rhtml 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<iframe width='<%="#{width}px"%>' height='<%="#{height}px"%>' src='<%= "#{url}" %>' frameborder="0" allowfullscreen></iframe>
plugins/video/views/box_organizer/_video_block.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<label for="url" class="formlabel"> Video URL: </label>
  2 +
  3 +<div class="formfield type-text">
  4 + <%= text_field_tag 'block[url]', @block.url, :class => 'video-url', :maxlength => 255 %>
  5 +</div>
  6 +<div class="formfield type-text">
  7 + <label for="width" class="formlabel"> Width: </label>
  8 + <%= text_field_tag 'block[width]', @block.width, :size => 7, :class => 'video-width', :maxlength => 5 %>
  9 + <label for="height" class="formlabel"> Height: </label>
  10 + <%= text_field_tag 'block[height]', @block.height, :size => 7, :class => 'video-height', :maxlength => 5 %>
  11 +</div>
plugins/video/views/environment_design 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +box_organizer
0 \ No newline at end of file 2 \ No newline at end of file
plugins/video/views/profile_design 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +box_organizer
0 \ No newline at end of file 2 \ No newline at end of file
plugins/video/views/video_block.rhtml 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<h3 class="block-title">
  2 + <span><%=block.title%></span>
  3 +</h3>
  4 +<div class="video-block-data">
  5 + <% if block.is_youtube? %>
  6 + <div class='youtube'>
  7 + <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_youtube, :width => block.width, :height => block.height }%>
  8 + </div>
  9 + <% elsif block.is_vimeo? %>
  10 + <div class='vimeo'>
  11 + <%= render :partial => 'box_organizer/iframe_video_block', :locals => { :url => block.format_embed_video_url_for_vimeo, :width => block.width, :height => block.height }%>
  12 + </div>
  13 + <% elsif block.is_video_file? %>
  14 + <div class='video'>
  15 + <%= render :partial => 'box_organizer/html5_video_block', :locals => { :url => block.url, :width => block.width, :height => block.height }%>
  16 + </div>
  17 + <% else %>
  18 + <span class='alert-block'><%= _("Register a valid url (Vimeo, Youtube, video files)") %></span>
  19 + <% end %>
  20 +
  21 +</div>
public/designs/icons/tango/ie6.css
@@ -1,52 +0,0 @@ @@ -1,52 +0,0 @@
1 -.msie6 .icon-edit { background-image: url(ie6/Tango/16x16/apps/text-editor.gif) }  
2 -.msie6 .icon-home { background-image: url(ie6/Tango/16x16/actions/go-home.gif) }  
3 -.msie6 .icon-new,  
4 -.msie6 .icon-suggest { background-image: url(ie6/Tango/16x16/actions/filenew.gif) }  
5 -.msie6 .icon-close { background-image: url(ie6/Tango/16x16/actions/gtk-cancel.gif) }  
6 -.msie6 .icon-newfolder { background-image: url(ie6/Tango/16x16/actions/folder-new.gif) }  
7 -.msie6 .icon-save { background-image: url(ie6/Tango/16x16/actions/filesave.gif) }  
8 -.msie6 .icon-send { background-image: url(ie6/Tango/16x16/actions/stock_mail-forward.gif) }  
9 -.msie6 .icon-cancel { background-image: url(ie6/Tango/16x16/actions/gtk-cancel.gif) }  
10 -.msie6 .icon-person { background-image: url(ie6/Tango/16x16/apps/system-config-users.gif) }  
11 -.msie6 .icon-product { background-image: url(ie6/Tango/16x16/mimetypes/package.gif) }  
12 -.msie6 .icon-delete { background-image: url(ie6/Tango/16x16/places/user-trash.gif) }  
13 -.msie6 .icon-back { background-image: url(ie6/Tango/16x16/actions/back.gif) }  
14 -.msie6 .icon-next { background-image: url(ie6/Tango/16x16/actions/go-next.gif) }  
15 -.msie6 .icon-add { background-image: url(ie6/Tango/16x16/actions/add.gif) }  
16 -.msie6 .icon-more { background-image: url(ie6/Tango/16x16/actions/add.gif) }  
17 -.msie6 .icon-up { background-image: url(ie6/Tango/16x16/actions/go-up.gif) }  
18 -.msie6 .icon-down { background-image: url(ie6/Tango/16x16/actions/go-down.gif) }  
19 -.msie6 .icon-left { background-image: url(ie6/Tango/16x16/actions/go-previous.gif) }  
20 -.msie6 .icon-right { background-image: url(ie6/Tango/16x16/actions/go-next.gif) }  
21 -.msie6 .icon-up-disabled { background-image: url(ie6/Tango/16x16/actions/go-up.gif); opacity: 0.25; filter:alpha(opacity=25); }  
22 -.msie6 .icon-down-disabled { background-image: url(ie6/Tango/16x16/actions/go-down.gif); opacity: 0.25; filter:alpha(opacity=25); }  
23 -.msie6 .icon-left-disabled { background-image: url(ie6/Tango/16x16/actions/go-previous.gif); opacity: 0.25; filter:alpha(opacity=25); }  
24 -.msie6 .icon-right-disabled { background-image: url(ie6/Tango/16x16/actions/go-next.gif); opacity: 0.25; filter:alpha(opacity=25); }  
25 -.msie6 .icon-up-red { background-image: url(ie6/mod/16x16/actions/go-up-red.gif) }  
26 -.msie6 .icon-forward { background-image: url(ie6/Tango/16x16/actions/go-next.gif) }  
27 -.msie6 .icon-search { background-image: url(ie6/Tango/16x16/actions/search.gif) }  
28 -.msie6 .icon-ok { background-image: url(ie6/Tango/16x16/actions/media-playback-start.gif) }  
29 -.msie6 .icon-login { background-image: url(ie6/mod/16x16/actions/log-in.gif) }  
30 -.msie6 .icon-help { background-image: url(ie6/Tango/16x16/apps/gnome-help.gif) }  
31 -.msie6 .icon-firefox { background-image: url(firefox-24x24.gif) }  
32 -.msie6 .icon-help32on { background-image: url(ie6/Tango/32x32/apps/gnome-help.gif) }  
33 -.msie6 .icon-help32off { background-image: url(ie6/mod/32x32/apps/gnome-help-red.gif) }  
34 -.msie6 .icon-spread { background-image: url(ie6/mod/16x16/actions/spread.gif) }  
35 -.msie6 .icon-todo { background-image: url(ie6/Tango/16x16/actions/stock_paste.gif) }  
36 -.msie6 .icon-eyes { background-image: url(ie6/Tango/16x16/actions/gtk-print-preview.gif) }  
37 -.msie6 .icon-menu-home { background-image: url(ie6/Tango/16x16/actions/go-home.gif) }  
38 -.msie6 .icon-menu-product { background-image: url(ie6/Tango/16x16/mimetypes/package.gif) }  
39 -.msie6 .icon-menu-enterprise { background-image: url(ie6/Tango/16x16/actions/go-home.gif) }  
40 -.msie6 .icon-menu-community { background-image: url(ie6/Tango/16x16/apps/system-config-users.gif) }  
41 -.msie6 .icon-menu-ctrl-panel { background-image: url(ie6/Tango/16x16/categories/preferences-desktop.gif) }  
42 -.msie6 .icon-menu-admin { background-image: url(ie6/Tango/16x16/categories/preferences-system.gif) }  
43 -.msie6 .icon-menu-my-groups { background-image: url(ie6/Tango/16x16/apps/system-config-users.gif) }  
44 -.msie6 .icon-menu-login { background-image: url(ie6/mod/16x16/actions/log-in.gif) }  
45 -.msie6 .icon-menu-logout { background-image: url(ie6/Tango/16x16/actions/exit.gif) }  
46 -.msie6 .icon-menu-search { background-image: url(ie6/Tango/16x16/actions/search.gif) }  
47 -.msie6 .icon-menu-events { background-image: url(ie6/Tango/16x16/mimetypes/stock_calendar.gif) }  
48 -.msie6 .icon-menu-articles { background-image: url(ie6/Tango/16x16/apps/text-editor.gif) }  
49 -.msie6 .icon-menu-people { background-image: url(ie6/mod/16x16/apps/user.gif) }  
50 -.msie6 .icon-menu-mail { background-image: url(ie6/Tango/16x16/apps/email.gif) }  
51 -.msie6 .icon-upload-file { background-image: url(ie6/Tango/16x16/actions/filesave.gif) }  
52 -.msie6 .icon-slideshow { background-image: url(ie6/Tango/16x16/mimetypes/x-office-presentation.gif) }  
public/designs/icons/tango/ie6/Tango/16x16/actions/add.gif

192 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/back.gif

570 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/exit.gif

1.03 KB

public/designs/icons/tango/ie6/Tango/16x16/actions/filenew.gif

354 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/filesave.gif

750 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/folder-new.gif

599 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/go-down.gif

568 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/go-home.gif

587 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/go-next.gif

570 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/go-previous.gif

570 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/go-up.gif

572 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/gtk-cancel.gif

1022 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/gtk-print-preview.gif

1022 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/media-playback-start.gif

314 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/search.gif

601 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/stock_mail-forward.gif

601 Bytes

public/designs/icons/tango/ie6/Tango/16x16/actions/stock_paste.gif

595 Bytes

public/designs/icons/tango/ie6/Tango/16x16/apps/email.gif

347 Bytes

public/designs/icons/tango/ie6/Tango/16x16/apps/gnome-help.gif

1.01 KB

public/designs/icons/tango/ie6/Tango/16x16/apps/system-config-users.gif

1.05 KB

public/designs/icons/tango/ie6/Tango/16x16/apps/text-editor.gif

363 Bytes

public/designs/icons/tango/ie6/Tango/16x16/categories/preferences-desktop.gif

357 Bytes

public/designs/icons/tango/ie6/Tango/16x16/categories/preferences-system.gif

333 Bytes

public/designs/icons/tango/ie6/Tango/16x16/mimetypes/package.gif

573 Bytes

public/designs/icons/tango/ie6/Tango/16x16/mimetypes/stock_calendar.gif

382 Bytes

public/designs/icons/tango/ie6/Tango/16x16/mimetypes/x-office-presentation.gif

559 Bytes

public/designs/icons/tango/ie6/Tango/16x16/places/user-home.gif

1 KB

public/designs/icons/tango/ie6/Tango/16x16/places/user-trash.gif

1009 Bytes

public/designs/icons/tango/ie6/Tango/32x32/apps/gnome-help.gif

1.03 KB

public/designs/icons/tango/ie6/mod/16x16/actions/go-up-red.gif

361 Bytes

public/designs/icons/tango/ie6/mod/16x16/actions/log-in.gif

246 Bytes

public/designs/icons/tango/ie6/mod/16x16/actions/log-out.gif

241 Bytes

public/designs/icons/tango/ie6/mod/16x16/actions/password.gif

546 Bytes

public/designs/icons/tango/ie6/mod/16x16/actions/spread.gif

532 Bytes

public/designs/icons/tango/ie6/mod/16x16/apps/user.gif

620 Bytes

public/designs/icons/tango/ie6/mod/32x32/apps/gnome-help-red.gif

969 Bytes

public/designs/icons/tango/style.css
1 -@import url(ie6.css);  
2 -  
3 /******************SMALL ICONS********************/ 1 /******************SMALL ICONS********************/
4 .icon-edit { background-image: url(Tango/16x16/apps/text-editor.png) } 2 .icon-edit { background-image: url(Tango/16x16/apps/text-editor.png) }
5 -.icon-home { background-image: url(Tango/16x16/actions/go-home.png) } 3 +.icon-home { background-image: url(Tango/16x16/actions/go-home.png) }
6 .icon-new, 4 .icon-new,
7 -.icon-suggest { background-image: url(Tango/16x16/actions/filenew.png) }  
8 -.icon-close { background-image: url(Tango/16x16/actions/gtk-cancel.png) } 5 +.icon-suggest { background-image: url(Tango/16x16/actions/filenew.png) }
  6 +.icon-close { background-image: url(Tango/16x16/actions/gtk-cancel.png) }
9 .icon-newfolder { background-image: url(Tango/16x16/actions/folder-new.png) } 7 .icon-newfolder { background-image: url(Tango/16x16/actions/folder-new.png) }
10 .icon-folder { background-image: url(Tango/16x16/places/folder.png) } 8 .icon-folder { background-image: url(Tango/16x16/places/folder.png) }
11 -.icon-parent-folder { background-image: url(Tango/16x16/places/folder_home.png) } 9 +.icon-parent-folder { background-image: url(Tango/16x16/places/folder_home.png) }
12 .icon-newblog { background-image: url(mod/16x16/apps/text-editor.png) } 10 .icon-newblog { background-image: url(mod/16x16/apps/text-editor.png) }
13 .icon-blog { background-image: url(mod/16x16/apps/text-editor.png) } 11 .icon-blog { background-image: url(mod/16x16/apps/text-editor.png) }
14 -/*.icon-open { background-image: url(folder-open.gif) } UNUSED*/  
15 -/*.icon-cms { background-image: url(abiword_48.png) } UNUSED*/  
16 -.icon-save { background-image: url(Tango/16x16/actions/filesave.png) }  
17 -.icon-send { background-image: url(Tango/16x16/actions/stock_mail-forward.png) }  
18 -.icon-cancel { background-image: url(Tango/16x16/actions/gtk-cancel.png) }  
19 -.icon-person { background-image: url(Tango/16x16/apps/system-config-users.png) }  
20 -.icon-product { background-image: url(Tango/16x16/mimetypes/package.png) } 12 +/*.icon-open { background-image: url(folder-open.gif) } UNUSED*/
  13 +/*.icon-cms { background-image: url(abiword_48.png) } UNUSED*/
  14 +.icon-save { background-image: url(Tango/16x16/actions/filesave.png) }
  15 +.icon-send { background-image: url(Tango/16x16/actions/stock_mail-forward.png) }
  16 +.icon-cancel { background-image: url(Tango/16x16/actions/gtk-cancel.png) }
  17 +.icon-person { background-image: url(Tango/16x16/apps/system-config-users.png) }
  18 +.icon-product { background-image: url(Tango/16x16/mimetypes/package.png) }
21 .icon-delete { background-image: url(Tango/16x16/places/user-trash.png) } 19 .icon-delete { background-image: url(Tango/16x16/places/user-trash.png) }
22 -/*.icon-find { background-image: url(noosfero-find.png) } UNUSED*/  
23 -.icon-back { background-image: url(Tango/16x16/actions/back.png) }  
24 -.icon-next { background-image: url(Tango/16x16/actions/go-next.png) }  
25 -.icon-add { background-image: url(Tango/16x16/actions/add.png) }  
26 -.icon-remove { background-image: url(Tango/16x16/actions/gtk-remove.png) }  
27 -.icon-more { background-image: url(Tango/16x16/actions/add.png) }  
28 -.icon-up { background-image: url(Tango/16x16/actions/go-up.png) }  
29 -.icon-down { background-image: url(Tango/16x16/actions/go-down.png) }  
30 -.icon-left { background-image: url(Tango/16x16/actions/go-previous.png) }  
31 -.icon-right { background-image: url(Tango/16x16/actions/go-next.png) }  
32 -.icon-up-disabled { background-image: url(Tango/16x16/actions/go-up.png); opacity: 0.25; filter:alpha(opacity=25); }  
33 -.icon-down-disabled { background-image: url(Tango/16x16/actions/go-down.png); opacity: 0.25; filter:alpha(opacity=25); }  
34 -.icon-left-disabled { background-image: url(Tango/16x16/actions/go-previous.png); opacity: 0.25; filter:alpha(opacity=25); }  
35 -.icon-right-disabled { background-image: url(Tango/16x16/actions/go-next.png); opacity: 0.25; filter:alpha(opacity=25); }  
36 -.icon-up-red { background-image: url(mod/16x16/actions/go-up-red.png) }  
37 -.icon-forward { background-image: url(Tango/16x16/actions/go-next.png) }  
38 -.icon-search { background-image: url(Tango/16x16/actions/search.png) }  
39 -.icon-ok { background-image: url(Tango/16x16/actions/media-playback-start.png) }  
40 -.icon-login { background-image: url(mod/16x16/actions/log-in.png) }  
41 -.icon-help { background-image: url(Tango/16x16/apps/gnome-help.png) }  
42 -.icon-firefox { background-image: url(firefox-24x24.gif) }  
43 -.icon-help32on { background-image: url(Tango/32x32/apps/gnome-help.png) }  
44 -.icon-help32off { background-image: url(mod/32x32/apps/gnome-help-red.png) } 20 +/*.icon-find { background-image: url(noosfero-find.png) } UNUSED*/
  21 +.icon-back { background-image: url(Tango/16x16/actions/back.png) }
  22 +.icon-next { background-image: url(Tango/16x16/actions/go-next.png) }
  23 +.icon-add { background-image: url(Tango/16x16/actions/add.png) }
  24 +.icon-remove { background-image: url(Tango/16x16/actions/gtk-remove.png) }
  25 +.icon-more { background-image: url(Tango/16x16/actions/add.png) }
  26 +.icon-up { background-image: url(Tango/16x16/actions/go-up.png) }
  27 +.icon-down { background-image: url(Tango/16x16/actions/go-down.png) }
  28 +.icon-left { background-image: url(Tango/16x16/actions/go-previous.png) }
  29 +.icon-right { background-image: url(Tango/16x16/actions/go-next.png) }
  30 +.icon-up-disabled { background-image: url(Tango/16x16/actions/go-up.png); opacity: 0.25; filter:alpha(opacity=25); }
  31 +.icon-down-disabled { background-image: url(Tango/16x16/actions/go-down.png); opacity: 0.25; filter:alpha(opacity=25); }
  32 +.icon-left-disabled { background-image: url(Tango/16x16/actions/go-previous.png); opacity: 0.25; filter:alpha(opacity=25); }
  33 +.icon-right-disabled { background-image: url(Tango/16x16/actions/go-next.png); opacity: 0.25; filter:alpha(opacity=25); }
  34 +.icon-up-red { background-image: url(mod/16x16/actions/go-up-red.png) }
  35 +.icon-forward { background-image: url(Tango/16x16/actions/go-next.png) }
  36 +.icon-search { background-image: url(Tango/16x16/actions/search.png) }
  37 +.icon-ok { background-image: url(Tango/16x16/actions/media-playback-start.png) }
  38 +.icon-login { background-image: url(mod/16x16/actions/log-in.png) }
  39 +.icon-help { background-image: url(Tango/16x16/apps/gnome-help.png) }
  40 +.icon-firefox { background-image: url(firefox-24x24.gif) }
  41 +.icon-help32on { background-image: url(Tango/32x32/apps/gnome-help.png) }
  42 +.icon-help32off { background-image: url(mod/32x32/apps/gnome-help-red.png) }
45 .icon-spread { background-image: url(mod/16x16/actions/spread.png) } 43 .icon-spread { background-image: url(mod/16x16/actions/spread.png) }
46 -.icon-todo { background-image: url(Tango/16x16/actions/stock_paste.png) }  
47 -.icon-eyes { background-image: url(Tango/16x16/actions/gtk-print-preview.png) }  
48 -/*.icon-menu- { background-image: url(menu-without-ico-HC.gif) }*/  
49 -.icon-menu-home { background-image: url(Tango/16x16/actions/go-home.png) }  
50 -/*.icon-menu-blog { background-image: url(blog-HC.gif) } UNUSED*/  
51 -/*.icon-menu-album { background-image: url(album-HC.gif) } UNUSED*/  
52 -.icon-menu-product { background-image: url(Tango/16x16/mimetypes/package.png) }  
53 -.icon-menu-enterprise { background-image: url(Tango/16x16/actions/go-home.png) }  
54 -.icon-menu-community { background-image: url(Tango/16x16/apps/system-config-users.png) }  
55 -/*.icon-menu-edit { background-image: url(edit-HC.gif) } UNUSED */  
56 -.icon-menu-ctrl-panel { background-image: url(Tango/16x16/categories/preferences-desktop.png) }  
57 -.icon-menu-admin { background-image: url(Tango/16x16/categories/preferences-system.png) }  
58 -.icon-menu-my-groups { background-image: url(Tango/16x16/apps/system-config-users.png) }  
59 -.icon-menu-login { background-image: url(mod/16x16/actions/log-in.png) }  
60 -.icon-menu-logout { background-image: url(mod/16x16/actions/log-out.png) }  
61 -.icon-menu-search { background-image: url(Tango/16x16/actions/search.png) }  
62 -/*.icon-menu-ed-design { background-image: url(edit-design-HC.gif) } UNUSED */  
63 -.icon-menu-events { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }  
64 -.icon-event { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }  
65 -.icon-newevent { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }  
66 -.icon-menu-articles { background-image: url(Tango/16x16/apps/text-editor.png) }  
67 -/*.icon-menu-comments { background-image: url(blog-HC.gif) } UNUSED */  
68 -.icon-menu-people { background-image: url(mod/16x16/apps/user.png) }  
69 -.icon-menu-mail { background-image: url(Tango/16x16/apps/email.png) }  
70 -.icon-upload-file { background-image: url(Tango/16x16/actions/filesave.png) }  
71 -.icon-newupload-file { background-image: url(Tango/16x16/actions/filesave.png) }  
72 -.icon-slideshow { background-image: url(Tango/16x16/mimetypes/x-office-presentation.png) } 44 +.icon-todo { background-image: url(Tango/16x16/actions/stock_paste.png) }
  45 +.icon-eyes { background-image: url(Tango/16x16/actions/find.png) }
  46 +/*.icon-menu- { background-image: url(menu-without-ico-HC.gif) }*/
  47 +.icon-menu-home { background-image: url(Tango/16x16/actions/go-home.png) }
  48 +/*.icon-menu-blog { background-image: url(blog-HC.gif) } UNUSED*/
  49 +/*.icon-menu-album { background-image: url(album-HC.gif) } UNUSED*/
  50 +.icon-menu-product { background-image: url(Tango/16x16/mimetypes/package.png) }
  51 +.icon-menu-enterprise { background-image: url(Tango/16x16/actions/go-home.png) }
  52 +.icon-menu-community { background-image: url(Tango/16x16/apps/system-config-users.png) }
  53 +/*.icon-menu-edit { background-image: url(edit-HC.gif) } UNUSED */
  54 +.icon-menu-ctrl-panel { background-image: url(Tango/16x16/categories/preferences-desktop.png) }
  55 +.icon-menu-admin { background-image: url(Tango/16x16/categories/preferences-system.png) }
  56 +.icon-menu-my-groups { background-image: url(Tango/16x16/apps/system-config-users.png) }
  57 +.icon-menu-login { background-image: url(mod/16x16/actions/log-in.png) }
  58 +.icon-menu-logout { background-image: url(mod/16x16/actions/log-out.png) }
  59 +.icon-menu-search { background-image: url(Tango/16x16/actions/search.png) }
  60 +/*.icon-menu-ed-design { background-image: url(edit-design-HC.gif) } UNUSED */
  61 +.icon-menu-events { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }
  62 +.icon-event { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }
  63 +.icon-newevent { background-image: url(Tango/16x16/mimetypes/stock_calendar.png) }
  64 +.icon-menu-articles { background-image: url(Tango/16x16/apps/text-editor.png) }
  65 +/*.icon-menu-comments { background-image: url(blog-HC.gif) } UNUSED */
  66 +.icon-menu-people { background-image: url(mod/16x16/apps/user.png) }
  67 +.icon-menu-mail { background-image: url(Tango/16x16/apps/email.png) }
  68 +.icon-upload-file { background-image: url(Tango/16x16/actions/filesave.png) }
  69 +.icon-newupload-file { background-image: url(Tango/16x16/actions/filesave.png) }
  70 +.icon-slideshow { background-image: url(Tango/16x16/mimetypes/x-office-presentation.png) }
73 .icon-photos { background-image: url(Tango/16x16/devices/camera-photo.png) } 71 .icon-photos { background-image: url(Tango/16x16/devices/camera-photo.png) }
74 72
75 -.icon-text-html { background-image: url(Tango/16x16/mimetypes/text-html.png) } 73 +.icon-text-html { background-image: url(Tango/16x16/mimetypes/text-html.png) }
76 .icon-text-plain { background-image: url(Tango/16x16/mimetypes/text-x-generic.png) } 74 .icon-text-plain { background-image: url(Tango/16x16/mimetypes/text-x-generic.png) }
77 -.icon-image-svg-xml { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) } 75 +.icon-image-svg-xml { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
78 .icon-application-octet-stream { background-image: url(Tango/16x16/mimetypes/binary.png) } 76 .icon-application-octet-stream { background-image: url(Tango/16x16/mimetypes/binary.png) }
79 -.icon-application-x-gzip { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-x-gzip.png) }  
80 -.icon-application-postscript { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-postscript.png) }  
81 -.icon-application-pdf { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-pdf.png) }  
82 -.icon-application-ogg { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-ogg.png) }  
83 -.icon-video-mpeg { background-image: url(Tango/16x16/mimetypes/video-x-generic.png) }  
84 -.icon-application-vnd-oasis-opendocument-text { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.text.png) } 77 +.icon-application-x-gzip { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-x-gzip.png) }
  78 +.icon-application-postscript { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-postscript.png) }
  79 +.icon-application-pdf { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-pdf.png) }
  80 +.icon-application-ogg { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-ogg.png) }
  81 +.icon-video, .icon-video-mpeg { background-image: url(Tango/16x16/mimetypes/video-x-generic.png) }
  82 +.icon-application-vnd-oasis-opendocument-text { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.text.png) }
85 .icon-application-vnd-oasis-opendocument-spreadsheet { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.spreadsheet.png) } 83 .icon-application-vnd-oasis-opendocument-spreadsheet { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.spreadsheet.png) }
86 -.icon-application-vnd-oasis-opendocument-presentation { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.presentation.png) } 84 +.icon-application-vnd-oasis-opendocument-presentation { background-image: url(Tango/16x16/mimetypes/gnome-mime-application-vnd.oasis.opendocument.presentation.png) }
87 85
88 -.icon-media-pause { background-image: url(Tango/16x16/actions/media-playback-pause.png) }  
89 -.icon-media-play { background-image: url(Tango/16x16/actions/media-playback-start.png) }  
90 -.icon-media-prev { background-image: url(Tango/16x16/actions/media-skip-backward.png) }  
91 -.icon-media-next { background-image: url(Tango/16x16/actions/media-skip-forward.png) } 86 +.icon-media-pause { background-image: url(Tango/16x16/actions/media-playback-pause.png) }
  87 +.icon-media-play { background-image: url(Tango/16x16/actions/media-playback-start.png) }
  88 +.icon-media-prev { background-image: url(Tango/16x16/actions/media-skip-backward.png) }
  89 +.icon-media-next { background-image: url(Tango/16x16/actions/media-skip-forward.png) }
92 .icon-lock { background-image: url(Tango/16x16/actions/lock.png) } 90 .icon-lock { background-image: url(Tango/16x16/actions/lock.png) }
93 -.icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat }  
94 -.icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }  
95 -.icon-newforum { background-image: url(Tango/16x16/apps/internet-group-chat.png) }  
96 -.icon-forum { background-image: url(Tango/16x16/apps/system-users.png) }  
97 -.icon-gallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) } 91 +.icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat }
  92 +.icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }
  93 +.icon-newforum { background-image: url(Tango/16x16/apps/internet-group-chat.png) }
  94 +.icon-forum { background-image: url(Tango/16x16/apps/system-users.png) }
  95 +.icon-gallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
98 .icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) } 96 .icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
99 -.icon-locale { background-image: url(Tango/16x16/apps/preferences-desktop-locale.png) }  
100 -.icon-user-removed { background-image: url(Tango/16x16/actions/gtk-cancel.png) }  
101 -.icon-user-unknown { background-image: url(Tango/16x16/status/dialog-error.png) }  
102 -.icon-alert { background-image: url(Tango/16x16/status/dialog-warning.png) } 97 +.icon-locale { background-image: url(Tango/16x16/apps/preferences-desktop-locale.png) }
  98 +.icon-user-removed { background-image: url(Tango/16x16/actions/gtk-cancel.png) }
  99 +.icon-user-unknown { background-image: url(Tango/16x16/status/dialog-error.png) }
  100 +.icon-alert { background-image: url(Tango/16x16/status/dialog-warning.png) }
103 101
104 /******************LARGE ICONS********************/ 102 /******************LARGE ICONS********************/
105 -.image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) }  
106 -.image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) } 103 +.image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) }
  104 +.image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) }
public/designs/themes/base/style.css
@@ -89,7 +89,7 @@ body, th, td, input { @@ -89,7 +89,7 @@ body, th, td, input {
89 color: #555753; 89 color: #555753;
90 } 90 }
91 91
92 -#controlpanel, #logout, #openchat, #manage-enterprises { 92 +#controlpanel, #logout, #openchat, .manage-groups {
93 margin-left: 25px; 93 margin-left: 25px;
94 } 94 }
95 95
@@ -822,12 +822,6 @@ div#notice { @@ -822,12 +822,6 @@ div#notice {
822 margin-bottom: 0px; 822 margin-bottom: 0px;
823 } 823 }
824 824
825 -X.sep {  
826 - background: url(imgs/blog-sep.png) 50% 50% repeat-x;  
827 - padding: 10px 20px;  
828 - margin: 10px -19px;  
829 -}  
830 -  
831 /* ==> search-results.css <== */ 825 /* ==> search-results.css <== */
832 826
833 827
@@ -1019,6 +1013,46 @@ hr.pre-posts, hr.sep-posts { @@ -1019,6 +1013,46 @@ hr.pre-posts, hr.sep-posts {
1019 background: transparent; 1013 background: transparent;
1020 } 1014 }
1021 1015
  1016 +/************* uploaded file *****************/
  1017 +
  1018 +#article .gallery-navigation {
  1019 + padding: 10px 0;
  1020 +}
  1021 +
  1022 +#article .gallery-navigation .previous {
  1023 + margin-right: 10px;
  1024 +}
  1025 +
  1026 +#article .gallery-navigation .next {
  1027 + margin-left: 10px;
  1028 +}
  1029 +
  1030 +#article .gallery-navigation .total-of-images {
  1031 + font-weight: bold;
  1032 +}
  1033 +
  1034 +#article .uploaded-file-description {
  1035 + background: #f6f6f6;
  1036 + border-top: 1px solid #ccc;
  1037 + border-bottom: 1px solid #ccc;
  1038 + padding: 1em;
  1039 +}
  1040 +#article .uploaded-file-description.empty {
  1041 + display: none;
  1042 +}
  1043 +
  1044 +#article.file-generic .download-link {
  1045 + display: block;
  1046 + margin-bottom: 10px;
  1047 +}
  1048 +#article.file-generic .download-link span {
  1049 + font-size: 150%;
  1050 + padding-right: 5px;
  1051 +}
  1052 +#article.file-generic .download-link a {
  1053 + font-size: 180%;
  1054 + text-decoration: none;
  1055 +}
1022 1056
1023 /**************************** Comments *******************************/ 1057 /**************************** Comments *******************************/
1024 1058
public/javascripts/application.js
@@ -709,7 +709,7 @@ jQuery(function($) { @@ -709,7 +709,7 @@ jQuery(function($) {
709 document.location.href = this.href; 709 document.location.href = this.href;
710 }) 710 })
711 } 711 }
712 - $('#manage-enterprises-link').live('click', function() { 712 + $('.manage-groups > a').live('click', function() {
713 toggleMenu(this); 713 toggleMenu(this);
714 return false; 714 return false;
715 }); 715 });
public/javascripts/spam.js 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +function removeTaskBox(button, url, task_box_id, msg) {
  2 + var $ = jQuery;
  3 + if (msg && !confirm(msg)) {
  4 + return;
  5 + }
  6 + button = $(button);
  7 + button.addClass('task-button-loading');
  8 + $.post(url, function (data) {
  9 + if (data.ok) {
  10 + $('#' + task_box_id).slideUp();
  11 + } else {
  12 + button.removeClass('task-button-loading');
  13 + button.addClass('task-button-failure');
  14 + }
  15 + });
  16 +}
  17 +
  18 +function toggleDetails(link, msg_hide, msg_show) {
  19 + var $ = jQuery;
  20 + $(link).toggleClass('icon-up icon-down');
  21 + details = $(link).closest('.task_box').find('.suggest-article-details');
  22 + if (details.css('display') == 'none') {
  23 + link.innerHTML = msg_hide;
  24 + } else {
  25 + link.innerHTML = msg_show;
  26 + }
  27 + details.slideToggle();
  28 +}
public/stylesheets/application.css
@@ -882,6 +882,40 @@ code input { @@ -882,6 +882,40 @@ code input {
882 .webkit #manage-enterprises .simplemenu-submenu { 882 .webkit #manage-enterprises .simplemenu-submenu {
883 top: 20px; 883 top: 20px;
884 } 884 }
  885 +#manage-communities {
  886 + display: inline-block;
  887 + margin-right: 5px;
  888 + position: relative;
  889 +}
  890 +#manage-communities .ui-icon {
  891 + position: absolute;
  892 + top: 0;
  893 + right: -20px;
  894 +}
  895 +#manage-communities .simplemenu-submenu {
  896 + text-align: left;
  897 + left: -20px;
  898 + width: 200px;
  899 +}
  900 +#manage-communities .simplemenu-item {
  901 + padding: 5px 0;
  902 +}
  903 +#manage-communities .simplemenu-item a {
  904 + background-repeat: no-repeat;
  905 + padding-left: 20px;
  906 +}
  907 +#manage-communities .simplemenu-item a span {
  908 + display: none;
  909 +}
  910 +.msie8 #manage-communities-link { /* IE8 hack */
  911 + border: 0px solid;
  912 +}
  913 +.msie8 #manage-communities .simplemenu-submenu {
  914 + top: 16px;
  915 +}
  916 +.webkit #manage-communities .simplemenu-submenu {
  917 + top: 20px;
  918 +}
885 #article { 919 #article {
886 position: relative; 920 position: relative;
887 text-align: justify; 921 text-align: justify;
@@ -1552,6 +1586,7 @@ a.button.disabled, input.disabled { @@ -1552,6 +1586,7 @@ a.button.disabled, input.disabled {
1552 .map { 1586 .map {
1553 clear: both; 1587 clear: both;
1554 } 1588 }
  1589 +
1555 /*********************************************************** 1590 /***********************************************************
1556 * style for blocks 1591 * style for blocks
1557 ***********************************************************/ 1592 ***********************************************************/
@@ -3176,6 +3211,14 @@ table.cms-articles .icon:hover { @@ -3176,6 +3211,14 @@ table.cms-articles .icon:hover {
3176 background: #eeeeec; 3211 background: #eeeeec;
3177 border: 1px solid #d3d7cf; 3212 border: 1px solid #d3d7cf;
3178 } 3213 }
  3214 +
  3215 +.controller-cms .article-mime {
  3216 + max-width: 90px;
  3217 + overflow: hidden;
  3218 + text-overflow: ellipsis;
  3219 + white-space: nowrap;
  3220 +}
  3221 +
3179 .controller-cms .article-controls { 3222 .controller-cms .article-controls {
3180 white-space: nowrap; 3223 white-space: nowrap;
3181 } 3224 }
@@ -3446,26 +3489,7 @@ div#article-parent { @@ -3446,26 +3489,7 @@ div#article-parent {
3446 .article-body-uploaded-file { 3489 .article-body-uploaded-file {
3447 text-align: center; 3490 text-align: center;
3448 } 3491 }
3449 -/************* uploaded file *****************/  
3450 3492
3451 -#article .gallery-navigation {  
3452 - padding: 10px 0;  
3453 -}  
3454 -#article .gallery-navigation .left {  
3455 - margin-right: 10px;  
3456 -}  
3457 -#article .gallery-navigation .right {  
3458 - margin-left: 10px;  
3459 -}  
3460 -#article .gallery-navigation .total-of-images {  
3461 - font-weight: bold;  
3462 -}  
3463 -#article .uploaded-file-description {  
3464 - background: #f6f6f6;  
3465 - border-top: 1px solid #ccc;  
3466 - border-bottom: 1px solid #ccc;  
3467 - padding: 1em;  
3468 -}  
3469 /* ==> public/stylesheets/controller_events.css <== */ 3493 /* ==> public/stylesheets/controller_events.css <== */
3470 #agenda { 3494 #agenda {
3471 position: relative; 3495 position: relative;
script/development
1 #!/bin/sh 1 #!/bin/sh
2 2
  3 +set -e
  4 +
3 export RAILS_ENV=development 5 export RAILS_ENV=development
4 6
5 stop() { 7 stop() {
@@ -9,6 +11,7 @@ stop() { @@ -9,6 +11,7 @@ stop() {
9 } 11 }
10 12
11 start() { 13 start() {
  14 + rake db:abort_if_pending_migrations
12 ./script/feed-updater start 15 ./script/feed-updater start
13 ./script/delayed_job start 16 ./script/delayed_job start
14 trap stop INT TERM 17 trap stop INT TERM
script/quick-start
@@ -67,10 +67,25 @@ else @@ -67,10 +67,25 @@ else
67 fi 67 fi
68 68
69 # create the database with sample data 69 # create the database with sample data
70 -run cp config/database.yml.pgsql config/database.yml  
71 -sudo -u postgres createuser $USER --no-superuser --createdb --no-createrole  
72 -sed -ri "s/username: noosfero/username: $USER/" config/database.yml  
73 -sudo -u postgres createdb noosfero_development -O $USER 70 +if test -e config/database.yml; then
  71 + say 'Not updating existent database.yml.'
  72 + say 'If you wish to automatic reconfigure your database connection, you can delete config/database.yml and run this script again.'
  73 +else
  74 + say 'Configuring Noosfero to use PostgreSQL, with your user.'
  75 + run cp config/database.yml.pgsql config/database.yml
  76 + sed -ri "s/username: noosfero/username: $USER/" config/database.yml
  77 + sudo -u postgres createuser $USER --no-superuser --createdb --no-createrole
  78 +fi
  79 +DB_USER="$(
  80 + grep username: config/database.yml | head -n1 | sed -r 's/.*:\s*([^ ]+).*/\1/'
  81 +)"
  82 +if test -n "$DB_USER"; then
  83 + say "DB user: $DB_USER"
  84 +else
  85 + say 'It looks like your database.yml have no user defined'
  86 + DB_USER=$USER
  87 +fi
  88 +sudo -u postgres createdb noosfero_development -O $DB_USER
74 run rake db:schema:load 89 run rake db:schema:load
75 run rake db:data:minimal 90 run rake db:data:minimal
76 run rake db:test:prepare 91 run rake db:test:prepare
test/functional/cms_controller_test.rb
@@ -940,8 +940,8 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -940,8 +940,8 @@ class CmsControllerTest &lt; ActionController::TestCase
940 :article => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')} 940 :article => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')}
941 941
942 process_delayed_job_queue 942 process_delayed_job_queue
943 - file = profile.articles.find_by_name('rails.png')  
944 - assert File.exists?(file.class.icon_name(file)) 943 + file = FilePresenter.for profile.articles.find_by_name('rails.png')
  944 + assert File.exists?(file.icon_name)
945 file.destroy 945 file.destroy
946 end 946 end
947 947
@@ -951,8 +951,8 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -951,8 +951,8 @@ class CmsControllerTest &lt; ActionController::TestCase
951 :article => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')} 951 :article => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')}
952 952
953 process_delayed_job_queue 953 process_delayed_job_queue
954 - file = profile.articles.find_by_name('rails.png')  
955 - assert File.exists?(file.class.icon_name(file)) 954 + file = FilePresenter.for profile.articles.find_by_name('rails.png')
  955 + assert File.exists?(file.icon_name)
956 file.destroy 956 file.destroy
957 end 957 end
958 958
test/functional/content_viewer_controller_test.rb
@@ -1271,4 +1271,12 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1271,4 +1271,12 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1271 assert_tag :tag => 'strong', :content => /bold/ 1271 assert_tag :tag => 'strong', :content => /bold/
1272 end 1272 end
1273 1273
  1274 + should 'display link to download of non-recognized file types on its page' do
  1275 + file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'bin/unknown'), :profile => profile)
  1276 + get :view_page, file.url.merge(:view=>:true)
  1277 + assert_tag :tag => 'a',
  1278 + :content => file.filename,
  1279 + :attributes => { :href => file.public_filename }
  1280 + end
  1281 +
1274 end 1282 end
test/functional/memberships_controller_test.rb
@@ -245,4 +245,17 @@ class MembershipsControllerTest &lt; ActionController::TestCase @@ -245,4 +245,17 @@ class MembershipsControllerTest &lt; ActionController::TestCase
245 assert_tag :tag => 'input', :attributes => {:id => 'community_plugin2', :type => 'hidden', :value => 'Plugin 2'} 245 assert_tag :tag => 'input', :attributes => {:id => 'community_plugin2', :type => 'hidden', :value => 'Plugin 2'}
246 end 246 end
247 247
  248 + should 'redirect to back_to parameter when create a new community' do
  249 + back_to = '/'
  250 + post :new_community, :profile => profile.identifier, :community => { :name => 'My shiny new community', :description => 'This is a community devoted to anything interesting we find in the internet '}, :back_to => back_to
  251 + assert_response :redirect
  252 + assert_redirected_to back_to
  253 + end
  254 +
  255 + should 'cancel button redirect to back_to parameter' do
  256 + back_to = '/'
  257 + get :new_community, :profile => profile.identifier, :back_to => back_to
  258 + assert_tag :tag => 'a', :attributes => { :class => 'button icon-cancel with-text', :href => back_to }
  259 + end
  260 +
248 end 261 end
test/functional/profile_controller_test.rb
@@ -17,11 +17,11 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -17,11 +17,11 @@ class ProfileControllerTest &lt; ActionController::TestCase
17 def test_local_files_reference 17 def test_local_files_reference
18 assert_local_files_reference 18 assert_local_files_reference
19 end 19 end
20 - 20 +
21 def test_valid_xhtml 21 def test_valid_xhtml
22 assert_valid_xhtml 22 assert_valid_xhtml
23 end 23 end
24 - 24 +
25 noosfero_test :profile => 'testuser' 25 noosfero_test :profile => 'testuser'
26 26
27 should 'list friends' do 27 should 'list friends' do
@@ -68,7 +68,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -68,7 +68,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
68 assert_template 'members' 68 assert_template 'members'
69 assert_kind_of Array, assigns(:members) 69 assert_kind_of Array, assigns(:members)
70 end 70 end
71 - 71 +
72 should 'list favorite enterprises' do 72 should 'list favorite enterprises' do
73 get :favorite_enterprises 73 get :favorite_enterprises
74 74
@@ -96,7 +96,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -96,7 +96,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
96 end 96 end
97 97
98 should 'not show enterprises link to enterprise' do 98 should 'not show enterprises link to enterprise' do
99 - ent = fast_create(Enterprise, :identifier => 'test_enterprise1', :name => 'Test enteprise1') 99 + ent = fast_create(Enterprise, :identifier => 'test_enterprise1', :name => 'Test enterprise1')
100 get :index, :profile => ent.identifier 100 get :index, :profile => ent.identifier
101 assert_no_tag :tag => 'a', :content => 'Enterprises', :attributes => { :href => /profile\/#{ent.identifier}\/enterprises$/ } 101 assert_no_tag :tag => 'a', :content => 'Enterprises', :attributes => { :href => /profile\/#{ent.identifier}\/enterprises$/ }
102 end 102 end
@@ -318,7 +318,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -318,7 +318,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
318 get :profile_info, :profile => 'my-test-enterprise', :block_id => block.id 318 get :profile_info, :profile => 'my-test-enterprise', :block_id => block.id
319 assert_no_match /\/contact\/my-test-enterprise\/new/, @response.body 319 assert_no_match /\/contact\/my-test-enterprise\/new/, @response.body
320 end 320 end
321 - 321 +
322 should 'display contact button only if friends' do 322 should 'display contact button only if friends' do
323 friend = create_user_full('friend_user').person 323 friend = create_user_full('friend_user').person
324 friend.user.activate 324 friend.user.activate
@@ -560,7 +560,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -560,7 +560,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
560 assert_response 403 560 assert_response 403
561 end 561 end
562 562
563 - should 'allow environment admin to unblock enteprises' do 563 + should 'allow environment admin to unblock enterprises' do
564 login_as(profile.identifier) 564 login_as(profile.identifier)
565 enterprise = fast_create(Enterprise) 565 enterprise = fast_create(Enterprise)
566 enterprise.environment.add_admin(profile) 566 enterprise.environment.add_admin(profile)
@@ -881,7 +881,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -881,7 +881,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
881 assert_template 'index' 881 assert_template 'index'
882 end 882 end
883 883
884 - should 'the network activity be visible to uses not logged in on communities and enteprises' do 884 + should 'the network activity be visible to uses not logged in on communities and enterprises' do
885 p1= Person.first 885 p1= Person.first
886 community = fast_create(Community) 886 community = fast_create(Community)
887 p2= fast_create(Person) 887 p2= fast_create(Person)
@@ -1091,7 +1091,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1091,7 +1091,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1091 login_as(profile.identifier) 1091 login_as(profile.identifier)
1092 person = fast_create(Person) 1092 person = fast_create(Person)
1093 at = fast_create(ActionTracker::Record, :user_id => person.id) 1093 at = fast_create(ActionTracker::Record, :user_id => person.id)
1094 - atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id) 1094 + atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
1095 get :index, :profile => person.identifier 1095 get :index, :profile => person.identifier
1096 assert_no_tag :tag => 'div', :attributes => {:id => 'profile-network'} 1096 assert_no_tag :tag => 'div', :attributes => {:id => 'profile-network'}
1097 1097
@@ -1103,7 +1103,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1103,7 +1103,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1103 should "not show the scrap button on network activity if the user is himself" do 1103 should "not show the scrap button on network activity if the user is himself" do
1104 login_as(profile.identifier) 1104 login_as(profile.identifier)
1105 at = fast_create(ActionTracker::Record, :user_id => profile.id) 1105 at = fast_create(ActionTracker::Record, :user_id => profile.id)
1106 - atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id) 1106 + atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
1107 get :index, :profile => profile.identifier 1107 get :index, :profile => profile.identifier
1108 assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'} 1108 assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
1109 end 1109 end
@@ -1131,7 +1131,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1131,7 +1131,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1131 at = fast_create(ActionTracker::Record, :user_id => profile.id) 1131 at = fast_create(ActionTracker::Record, :user_id => profile.id)
1132 profile.public_profile=false 1132 profile.public_profile=false
1133 profile.save 1133 profile.save
1134 - atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id) 1134 + atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
1135 get :index, :profile => profile.identifier 1135 get :index, :profile => profile.identifier
1136 assert_equal [at], profile.tracked_actions 1136 assert_equal [at], profile.tracked_actions
1137 assert_no_tag :tag => 'li', :attributes => {:id => "profile-activity-item-#{atn.id}"} 1137 assert_no_tag :tag => 'li', :attributes => {:id => "profile-activity-item-#{atn.id}"}
@@ -1276,7 +1276,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1276,7 +1276,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1276 login_as(profile.identifier) 1276 login_as(profile.identifier)
1277 get :index, :profile => profile.identifier 1277 get :index, :profile => profile.identifier
1278 1278
1279 - assert_tag :tag => 'p', :content => 'A scrap', :attributes => { :class => 'profile-activity-text'} 1279 + assert_tag :tag => 'p', :content => 'A scrap', :attributes => { :class => 'profile-activity-text'}
1280 assert_tag :tag => 'div', :attributes => { :class => 'profile-activity-lead' }, :descendant => { :tag => 'a', :content => 'An article about free software' } 1280 assert_tag :tag => 'div', :attributes => { :class => 'profile-activity-lead' }, :descendant => { :tag => 'a', :content => 'An article about free software' }
1281 end 1281 end
1282 1282
@@ -1549,6 +1549,109 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1549,6 +1549,109 @@ class ProfileControllerTest &lt; ActionController::TestCase
1549 assert_tag :tag => 'td', :content => 'e-Mail:' 1549 assert_tag :tag => 'td', :content => 'e-Mail:'
1550 end 1550 end
1551 1551
  1552 + should 'not display list of communities to manage on menu by default' do
  1553 + user = create_user('community_admin').person
  1554 + community = fast_create(Community)
  1555 + community.add_admin(user)
  1556 +
  1557 + login_as(user.identifier)
  1558 + get :index
  1559 + assert_no_tag :tag => 'div', :attributes => {:id => 'manage-communities'}
  1560 + end
  1561 +
  1562 + should 'display list of communities to manage on menu if enabled' do
  1563 + user = create_user('community_admin').person
  1564 + env = user.environment
  1565 + community = fast_create(Community)
  1566 + community.add_admin(user)
  1567 +
  1568 + Environment.any_instance.stubs(:enabled?).returns(false)
  1569 + Environment.any_instance.stubs(:enabled?).with(:display_my_communities_on_user_menu).returns(true)
  1570 +
  1571 + login_as(user.identifier)
  1572 + get :index
  1573 + assert_tag :tag => 'div', :attributes => {:id => 'manage-communities'}
  1574 +
  1575 + end
  1576 +
  1577 + should 'build menu to the community panel of communities the user can manage if enabled' do
  1578 + u = create_user('other_other_ze').person
  1579 + u2 = create_user('guy_that_will_be_admin_of_all').person # because the first member of each community is an admin
  1580 +
  1581 + Environment.any_instance.stubs(:enabled?).returns(false)
  1582 + Environment.any_instance.stubs(:enabled?).with(:display_my_communities_on_user_menu).returns(true)
  1583 +
  1584 + Environment.any_instance.stubs(:required_person_fields).returns([])
  1585 + u.data = { :email => 'test@test.com', :fields_privacy => { } }
  1586 + u.save!
  1587 + c1 = fast_create(Community, :name => 'community_1')
  1588 + c2 = fast_create(Community, :name => 'community_2')
  1589 + c3 = fast_create(Community, :name => 'community_3')
  1590 + c4 = fast_create(Community, :name => 'community_4')
  1591 +
  1592 + c1.add_admin(u2)
  1593 + c2.add_admin(u2)
  1594 + c3.add_admin(u2)
  1595 +
  1596 + c1.add_member(u)
  1597 + c2.add_member(u)
  1598 + c3.add_member(u)
  1599 + c1.add_admin(u)
  1600 + c2.add_admin(u)
  1601 +
  1602 + login_as(u.identifier)
  1603 +
  1604 + get :index
  1605 +
  1606 + assert_tag :tag => 'div', :attributes => {:id => 'manage-communities'}
  1607 + assert_select '#manage-communities li > a' do |links|
  1608 + assert_equal 2, links.length
  1609 + assert_match /community_1/, links.to_s
  1610 + assert_match /community_2/, links.to_s
  1611 + assert_no_match /community_3/, links.to_s
  1612 + assert_no_match /community_4/, links.to_s
  1613 + end
  1614 + end
  1615 +
  1616 + should 'build menu to the enterprise panel if enabled' do
  1617 + u = create_user('other_other_ze').person
  1618 +
  1619 + Environment.any_instance.stubs(:enabled?).returns(false)
  1620 + Environment.any_instance.stubs(:enabled?).with(:display_my_enterprises_on_user_menu).returns(true)
  1621 +
  1622 + Environment.any_instance.stubs(:required_person_fields).returns([])
  1623 + u.data = { :email => 'test@test.com', :fields_privacy => { } }
  1624 + u.save!
  1625 + e1 = fast_create(Enterprise, :identifier => 'test_enterprise1', :name => 'Test enterprise1')
  1626 + e2 = fast_create(Enterprise, :identifier => 'test_enterprise2', :name => 'Test enterprise2')
  1627 +
  1628 + e1.add_member(u)
  1629 +
  1630 + login_as(u.identifier)
  1631 +
  1632 + get :index
  1633 +
  1634 + assert_tag :tag => 'div', :attributes => {:id => 'manage-enterprises'}
  1635 + assert_select '#manage-enterprises li > a' do |links|
  1636 + assert_equal 1, links.length
  1637 + assert_match /Test enterprise1/, links.to_s
  1638 + assert_no_match /Test enterprise_2/, links.to_s
  1639 + end
  1640 + end
  1641 +
  1642 + should 'not build menu to the enterprise panel if not enabled' do
  1643 + user = create_user('enterprise_admin').person
  1644 + enterprise = fast_create(Enterprise)
  1645 + enterprise.add_admin(user)
  1646 +
  1647 + Environment.any_instance.stubs(:enabled?).returns(false)
  1648 + Environment.any_instance.stubs(:enabled?).with(:display_my_enterprises_on_user_menu).returns(false)
  1649 +
  1650 + login_as(user.identifier)
  1651 + get :index
  1652 + assert_no_tag :tag => 'div', :attributes => {:id => 'manage-enterprises'}
  1653 + end
  1654 +
1552 should 'show enterprises field if enterprises are enabled on environment' do 1655 should 'show enterprises field if enterprises are enabled on environment' do
1553 person = fast_create(Person) 1656 person = fast_create(Person)
1554 environment = person.environment 1657 environment = person.environment
test/functional/spam_controller_test.rb
@@ -4,37 +4,55 @@ class SpamControllerTest &lt; ActionController::TestCase @@ -4,37 +4,55 @@ class SpamControllerTest &lt; ActionController::TestCase
4 4
5 def setup 5 def setup
6 @profile = create_user.person 6 @profile = create_user.person
7 - @article = fast_create(TextileArticle, :profile_id => @profile.id)  
8 - @spam = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com')  
9 7
  8 + @community = fast_create(Community, :name => 'testcommunity')
  9 + @community.add_admin(@profile)
  10 + @article = fast_create(TextileArticle, :profile_id => @community.id)
  11 + @spam_comment = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com')
  12 +
  13 + @spam_suggest_article = SuggestArticle.create!(:name => 'spammer', :article_name => 'Spam article', :email => 'spammer@shady.place', :article_body => "Something you don't need", :target => @community, :spam => true)
10 login_as @profile.identifier 14 login_as @profile.identifier
11 end 15 end
12 16
13 - test "should only list spammy comments" do 17 + test "should only list spammy comments and spammy suggest articles" do
14 ham = fast_create(Comment, :source_id => @article.id) 18 ham = fast_create(Comment, :source_id => @article.id)
15 19
16 - get :index, :profile => @profile.identifier 20 + get :index, :profile => @community.identifier
17 21
18 - assert_equivalent [@spam], assigns(:spam) 22 + assert_equivalent [@spam_comment], assigns(:comment_spam)
  23 + assert_equivalent [@spam_suggest_article], assigns(:task_spam)
19 end 24 end
20 25
21 test "should mark comments as ham" do 26 test "should mark comments as ham" do
22 - post :index, :profile => @profile.identifier, :mark_comment_as_ham => @spam.id 27 + post :index, :profile => @community.identifier, :mark_comment_as_ham => @spam_comment.id
  28 +
  29 + @spam_comment.reload
  30 + assert @spam_comment.ham?
  31 + end
  32 +
  33 + test "should mark suggest article as ham" do
  34 + post :index, :profile => @community.identifier, :mark_task_as_ham => @spam_suggest_article.id
23 35
24 - @spam.reload  
25 - assert @spam.ham? 36 + @spam_suggest_article.reload
  37 + assert @spam_suggest_article.ham?
26 end 38 end
27 39
28 test "should remove comments" do 40 test "should remove comments" do
29 - post :index, :profile => @profile.identifier, :remove_comment => @spam.id 41 + post :index, :profile => @community.identifier, :remove_comment => @spam_comment.id
  42 +
  43 + assert !Comment.exists?(@spam_comment.id)
  44 + end
  45 +
  46 + test "should remove suggest articles" do
  47 + post :index, :profile => @community.identifier, :remove_task => @spam_suggest_article.id
30 48
31 - assert !Comment.exists?(@spam.id) 49 + assert !SuggestArticle.exists?(@spam_suggest_article.id)
32 end 50 end
33 51
34 should 'properly render spam that have replies' do 52 should 'properly render spam that have replies' do
35 - reply_spam = fast_create(Comment, :source_id => @article_id, :reply_of_id => @spam.id) 53 + reply_spam = fast_create(Comment, :source_id => @article_id, :reply_of_id => @spam_comment.id)
36 54
37 - get :index, :profile => @profile.identifier 55 + get :index, :profile => @community.identifier
38 assert_response :success 56 assert_response :success
39 end 57 end
40 58
test/functional/tasks_controller_test.rb
@@ -38,6 +38,17 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -38,6 +38,17 @@ class TasksControllerTest &lt; ActionController::TestCase
38 assert_kind_of Array, assigns(:tasks) 38 assert_kind_of Array, assigns(:tasks)
39 end 39 end
40 40
  41 + should 'list pending tasks without spam' do
  42 + requestor = fast_create(Person)
  43 + task_spam = Task.create!(:requestor => requestor, :target => profile, :spam => true)
  44 + task_ham = Task.create!(:requestor => requestor, :target => profile, :spam => false)
  45 +
  46 + get :index
  47 + assert_response :success
  48 + assert_includes assigns(:tasks), task_ham
  49 + assert_not_includes assigns(:tasks), task_spam
  50 + end
  51 +
41 should 'list processed tasks' do 52 should 'list processed tasks' do
42 get :processed 53 get :processed
43 54
@@ -46,6 +57,17 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -46,6 +57,17 @@ class TasksControllerTest &lt; ActionController::TestCase
46 assert_kind_of Array, assigns(:tasks) 57 assert_kind_of Array, assigns(:tasks)
47 end 58 end
48 59
  60 + should 'list processed tasks without spam' do
  61 + requestor = fast_create(Person)
  62 + task_spam = Task.create!(:status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => true)
  63 + task_ham = Task.create!(:status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => false)
  64 +
  65 + get :processed
  66 + assert_response :success
  67 + assert_includes assigns(:tasks), task_ham
  68 + assert_not_includes assigns(:tasks), task_spam
  69 + end
  70 +
49 should 'be able to finish a task' do 71 should 'be able to finish a task' do
50 t = profile.tasks.build; t.save! 72 t = profile.tasks.build; t.save!
51 73
@@ -140,6 +162,15 @@ class TasksControllerTest &lt; ActionController::TestCase @@ -140,6 +162,15 @@ class TasksControllerTest &lt; ActionController::TestCase
140 assert_includes assigns(:tasks), task 162 assert_includes assigns(:tasks), task
141 end 163 end
142 164
  165 + should 'list tasks that this profile created without spam' do
  166 + task_spam = Ticket.create!(:name => 'test', :requestor => profile, :spam => true)
  167 + task_ham = Ticket.create!(:name => 'test', :requestor => profile, :spam => false)
  168 + get :list_requested, :profile => profile.identifier
  169 +
  170 + assert_includes assigns(:tasks), task_ham
  171 + assert_not_includes assigns(:tasks), task_spam
  172 + end
  173 +
143 should 'set target of ticket when creating it' do 174 should 'set target of ticket when creating it' do
144 f = create_user('friend').person 175 f = create_user('friend').person
145 profile.add_friend f 176 profile.add_friend f
test/unit/application_helper_test.rb
@@ -591,8 +591,8 @@ class ApplicationHelperTest &lt; ActiveSupport::TestCase @@ -591,8 +591,8 @@ class ApplicationHelperTest &lt; ActiveSupport::TestCase
591 end 591 end
592 592
593 should 'include item in usermenu for environment enabled features' do 593 should 'include item in usermenu for environment enabled features' do
594 - env = Environment.new  
595 - env.enable('xmpp_chat') 594 + env = fast_create(Environment)
  595 + env.enable('xmpp_chat', false)
596 stubs(:environment).returns(env) 596 stubs(:environment).returns(env)
597 597
598 @controller = ApplicationController.new 598 @controller = ApplicationController.new
@@ -791,6 +791,29 @@ class ApplicationHelperTest &lt; ActiveSupport::TestCase @@ -791,6 +791,29 @@ class ApplicationHelperTest &lt; ActiveSupport::TestCase
791 '<br style=\'clear: left;\' /></div>', result 791 '<br style=\'clear: left;\' /></div>', result
792 end 792 end
793 793
  794 + should 'not filter html if source does not have macros' do
  795 + class Plugin1 < Noosfero::Plugin
  796 + end
  797 +
  798 + class Plugin1::Macro1 < Noosfero::Plugin::Macro
  799 + def parse(params, inner_html, source)
  800 + 'Test1'
  801 + end
  802 + end
  803 +
  804 + environment = Environment.default
  805 + environment.enable_plugin(Plugin1)
  806 + @plugins = Noosfero::Plugin::Manager.new(environment, self)
  807 + macro1_name = Plugin1::Macro1.identifier
  808 + source = mock
  809 + source.stubs(:has_macro?).returns(false)
  810 +
  811 + html = "<div class='macro nonEdit' data-macro='#{macro1_name}' data-macro-param='123'></div>"
  812 + parsed_html = filter_html(html, source)
  813 +
  814 + assert_no_match /Test1/, parsed_html
  815 + end
  816 +
794 protected 817 protected
795 include NoosferoTestHelper 818 include NoosferoTestHelper
796 819
test/unit/article_block_test.rb
@@ -110,9 +110,12 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase @@ -110,9 +110,12 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase
110 block.article = image 110 block.article = image
111 block.save! 111 block.save!
112 112
113 - expects(:image_tag).with(image.public_filename(:display), :class => image.css_class_name, :style => 'max-width: 100%').returns('image')  
114 -  
115 - assert_match(/image/, instance_eval(&block.content)) 113 + assert_tag_in_string instance_eval(&block.content),
  114 + :tag => 'img',
  115 + :attributes => {
  116 + :src => image.public_filename(:display),
  117 + :class => /file-image/
  118 + }
116 end 119 end
117 120
118 should 'not display gallery pages navigation in content' do 121 should 'not display gallery pages navigation in content' do
@@ -123,8 +126,6 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase @@ -123,8 +126,6 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase
123 block.article = image 126 block.article = image
124 block.save! 127 block.save!
125 128
126 - expects(:image_tag).with(image.public_filename(:display), :class => image.css_class_name, :style => 'max-width: 100%').returns('image')  
127 -  
128 assert_no_match(/Previous/, instance_eval(&block.content)) 129 assert_no_match(/Previous/, instance_eval(&block.content))
129 end 130 end
130 131
test/unit/article_test.rb
@@ -1744,4 +1744,33 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1744,4 +1744,33 @@ class ArticleTest &lt; ActiveSupport::TestCase
1744 assert_nil article.author_id 1744 assert_nil article.author_id
1745 end 1745 end
1746 1746
  1747 + should 'identify if belongs to forum' do
  1748 + p = create_user('user_forum_test').person
  1749 + forum = fast_create(Forum, :name => 'Forum test', :profile_id => p.id)
  1750 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => p.id, :parent_id => forum.id)
  1751 + assert post.belongs_to_forum?
  1752 + end
  1753 +
  1754 + should 'not belongs to forum' do
  1755 + p = create_user('user_forum_test').person
  1756 + blog = fast_create(Blog, :name => 'Not Forum', :profile_id => p.id)
  1757 + a = fast_create(TextileArticle, :name => 'Not forum post', :profile_id => p.id, :parent_id => blog.id)
  1758 + assert !a.belongs_to_forum?
  1759 + end
  1760 +
  1761 + should 'not belongs to forum if do not have a parent' do
  1762 + p = create_user('user_forum_test').person
  1763 + a = fast_create(TextileArticle, :name => 'Orphan post', :profile_id => p.id)
  1764 + assert !a.belongs_to_forum?
  1765 + end
  1766 +
  1767 + should 'save image on create article' do
  1768 + assert_difference Article, :count do
  1769 + p = Article.create!(:name => 'test', :image_builder => {
  1770 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  1771 + }, :profile_id => @profile.id)
  1772 + assert_equal p.image(true).filename, 'rails.png'
  1773 + end
  1774 + end
  1775 +
1747 end 1776 end
test/unit/block_test.rb
@@ -156,4 +156,13 @@ class BlockTest &lt; ActiveSupport::TestCase @@ -156,4 +156,13 @@ class BlockTest &lt; ActiveSupport::TestCase
156 assert_equal box.environment, block.environment 156 assert_equal box.environment, block.environment
157 end 157 end
158 158
  159 + should 'inform conditions for expiration on profile context' do
  160 + conditions = Block.expire_on
  161 + assert conditions[:profile].kind_of?(Array)
  162 + end
  163 +
  164 + should 'inform conditions for expiration on environment context' do
  165 + conditions = Block.expire_on
  166 + assert conditions[:environment].kind_of?(Array)
  167 + end
159 end 168 end
test/unit/blog_helper_test.rb
@@ -94,10 +94,10 @@ class BlogHelperTest &lt; ActiveSupport::TestCase @@ -94,10 +94,10 @@ class BlogHelperTest &lt; ActiveSupport::TestCase
94 should 'display link to file if post is an uploaded_file' do 94 should 'display link to file if post is an uploaded_file' do
95 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog) 95 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog)
96 96
97 - expects(:article_to_html).with(file).returns('TO HTML')  
98 -  
99 result = display_post(file) 97 result = display_post(file)
100 - assert_tag_in_string result, :content => /TO HTML/ 98 + assert_tag_in_string result, :tag => 'a',
  99 + :attributes => { :href => file.public_filename },
  100 + :content => file.filename
101 end 101 end
102 102
103 should 'display image if post is an image' do 103 should 'display image if post is an image' do
test/unit/category_test.rb
@@ -168,11 +168,11 @@ class CategoryTest &lt; ActiveSupport::TestCase @@ -168,11 +168,11 @@ class CategoryTest &lt; ActiveSupport::TestCase
168 should "limit the possibile display colors" do 168 should "limit the possibile display colors" do
169 c = Category.new(:name => 'test category', :environment_id => @env.id) 169 c = Category.new(:name => 'test category', :environment_id => @env.id)
170 170
171 - c.display_color = 10 171 + c.display_color = 16
172 c.valid? 172 c.valid?
173 assert c.errors.invalid?(:display_color) 173 assert c.errors.invalid?(:display_color)
174 174
175 - valid = %w[ 1 2 3 4 ].map { |item| item.to_i } 175 + valid = (1..15).map { |item| item.to_i }
176 valid.each do |item| 176 valid.each do |item|
177 c.display_color = item 177 c.display_color = item
178 c.valid? 178 c.valid?
test/unit/cms_helper_test.rb
@@ -41,6 +41,7 @@ class CmsHelperTest &lt; ActiveSupport::TestCase @@ -41,6 +41,7 @@ class CmsHelperTest &lt; ActiveSupport::TestCase
41 should 'display image and link if article is an image' do 41 should 'display image and link if article is an image' do
42 profile = fast_create(Profile) 42 profile = fast_create(Profile)
43 file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 43 file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
  44 + file = FilePresenter.for file
44 icon = icon_for_article(file) 45 icon = icon_for_article(file)
45 expects(:image_tag).with(icon).returns('icon') 46 expects(:image_tag).with(icon).returns('icon')
46 47
test/unit/comment_test.rb
@@ -447,7 +447,7 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -447,7 +447,7 @@ class CommentTest &lt; ActiveSupport::TestCase
447 end 447 end
448 448
449 class EverythingIsSpam < Noosfero::Plugin 449 class EverythingIsSpam < Noosfero::Plugin
450 - def check_comment_for_spam(comment) 450 + def check_for_spam(comment)
451 comment.spam! 451 comment.spam!
452 end 452 end
453 end 453 end
@@ -469,11 +469,11 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -469,11 +469,11 @@ class CommentTest &lt; ActiveSupport::TestCase
469 attr_accessor :marked_as_ham 469 attr_accessor :marked_as_ham
470 end 470 end
471 471
472 - def comment_marked_as_spam(c) 472 + def marked_as_spam(c)
473 self.class.marked_as_spam = c 473 self.class.marked_as_spam = c
474 end 474 end
475 475
476 - def comment_marked_as_ham(c) 476 + def marked_as_ham(c)
477 self.class.marked_as_ham = c 477 self.class.marked_as_ham = c
478 end 478 end
479 end 479 end
@@ -523,7 +523,6 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -523,7 +523,6 @@ class CommentTest &lt; ActiveSupport::TestCase
523 comment.spam! 523 comment.spam!
524 log = File.open('log/test_spammers.log') 524 log = File.open('log/test_spammers.log')
525 assert_match "Comment-id: #{comment.id} IP: 192.168.0.1", log.read 525 assert_match "Comment-id: #{comment.id} IP: 192.168.0.1", log.read
526 - SpammerLogger.clean_log  
527 end 526 end
528 527
529 should 'not need moderation if article is not moderated' do 528 should 'not need moderation if article is not moderated' do
test/unit/content_viewer_helper_test.rb
@@ -18,8 +18,15 @@ class ContentViewerHelperTest &lt; ActiveSupport::TestCase @@ -18,8 +18,15 @@ class ContentViewerHelperTest &lt; ActiveSupport::TestCase
18 result = article_title(post) 18 result = article_title(post)
19 assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at) 19 assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at)
20 end 20 end
  21 +
  22 + should 'display published-at for forum posts' do
  23 + forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
  24 + post = TextileArticle.create!(:name => 'post test', :profile => profile, :parent => forum)
  25 + result = article_title(post)
  26 + assert_tag_in_string result, :tag => 'span', :content => show_date(post.published_at)
  27 + end
21 28
22 - should 'not display published-at for non-blog posts' do 29 + should 'not display published-at for non-blog and non-forum posts' do
23 article = TextileArticle.create!(:name => 'article for test', :profile => profile) 30 article = TextileArticle.create!(:name => 'article for test', :profile => profile)
24 result = article_title(article) 31 result = article_title(article)
25 assert_no_match /<span class="date">#{show_date(article.published_at)}<\/span><span class="author">, by .*#{profile.identifier}/, result 32 assert_no_match /<span class="date">#{show_date(article.published_at)}<\/span><span class="author">, by .*#{profile.identifier}/, result
test/unit/environment_statistics_block_test.rb
@@ -84,8 +84,8 @@ class EnvironmentStatisticsBlockTest &lt; ActiveSupport::TestCase @@ -84,8 +84,8 @@ class EnvironmentStatisticsBlockTest &lt; ActiveSupport::TestCase
84 end 84 end
85 85
86 should 'not display enterprises if disabled' do 86 should 'not display enterprises if disabled' do
87 - env = Environment.new  
88 - env.enable('disable_asset_enterprises') 87 + env = fast_create(Environment)
  88 + env.enable('disable_asset_enterprises', false)
89 89
90 block = EnvironmentStatisticsBlock.new 90 block = EnvironmentStatisticsBlock.new
91 block.stubs(:owner).returns(env) 91 block.stubs(:owner).returns(env)
test/unit/environment_test.rb
@@ -34,22 +34,22 @@ class EnvironmentTest &lt; ActiveSupport::TestCase @@ -34,22 +34,22 @@ class EnvironmentTest &lt; ActiveSupport::TestCase
34 end 34 end
35 35
36 def test_features 36 def test_features
37 - v = Environment.new  
38 - v.enable('feature1') 37 + v = fast_create(Environment)
  38 + v.enable('feature1', false)
39 assert v.enabled?('feature1') 39 assert v.enabled?('feature1')
40 - v.disable('feature1') 40 + v.disable('feature1', false)
41 assert !v.enabled?('feature1') 41 assert !v.enabled?('feature1')
42 end 42 end
43 43
44 def test_enabled_features 44 def test_enabled_features
45 - v = Environment.new  
46 - v.enabled_features = [ 'feature1', 'feature2' ] 45 + v = fast_create(Environment)
  46 + v.enable('feature1', false)
  47 + v.enable('feature2', false)
47 assert v.enabled?('feature1') && v.enabled?('feature2') && !v.enabled?('feature3') 48 assert v.enabled?('feature1') && v.enabled?('feature2') && !v.enabled?('feature3')
48 end 49 end
49 50
50 def test_enabled_features_no_features_enabled 51 def test_enabled_features_no_features_enabled
51 - v = Environment.new  
52 - v.enabled_features = nil 52 + v = fast_create(Environment)
53 assert !v.enabled?('feature1') && !v.enabled?('feature2') && !v.enabled?('feature3') 53 assert !v.enabled?('feature1') && !v.enabled?('feature2') && !v.enabled?('feature3')
54 end 54 end
55 55
@@ -1074,10 +1074,10 @@ class EnvironmentTest &lt; ActiveSupport::TestCase @@ -1074,10 +1074,10 @@ class EnvironmentTest &lt; ActiveSupport::TestCase
1074 end 1074 end
1075 1075
1076 should 'get enabled features' do 1076 should 'get enabled features' do
1077 - env = Environment.new  
1078 - env.enable('feature1')  
1079 - env.enable('feature2')  
1080 - env.disable('feature3') 1077 + env = fast_create(Environment)
  1078 + env.enable('feature1', false)
  1079 + env.enable('feature2', false)
  1080 + env.disable('feature3', false)
1081 1081
1082 assert_includes env.enabled_features.keys, 'feature1' 1082 assert_includes env.enabled_features.keys, 'feature1'
1083 assert_includes env.enabled_features.keys, 'feature2' 1083 assert_includes env.enabled_features.keys, 'feature2'
test/unit/file_presenter_test.rb 0 → 100644
@@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class FilePresenterTest < ActiveSupport::TestCase
  4 +
  5 + should 'notify about deprecated method UploadedFile.icon_name' do
  6 + profile = fast_create(Profile)
  7 + file = UploadedFile.create!(
  8 + :profile => profile,
  9 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  10 + )
  11 + assert_raise NoMethodError do
  12 + UploadedFile.icon_name file
  13 + end
  14 + ENV.stubs('[]').with('RAILS_ENV').returns('other')
  15 + Rails.logger.expects(:warn) # must warn on any other RAILS_ENV
  16 + stubs(:puts)
  17 + UploadedFile.icon_name file
  18 + end
  19 +
  20 + should 'notify about deprecated method UploadedFile#to_html' do
  21 + profile = fast_create(Profile)
  22 + file = UploadedFile.create!(
  23 + :profile => profile,
  24 + :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
  25 + )
  26 + assert_raise NoMethodError do
  27 + file.to_html
  28 + end
  29 + ENV.stubs('[]').with('RAILS_ENV').returns('other')
  30 + Rails.logger.expects(:warn) # must warn on any other RAILS_ENV
  31 + stubs(:puts)
  32 + file.to_html
  33 + end
  34 +
  35 + should 'return a thumbnail as icon for images ' do
  36 + f = UploadedFile.new
  37 + f.stubs(:image?).returns(true)
  38 + p = FilePresenter.for f
  39 + p.expects(:public_filename).with(:icon).returns('/path/to/file.xyz')
  40 + assert_equal '/path/to/file.xyz', p.icon_name
  41 + end
  42 +
  43 + should 'not crach when accepts? method receives a pure article' do
  44 + assert_nothing_raised do
  45 + FilePresenter.for Article.new
  46 + end
  47 + end
  48 +
  49 + should 'not crach when accepts? method receives a non-sense object' do
  50 + assert_nothing_raised do
  51 + FilePresenter.for nil
  52 + end
  53 + assert_nothing_raised do
  54 + FilePresenter.for({:key => 'value'})
  55 + end
  56 + assert_nothing_raised do
  57 + FilePresenter.for 'a string'
  58 + end
  59 + end
  60 +
  61 +end
test/unit/folder_helper_test.rb
@@ -26,6 +26,7 @@ class FolderHelperTest &lt; ActiveSupport::TestCase @@ -26,6 +26,7 @@ class FolderHelperTest &lt; ActiveSupport::TestCase
26 should 'display icon for images' do 26 should 'display icon for images' do
27 profile = fast_create(Profile) 27 profile = fast_create(Profile)
28 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile) 28 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile)
  29 + file = FilePresenter.for file
29 process_delayed_job_queue 30 process_delayed_job_queue
30 31
31 assert_match /rails_icon\.png/, icon_for_article(file.reload) 32 assert_match /rails_icon\.png/, icon_for_article(file.reload)
test/unit/link_list_block_test.rb
@@ -23,7 +23,6 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase @@ -23,7 +23,6 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase
23 23
24 should 'list links' do 24 should 'list links' do
25 l = LinkListBlock.new(:links => [{:name => 'products', :address => '/cat/products'}]) 25 l = LinkListBlock.new(:links => [{:name => 'products', :address => '/cat/products'}])
26 - l.expects(:links).returns([{:name => 'products', :address => '/cat/products'}])  
27 assert_match /products/, l.content 26 assert_match /products/, l.content
28 end 27 end
29 28
@@ -83,4 +82,8 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase @@ -83,4 +82,8 @@ class LinkListBlockTest &lt; ActiveSupport::TestCase
83 assert_equal 'always', block.display 82 assert_equal 'always', block.display
84 end 83 end
85 84
  85 + should 'have options for links target' do
  86 + assert_equivalent LinkListBlock::TARGET_OPTIONS.map {|t|t[1]}, ['_self', '_blank', '_new']
  87 + end
  88 +
86 end 89 end
test/unit/plugin_manager_test.rb
@@ -61,6 +61,10 @@ class PluginManagerTest &lt; ActiveSupport::TestCase @@ -61,6 +61,10 @@ class PluginManagerTest &lt; ActiveSupport::TestCase
61 end 61 end
62 62
63 should 'dispatch_first method returns the first plugin response if there is many plugins to responde the event' do 63 should 'dispatch_first method returns the first plugin response if there is many plugins to responde the event' do
  64 + class Noosfero::Plugin
  65 + def random_event
  66 + end
  67 + end
64 68
65 class Plugin1 < Noosfero::Plugin 69 class Plugin1 < Noosfero::Plugin
66 def random_event 70 def random_event
test/unit/profile_list_block_test.rb
@@ -2,6 +2,8 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39; @@ -2,6 +2,8 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
2 2
3 class ProfileListBlockTest < ActiveSupport::TestCase 3 class ProfileListBlockTest < ActiveSupport::TestCase
4 4
  5 + include ActionView::Helpers::TagHelper
  6 +
5 should 'describe itself' do 7 should 'describe itself' do
6 assert_not_equal Block.description, ProfileListBlock.description 8 assert_not_equal Block.description, ProfileListBlock.description
7 end 9 end
@@ -32,6 +34,7 @@ class ProfileListBlockTest &lt; ActiveSupport::TestCase @@ -32,6 +34,7 @@ class ProfileListBlockTest &lt; ActiveSupport::TestCase
32 self.expects(:profile_image_link).with(person2, :minor).once 34 self.expects(:profile_image_link).with(person2, :minor).once
33 self.expects(:profile_image_link).with(person3, :minor).once 35 self.expects(:profile_image_link).with(person3, :minor).once
34 36
  37 + self.stubs(:tag).returns('<div></div>')
35 self.expects(:content_tag).returns('<div></div>').at_least_once 38 self.expects(:content_tag).returns('<div></div>').at_least_once
36 self.expects(:block_title).returns('block title').at_least_once 39 self.expects(:block_title).returns('block title').at_least_once
37 40
test/unit/spammer_logger_test.rb
1 require File.dirname(__FILE__) + '/../test_helper' 1 require File.dirname(__FILE__) + '/../test_helper'
2 2
3 class SpammerLoggerTest < ActiveSupport::TestCase 3 class SpammerLoggerTest < ActiveSupport::TestCase
4 -  
5 - def setup  
6 - SpammerLogger.reload_log  
7 - end  
8 -  
9 - def teardown  
10 - SpammerLogger.clean_log  
11 - end  
12 -  
13 should 'log the spammer ip' do 4 should 'log the spammer ip' do
14 SpammerLogger.log('192.168.0.1') 5 SpammerLogger.log('192.168.0.1')
15 log = File.open('log/test_spammers.log') 6 log = File.open('log/test_spammers.log')
@@ -22,5 +13,4 @@ class SpammerLoggerTest &lt; ActiveSupport::TestCase @@ -22,5 +13,4 @@ class SpammerLoggerTest &lt; ActiveSupport::TestCase
22 log = File.open('log/test_spammers.log') 13 log = File.open('log/test_spammers.log')
23 assert_match "Comment-id: #{comment.id} IP: 192.168.0.1", log.read 14 assert_match "Comment-id: #{comment.id} IP: 192.168.0.1", log.read
24 end 15 end
25 -  
26 end 16 end
test/unit/suggest_article_test.rb
@@ -150,5 +150,78 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase @@ -150,5 +150,78 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
150 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}/, email.subject) 150 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}/, email.subject)
151 end 151 end
152 152
  153 + class EverythingIsSpam < Noosfero::Plugin
  154 + def check_for_spam(object)
  155 + object.spam!
  156 + end
  157 + end
  158 +
  159 + should 'delegate spam detection to plugins' do
  160 + Environment.default.enable_plugin(EverythingIsSpam)
  161 +
  162 + t1 = build(SuggestArticle, :target => @profile, :article_name => 'suggested article', :name => 'johndoe', :email => 'johndoe@example.com')
  163 +
  164 + EverythingIsSpam.any_instance.expects(:check_for_spam)
  165 +
  166 + t1.check_for_spam
  167 + end
  168 +
  169 + class SpamNotification < Noosfero::Plugin
  170 + class << self
  171 + attr_accessor :marked_as_spam
  172 + attr_accessor :marked_as_ham
  173 + end
  174 +
  175 + def check_for_spam(c)
  176 + # do nothing
  177 + end
  178 +
  179 + def marked_as_spam(c)
  180 + self.class.marked_as_spam = c
  181 + end
  182 +
  183 + def marked_as_ham(c)
  184 + self.class.marked_as_ham = c
  185 + end
  186 + end
  187 +
  188 + should 'notify plugins of suggest_articles being marked as spam' do
  189 + Environment.default.enable_plugin(SpamNotification)
  190 +
  191 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com')
  192 +
  193 + t.spam!
  194 + process_delayed_job_queue
  195 +
  196 + assert_equal t, SpamNotification.marked_as_spam
  197 + end
  198 +
  199 + should 'notify plugins of suggest_articles being marked as ham' do
  200 + Environment.default.enable_plugin(SpamNotification)
  201 +
  202 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com')
  203 +
  204 + t.ham!
  205 + process_delayed_job_queue
  206 +
  207 + assert_equal t, SpamNotification.marked_as_ham
  208 + end
  209 +
  210 + should 'store User-Agent' do
  211 + t = SuggestArticle.new(:user_agent => 'foo')
  212 + assert_equal 'foo', t.user_agent
  213 + end
  214 +
  215 + should 'store referrer' do
  216 + t = SuggestArticle.new(:referrer => 'bar')
  217 + assert_equal 'bar', t.referrer
  218 + end
  219 +
  220 + should 'log spammer ip after marking comment as spam' do
  221 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com', :ip_address => '192.168.0.1')
  222 + t.spam!
  223 + log = File.open('log/test_spammers.log')
  224 + assert_match "SuggestArticle-id: #{t.id} IP: 192.168.0.1", log.read
  225 + end
153 226
154 end 227 end
test/unit/task_test.rb
@@ -372,6 +372,55 @@ class TaskTest &lt; ActiveSupport::TestCase @@ -372,6 +372,55 @@ class TaskTest &lt; ActiveSupport::TestCase
372 assert_includes Task.closed, canceled 372 assert_includes Task.closed, canceled
373 end 373 end
374 374
  375 + should 'be ham by default' do # ham means not spam
  376 + assert_equal false, Task.create.spam
  377 + end
  378 +
  379 + should 'be able to mark tasks as spam/ham/unknown' do
  380 + t = Task.new
  381 + t.spam = true
  382 + assert t.spam?
  383 + assert !t.ham?
  384 +
  385 + t.spam = false
  386 + assert t.ham?
  387 + assert !t.spam?
  388 +
  389 + t.spam = nil
  390 + assert !t.spam?
  391 + assert !t.ham?
  392 + end
  393 +
  394 + should 'be able to select non-spam tasks' do
  395 + t1 = fast_create(Task)
  396 + t2 = fast_create(Task, :spam => false)
  397 + t3 = fast_create(Task, :spam => true)
  398 +
  399 + assert_equivalent [t1,t2], Task.without_spam
  400 + end
  401 +
  402 + should 'be able to select spam tasks' do
  403 + t1 = fast_create(Task)
  404 + t2 = fast_create(Task, :spam => false)
  405 + t3 = fast_create(Task, :spam => true)
  406 +
  407 + assert_equivalent [t3], Task.spam
  408 + end
  409 +
  410 + should 'be able to mark as spam' do
  411 + t1 = fast_create(Task)
  412 + t1.spam!
  413 + t1.reload
  414 + assert t1.spam?
  415 + end
  416 +
  417 + should 'be able to mark as ham' do
  418 + t1 = fast_create(Task)
  419 + t1.ham!
  420 + t1.reload
  421 + assert t1.ham?
  422 + end
  423 +
375 protected 424 protected
376 425
377 def sample_user 426 def sample_user
test/unit/uploaded_file_test.rb
@@ -7,13 +7,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -7,13 +7,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
7 end 7 end
8 attr_reader :profile 8 attr_reader :profile
9 9
10 - should 'return a thumbnail as icon for images ' do  
11 - f = UploadedFile.new  
12 - f.expects(:image?).returns(true)  
13 - f.expects(:public_filename).with(:icon).returns('/path/to/file.xyz')  
14 - assert_equal '/path/to/file.xyz', UploadedFile.icon_name(f)  
15 - end  
16 -  
17 should 'return a default icon for uploaded files' do 10 should 'return a default icon for uploaded files' do
18 assert_equal 'upload-file', UploadedFile.icon_name 11 assert_equal 'upload-file', UploadedFile.icon_name
19 end 12 end
@@ -113,8 +106,11 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -113,8 +106,11 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
113 p = create_user('test_user').person 106 p = create_user('test_user').person
114 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => p) 107 file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => p)
115 108
  109 + ENV.stubs('[]').with('RAILS_ENV').returns('other')
  110 + Rails.logger.expects(:warn) # warn about deprecatede usage of UploadedFile#to_html
  111 + stubs(:puts)
116 stubs(:content_tag).returns('link') 112 stubs(:content_tag).returns('link')
117 - expects(:link_to).with(file.name, file.url, :class => file.css_class_name) 113 + expects(:link_to).with(file.name, file.url)
118 114
119 instance_eval(&file.to_html) 115 instance_eval(&file.to_html)
120 end 116 end
@@ -206,13 +202,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -206,13 +202,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
206 file.destroy 202 file.destroy
207 end 203 end
208 204
209 - should 'return the default thumbnail image as icon for images ' do  
210 - f = UploadedFile.new  
211 - f.expects(:image?).returns(true)  
212 - f.expects(:public_filename).with(:icon).returns('/path/to/file.xyz')  
213 - assert_equal '/path/to/file.xyz', UploadedFile.icon_name(f)  
214 - end  
215 -  
216 should 'store width and height after processing' do 205 should 'store width and height after processing' do
217 file = UploadedFile.create!(:profile => @profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 206 file = UploadedFile.create!(:profile => @profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
218 file.create_thumbnails 207 file.create_thumbnails
@@ -287,12 +276,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -287,12 +276,6 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
287 assert_equal '', f.lead 276 assert_equal '', f.lead
288 end 277 end
289 278
290 - should 'survive when try to get icon_name from a file with mime_type nil' do  
291 - f = UploadedFile.new  
292 - f.expects(:mime_type).returns(nil)  
293 - assert_equal 'upload-file', UploadedFile.icon_name(f)  
294 - end  
295 -  
296 should 'upload to a folder with same name as the schema if database is postgresql' do 279 should 'upload to a folder with same name as the schema if database is postgresql' do
297 uses_postgresql 'image_schema_one' 280 uses_postgresql 'image_schema_one'
298 file1 = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => @profile) 281 file1 = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => @profile)
@@ -352,4 +335,26 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -352,4 +335,26 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
352 assert_equal 1, ActionTracker::Record.find_all_by_verb('upload_image').count 335 assert_equal 1, ActionTracker::Record.find_all_by_verb('upload_image').count
353 end 336 end
354 337
  338 + {
  339 + nil => 5.megabytes, # default
  340 + '1KB' => 1.kilobytes,
  341 + '2MB' => 2.megabyte,
  342 + '3GB' => 3.gigabytes,
  343 + '4TB' => 4.terabytes,
  344 + '6 MB' => 6.megabytes, # allow whitespace between number and unit
  345 + '0.5 GB' => 512.megabytes, # allow floating point numbers
  346 + '2' => 2.megabytes, # assume MB as unit by default
  347 + 'INVALID' => 5.megabytes, # use default for invalid input
  348 + '1ZYX' => 5.megabytes, # use default for invalid input
  349 + }.each do |input,output|
  350 + test 'maximum upload size: convert %s into %s' % [input, output] do
  351 + NOOSFERO_CONF.expects(:[]).with('max_upload_size').returns(input)
  352 + assert_equal output, UploadedFile.max_size
  353 + end
  354 + end
  355 + test 'max_size should always return an integer' do
  356 + NOOSFERO_CONF.expects(:[]).with('max_upload_size').returns("0.5 GB")
  357 + assert_instance_of Fixnum, UploadedFile.max_size
  358 + end
  359 +
355 end 360 end
vendor/plugins/action_tracker_has_comments/init.rb
1 # monkey patch to add comments on action_tracker 1 # monkey patch to add comments on action_tracker
2 2
3 -ActionTracker::Record.module_eval do 3 +Rails.configuration.to_prepare do
  4 + ActionTracker::Record.module_eval do
4 5
5 - has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :finder_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments} ORDER BY created_at ASC', :counter_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments}' 6 + has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :finder_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments} ORDER BY created_at ASC', :counter_sql => 'SELECT * FROM comments WHERE #{conditions_for_comments}'
6 7
7 - def conditions_for_comments  
8 - type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id])  
9 - "source_type = '#{type}' AND source_id = '#{id}'"  
10 - end 8 + def conditions_for_comments
  9 + type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id])
  10 + "source_type = '#{type}' AND source_id = '#{id}'"
  11 + end
11 12
12 - def comments_as_thread  
13 - result = {}  
14 - root = []  
15 - self.comments.each do |c|  
16 - c.replies = []  
17 - result[c.id] ||= c  
18 - c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c 13 + def comments_as_thread
  14 + result = {}
  15 + root = []
  16 + self.comments.each do |c|
  17 + c.replies = []
  18 + result[c.id] ||= c
  19 + c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c
  20 + end
  21 + root
19 end 22 end
20 - root  
21 - end  
22 23
  24 + end
23 end 25 end
vendor/plugins/monkey_patches/rescue_delayed_job_crashes/init.rb
1 Delayed::Worker.module_eval do 1 Delayed::Worker.module_eval do
2 # based on https://groups.google.com/forum/#!topic/delayed_job/ZGMUFFppNgs 2 # based on https://groups.google.com/forum/#!topic/delayed_job/ZGMUFFppNgs
3 class Delayed::Worker::ExceptionNotification < ActionMailer::Base 3 class Delayed::Worker::ExceptionNotification < ActionMailer::Base
4 - def mail error 4 + def mail job, error
5 environment = Environment.default 5 environment = Environment.default
6 6
7 recipients NOOSFERO_CONF['exception_recipients'] 7 recipients NOOSFERO_CONF['exception_recipients']
8 from environment.contact_email 8 from environment.contact_email
9 reply_to environment.contact_email 9 reply_to environment.contact_email
10 - subject "[#{environment.name}] DelayedJob: #{error.message}"  
11 - body render(:text => error.backtrace.join("\n")) 10 + subject "[#{environment.name}] DelayedJob ##{job.id}: #{error.message}"
  11 + body render(:text => "
  12 +Job:
  13 +#{job.inspect}
  14 +
  15 +Handler:
  16 +#{job.handler}
  17 +
  18 +Backtrace:
  19 +#{error.backtrace.join("\n")}
  20 + ")
12 end 21 end
13 end 22 end
14 23
15 def handle_failed_job_with_notification(job, error) 24 def handle_failed_job_with_notification(job, error)
16 - Delayed::Worker::ExceptionNotification.deliver_mail error if NOOSFERO_CONF['exception_recipients'].present? 25 + Delayed::Worker::ExceptionNotification.deliver_mail job, error if NOOSFERO_CONF['exception_recipients'].present?
17 handle_failed_job_without_notification job, error 26 handle_failed_job_without_notification job, error
18 end 27 end
19 alias_method_chain :handle_failed_job, :notification 28 alias_method_chain :handle_failed_job, :notification