diff --git a/app/controllers/admin/plugins_controller.rb b/app/controllers/admin/plugins_controller.rb
new file mode 100644
index 0000000..883977e
--- /dev/null
+++ b/app/controllers/admin/plugins_controller.rb
@@ -0,0 +1,18 @@
+class PluginsController < AdminController
+
+ def index
+ @active_plugins = Noosfero::Plugin.all.map {|plugin_name| eval(plugin_name)}.compact
+ end
+
+ post_only :update
+ def update
+ params[:environment][:enabled_plugins].delete('')
+ if @environment.update_attributes(params[:environment])
+ session[:notice] = _('Plugins updated successfully.')
+ else
+ session[:error] = _('Plugins were not updated successfully.')
+ end
+ redirect_to :action => 'index'
+ end
+
+end
diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index 239055e..60e1c5f 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -83,6 +83,7 @@ class ApplicationController < ActionController::Base
include NeedsProfile
before_filter :detect_stuff_by_domain
+ before_filter :init_noosfero_plugins
attr_reader :environment
before_filter :load_terminology
@@ -114,6 +115,10 @@ class ApplicationController < ActionController::Base
end
end
+ def init_noosfero_plugins
+ @plugins = Noosfero::Plugin::Manager.new(self)
+ end
+
def load_terminology
# cache terminology for performance
@@terminology_cache ||= {}
diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb
index fbfb6dd..9ec824b 100644
--- a/app/helpers/profile_helper.rb
+++ b/app/helpers/profile_helper.rb
@@ -15,4 +15,12 @@ module ProfileHelper
end
end
+ def render_tabs(tabs)
+ titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') }
+ contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) }
+
+ content_tag :div, :class => 'ui-tabs' do
+ content_tag(:ul, titles) + contents
+ end
+ end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 34cc7fe..db99dd9 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -220,6 +220,8 @@ class Environment < ActiveRecord::Base
settings_items :trusted_sites_for_iframe, :type => Array, :default => ['itheora.org', 'tv.softwarelivre.org', 'stream.softwarelivre.org']
+ settings_items :enabled_plugins, :type => Array, :default => []
+
def news_amount_by_folder=(amount)
settings[:news_amount_by_folder] = amount.to_i
end
diff --git a/app/views/admin_panel/index.rhtml b/app/views/admin_panel/index.rhtml
index 0f2dba0..813d41a 100644
--- a/app/views/admin_panel/index.rhtml
+++ b/app/views/admin_panel/index.rhtml
@@ -6,6 +6,7 @@
+ <% button_bar do %>
+ <%= submit_button('save', _('Save changes')) %>
+ <%= button :back, _('Back to admin panel'), :controller => 'admin_panel', :action => 'index' %>
+ <% end %>
+
+
+<% end %>
diff --git a/app/views/profile/_organization.rhtml b/app/views/profile/_organization.rhtml
deleted file mode 100644
index ca96d0d..0000000
--- a/app/views/profile/_organization.rhtml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
<%= _("%s's wall") % @profile.name %>
-
- <%= flash[:error] %>
- <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_scraps', :success => "$('leave_scrap_content').value=''" do %>
- <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2 %>
- <%= submit_button :scrap, _('Leave a scrap') %>
- <% end %>
-
-
-
- <%= render :partial => 'profile_scraps', :locals => {:scraps => @wall_items} %>
-
+
<%= _("%s's wall") % @profile.name %>
+
+ <%= flash[:error] %>
+ <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_scraps', :success => "$('leave_scrap_content').value=''" do %>
+ <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2 %>
+ <%= submit_button :scrap, _('Leave a scrap') %>
+ <% end %>
+
+
+ <%= render :partial => 'profile_scraps', :locals => {:scraps => @wall_items} %>
+
diff --git a/app/views/profile/index.rhtml b/app/views/profile/index.rhtml
index 504a5db..3560123 100644
--- a/app/views/profile/index.rhtml
+++ b/app/views/profile/index.rhtml
@@ -13,5 +13,5 @@
<% end %>
- <%= render :partial => partial_for_class(profile.class) %>
+ <%= render :partial => 'profile' %>
diff --git a/app/views/profile_editor/index.rhtml b/app/views/profile_editor/index.rhtml
index 97c73d5..99b4804 100644
--- a/app/views/profile_editor/index.rhtml
+++ b/app/views/profile_editor/index.rhtml
@@ -65,6 +65,11 @@
<% end %>
<%= control_panel_button(_('Manage my groups'), 'groups', :controller => 'memberships') if profile.person? %>
+
+ <% @plugins.map(:control_panel_buttons).each do |button| %>
+ <%= control_panel_button(button[:title], button[:icon], button[:url]) %>
+ <% end %>
+
<% end %>
<% if profile.person? && environment.enabled?('enterprise_activation') %>
diff --git a/config/initializers/plugins.rb b/config/initializers/plugins.rb
new file mode 100644
index 0000000..5348975
--- /dev/null
+++ b/config/initializers/plugins.rb
@@ -0,0 +1,5 @@
+require 'noosfero/plugin'
+require 'noosfero/plugin/manager'
+require 'noosfero/plugin/context'
+require 'noosfero/plugin/active_record'
+Noosfero::Plugin.init_system
diff --git a/config/plugins/mezuro b/config/plugins/mezuro
new file mode 120000
index 0000000..0efaf37
--- /dev/null
+++ b/config/plugins/mezuro
@@ -0,0 +1 @@
+../../plugins/mezuro
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 4621b94..8410e12 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -109,6 +109,12 @@ ActionController::Routing::Routes.draw do |map|
map.system 'system', :controller => 'system'
map.system 'system/:controller/:action/:id', :controller => Noosfero.pattern_for_controllers_in_directory('system')
+ ######################################################
+ # plugin routes
+ ######################################################
+ plugins_routes = File.join(Rails.root + '/lib/noosfero/plugin/routes.rb')
+ eval(IO.read(plugins_routes), binding, plugins_routes)
+
# cache stuff - hack
map.cache 'public/:action/:id', :controller => 'public'
diff --git a/features/plugins.feature b/features/plugins.feature
new file mode 100644
index 0000000..0bbeca8
--- /dev/null
+++ b/features/plugins.feature
@@ -0,0 +1,59 @@
+Feature: plugins
+ As a noosfero\'s developer
+ I want to create hot spots that a plugin should use
+ As a plugins\' developer
+ I want to create plugins that uses noosfero\'s hot spots
+ As an admin of a noosfero environment
+ I want to activate and deactivate some plugins
+ As a user
+ I want to use the features implemented by the plugins
+
+ Background:
+ Given the following users
+ | login | name |
+ | joaosilva | Joao Silva |
+ And I am logged in as "joaosilva"
+ And the following plugin
+ | klass |
+ | TestPlugin |
+ And the following events of TestPlugin
+ | event | body |
+ | control_panel_buttons | lambda { {:title => 'Test plugin button', :icon => '', :url => ''} } |
+ | profile_tabs | lambda { {:title => 'Test plugin tab', :id => 'test_plugin', :content => 'Test plugin random content'} } |
+
+ Scenario: a user must see the plugin\'s button in the control panel if the plugin is enabled
+ Given plugin TestPlugin is enabled on environment
+ And I go to Joao Silva's control panel
+ Then I should see "Test plugin button"
+
+ Scenario: a user must see the plugin\'s tab in in the profile if the plugin is enabled
+ Given plugin TestPlugin is enabled on environment
+ And I am on Joao Silva's profile
+ Then I should see "Test plugin tab"
+
+ Scenario: a user must not see the plugin\'s button in the control panel if the plugin is disabled
+ Given plugin TestPlugin is disabled on environment
+ And I go to Joao Silva's control panel
+ Then I should not see "Test plugin button"
+
+ Scenario: a user must not see the plugin\'s tab in in the profile if the plugin is disabled
+ Given plugin TestPlugin is disabled on environment
+ And I am on Joao Silva's profile
+ Then I should not see "Test plugin tab"
+
+ Scenario: an admin should be able to deactivate a plugin
+ Given plugin TestPlugin is enabled on environment
+ And I am logged in as admin
+ When I go to the Control panel
+ Then I should see "Test plugin button"
+ When I go to the profile
+ Then I should see "Test plugin tab"
+ And I go to the environment control panel
+ And I follow "Enable/disable plugins"
+ And I uncheck "Test plugin"
+ And I press "Save changes"
+ When I go to the Control panel
+ Then I should not see "Test plugin button"
+ When I go to the profile
+ Then I should not see "Test plugin tab"
+
diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb
index f5404f1..35bcb06 100644
--- a/features/step_definitions/noosfero_steps.rb
+++ b/features/step_definitions/noosfero_steps.rb
@@ -146,6 +146,29 @@ Given /^the following certifiers$/ do |table|
end
end
+Given /^the following plugin?$/ do |table|
+ table.hashes.each do |row|
+ row = row.dup
+ klass_name = row.delete('klass')
+ eval("class #{klass_name} < Noosfero::Plugin; end;") unless eval("defined?(#{klass_name})")
+ end
+end
+
+Given /^the following events of (.+)$/ do |plugin,table|
+ klass = eval(plugin)
+ table.hashes.each do |row|
+ row = row.dup
+ event = row.delete('event').to_sym
+ body = eval(row.delete('body'))
+
+ klass.class_eval do
+ define_method(event) do
+ body.call
+ end
+ end
+ end
+end
+
Given /^I am logged in as "(.+)"$/ do |username|
visit('/account/logout')
visit('/account/login')
@@ -184,6 +207,16 @@ Given /^feature "(.+)" is (enabled|disabled) on environment$/ do |feature, statu
e.save
end
+Given /^plugin (.+) is (enabled|disabled) on environment$/ do |plugin, status|
+ e = Environment.default
+ if status == 'enabled'
+ e.enabled_plugins += [plugin]
+ else
+ e.enabled_plugins -= [plugin]
+ end
+ e.save!
+end
+
Given /^organization_approval_method is "(.+)" on environment$/ do |approval_method|
e = Environment.default
e.organization_approval_method = approval_method
diff --git a/features/support/paths.rb b/features/support/paths.rb
index db6acce..99e1eb2 100644
--- a/features/support/paths.rb
+++ b/features/support/paths.rb
@@ -33,6 +33,9 @@ module NavigationHelpers
when /^(.*)'s profile/
'/profile/%s' % Profile.find_by_name($1).identifier
+ when /^the profile$/
+ '/profile/%s' % User.find_by_id(session[:user]).login
+
when /^login page$/
'/account/login'
@@ -45,6 +48,9 @@ module NavigationHelpers
when /^the Control panel$/
'/myprofile/%s' % User.find_by_id(session[:user]).login
+ when /the environment control panel/
+ '/admin'
+
when /^the search page$/
'/search'
diff --git a/lib/noosfero/plugin.rb b/lib/noosfero/plugin.rb
new file mode 100644
index 0000000..5a22246
--- /dev/null
+++ b/lib/noosfero/plugin.rb
@@ -0,0 +1,75 @@
+require 'noosfero'
+class Noosfero::Plugin
+
+ attr_accessor :context
+
+ class << self
+
+ def init_system
+ Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).select do |entry|
+ File.directory?(entry)
+ end.each do |dir|
+ Rails.configuration.controller_paths << File.join(dir, 'controllers')
+ Dependencies.load_paths << File.join(dir, 'controllers')
+ [ Dependencies.load_paths, $:].each do |path|
+ path << File.join(dir, 'models')
+ path << File.join(dir, 'lib')
+ end
+
+ plugin_name = File.basename(dir).camelize + 'Plugin'
+ plugin_name.constantize # load the plugin
+ end
+ end
+
+ def all
+ @all ||= []
+ end
+
+ def inherited(subclass)
+ all << subclass.to_s unless all.include?(subclass.to_s)
+ end
+
+ # Here the developer should specify the meta-informations that the plugin can
+ # inform.
+ def plugin_name
+ self.to_s.underscore.humanize
+ end
+
+ def plugin_description
+ _("No description informed.")
+ end
+
+ end
+
+ def expanded_template(original_path, file_path, locals = {})
+ while(File.basename(File.dirname(original_path)) != 'plugins')
+ original_path = File.dirname(original_path)
+ end
+
+ ERB.new(File.read("#{original_path}/#{file_path}")).result(binding)
+ end
+
+ # Here the developer should specify the events to which the plugins can
+ # register to. Must be explicitly defined its returning
+ # variables.
+
+ # -> Adds buttons to the control panel
+ # returns = { :title => title, :icon => icon, :url => url }
+ # title = name that will be displayed.
+ # icon = css class name (for customized icons include them in a css file).
+ # url = url or route to which the button will redirect.
+ def control_panel_buttons
+ nil
+ end
+
+ # -> Adds tabs to the profile
+ # returns = { :title => title, :id => id, :content => content, :start => start }
+ # title = name that will be displayed.
+ # id = div id.
+ # content = content of the tab (use expanded_template method to import content from another file).
+ # start = boolean that specifies if the tab must come before noosfero tabs (optional).
+ def profile_tabs
+ nil
+ end
+
+end
diff --git a/lib/noosfero/plugin/active_record.rb b/lib/noosfero/plugin/active_record.rb
new file mode 100644
index 0000000..b7aa868
--- /dev/null
+++ b/lib/noosfero/plugin/active_record.rb
@@ -0,0 +1,5 @@
+class Noosfero::Plugin::ActiveRecord < ActiveRecord::Base
+ def self.inherited(child)
+ child.table_name = child.name.gsub('::','_').underscore.pluralize
+ end
+end
diff --git a/lib/noosfero/plugin/context.rb b/lib/noosfero/plugin/context.rb
new file mode 100644
index 0000000..f7c6a76
--- /dev/null
+++ b/lib/noosfero/plugin/context.rb
@@ -0,0 +1,29 @@
+class Noosfero::Plugin::Context
+
+ def initialize(controller)
+ @controller = controller
+ end
+
+ # Here the developer should define the interface to important context
+ # information from the controller to the plugins to access
+ def profile
+ @profile ||= @controller.send(:profile)
+ end
+
+ def request
+ @request ||= @controller.send(:request)
+ end
+
+ def response
+ @response ||= @controller.send(:response)
+ end
+
+ def environment
+ @environment ||= @controller.send(:environment)
+ end
+
+ def params
+ @params ||= @controller.send(:params)
+ end
+
+end
diff --git a/lib/noosfero/plugin/manager.rb b/lib/noosfero/plugin/manager.rb
new file mode 100644
index 0000000..142e460
--- /dev/null
+++ b/lib/noosfero/plugin/manager.rb
@@ -0,0 +1,21 @@
+class Noosfero::Plugin::Manager
+
+ attr_reader :context
+
+ def initialize(controller)
+ @context = Noosfero::Plugin::Context.new(controller)
+ end
+
+ def map(event)
+ enabled_plugins.map { |plugin| plugin.send(event) }.compact.flatten
+ end
+
+ def enabled_plugins
+ @enabled_plugins ||= (Noosfero::Plugin.all & context.environment.enabled_plugins).map do |plugin|
+ p = eval(plugin).new
+ p.context = context
+ p
+ end
+ end
+
+end
diff --git a/lib/noosfero/plugin/routes.rb b/lib/noosfero/plugin/routes.rb
new file mode 100644
index 0000000..b55b627
--- /dev/null
+++ b/lib/noosfero/plugin/routes.rb
@@ -0,0 +1,7 @@
+Dir.glob(File.join(Rails.root, 'config', 'plugins', '*', 'controllers')) do |dir|
+ plugin_name = File.basename(File.dirname(dir))
+ map.connect 'plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_environment'
+ map.connect 'profile/:profile/plugins/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_profile'
+ map.connect 'myprofile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_myprofile'
+end
+
diff --git a/lib/tasks/plugins.rake b/lib/tasks/plugins.rake
new file mode 100644
index 0000000..bc10f23
--- /dev/null
+++ b/lib/tasks/plugins.rake
@@ -0,0 +1,9 @@
+namespace :plugins do
+ task :migrate do
+ Dir.glob(File.join(Rails.root, 'config', 'plugins', '*', 'db', 'migrate')).each do |path|
+ ActiveRecord::Migrator.migrate(path, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
+ end
+ end
+end
+
+task 'db:migrate' => 'plugins:migrate'
diff --git a/plugins/mezuro/README b/plugins/mezuro/README
new file mode 100644
index 0000000..9147b04
--- /dev/null
+++ b/plugins/mezuro/README
@@ -0,0 +1 @@
+This plugin depends on ruby binds for subversion. Checkout http://packages.debian.org/lenny/libsvn-ruby and http://subversion.tigris.org/ for further information.
diff --git a/plugins/mezuro/controllers/mezuro_plugin_myprofile_controller.rb b/plugins/mezuro/controllers/mezuro_plugin_myprofile_controller.rb
new file mode 100644
index 0000000..ac14b52
--- /dev/null
+++ b/plugins/mezuro/controllers/mezuro_plugin_myprofile_controller.rb
@@ -0,0 +1,55 @@
+class MezuroPluginMyprofileController < MyProfileController
+ append_view_path File.join(File.dirname(__FILE__) + '/../views')
+
+ def index
+ @projects = MezuroPlugin::Project.by_profile(profile)
+ end
+
+ def new
+ @project = MezuroPlugin::Project.new
+ end
+
+ def create
+ @project = MezuroPlugin::Project.new(params[:project])
+ if @project.save
+ session[:notice] = _('Project successfully registered')
+ redirect_to :action => 'index'
+ else
+ render :action => 'new'
+ end
+ end
+
+ def edit
+ @project = MezuroPlugin::Project.find(params[:id])
+ end
+
+ def update
+ @project = MezuroPlugin::Project.find(params[:id])
+ if @project.update_attributes(params[:project])
+ session[:notice] = _('Project successfully updated')
+ redirect_to :action => 'index'
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def show
+ @project = MezuroPlugin::Project.find_by_identifier params[:identifier]
+ @total_metrics = @project.total_metrics if @project != nil
+ @statistical_metrics = @project.statistical_metrics if @project != nil
+ @svn_error = @project.svn_error if (@project != nil && @project.svn_error)
+ end
+
+ def destroy
+ @project = MezuroPlugin::Project.by_profile(profile).find(params[:id])
+ if request.post?
+ if @project.destroy
+ session[:notice] = _('Project successfully removed.')
+ else
+ session[:notice] = _('Project was not successfully removed.')
+ end
+ redirect_to :action => 'index'
+ end
+ end
+
+end
diff --git a/plugins/mezuro/db/migrate/20101209151530_create_projects.rb b/plugins/mezuro/db/migrate/20101209151530_create_projects.rb
new file mode 100644
index 0000000..4f1e3aa
--- /dev/null
+++ b/plugins/mezuro/db/migrate/20101209151530_create_projects.rb
@@ -0,0 +1,20 @@
+class CreateProjects < ActiveRecord::Migration
+ def self.up
+ create_table :mezuro_plugin_projects do |t|
+ t.string :name
+ t.string :identifier
+ t.string :personal_webpage
+ t.text :description
+ t.string :repository_url
+ t.string :svn_error
+ t.boolean :with_tab
+ t.references :profile
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :mezuro_plugin_projects
+ end
+end
diff --git a/plugins/mezuro/db/migrate/20101209151640_create_metrics.rb b/plugins/mezuro/db/migrate/20101209151640_create_metrics.rb
new file mode 100644
index 0000000..deeccc7
--- /dev/null
+++ b/plugins/mezuro/db/migrate/20101209151640_create_metrics.rb
@@ -0,0 +1,16 @@
+class CreateMetrics < ActiveRecord::Migration
+ def self.up
+ create_table :mezuro_plugin_metrics do |t|
+ t.string :name
+ t.float :value
+ t.integer :metricable_id
+ t.string :metricable_type
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :mezuro_plugin_metrics
+ end
+end
diff --git a/plugins/mezuro/init.rb b/plugins/mezuro/init.rb
new file mode 100644
index 0000000..64b6709
--- /dev/null
+++ b/plugins/mezuro/init.rb
@@ -0,0 +1 @@
+require "mezuro_plugin"
diff --git a/plugins/mezuro/lib/mezuro_plugin.rb b/plugins/mezuro/lib/mezuro_plugin.rb
new file mode 100644
index 0000000..01d8384
--- /dev/null
+++ b/plugins/mezuro/lib/mezuro_plugin.rb
@@ -0,0 +1,27 @@
+class MezuroPlugin < Noosfero::Plugin
+
+ def self.plugin_name
+ "Mezuro"
+ end
+
+ def self.plugin_description
+ _("A metric analizer plugin.")
+ end
+
+ def control_panel_buttons
+ if context.profile.community?
+ { :title => 'Mezuro projects', :icon => 'mezuro', :url => {:controller => 'mezuro_plugin_myprofile', :action => 'index'} }
+ end
+ end
+
+ def profile_tabs
+ if context.profile.community? && !MezuroPlugin::Project.by_profile(context.profile).blank?
+ MezuroPlugin::Project.by_profile(context.profile).with_tab.map do |project|
+ { :title => 'Mezuro ' + project.name,
+ :id => 'mezuro-project-'+project.identifier,
+ :content => expanded_template(__FILE__,"views/show.html.erb",{:current_project => project}) }
+ end
+ end
+ end
+
+end
diff --git a/plugins/mezuro/lib/mezuro_plugin/analizo_extractor.rb b/plugins/mezuro/lib/mezuro_plugin/analizo_extractor.rb
new file mode 100644
index 0000000..43f1248
--- /dev/null
+++ b/plugins/mezuro/lib/mezuro_plugin/analizo_extractor.rb
@@ -0,0 +1,43 @@
+class MezuroPlugin::AnalizoExtractor < Noosfero::Plugin::ActiveRecord
+ attr_reader :string_output, :hash_output
+
+ def initialize project
+ @project = project
+ end
+
+ def perform
+ run_analizo
+ create_hash
+ save_metrics
+ end
+
+ def run_analizo
+ project_path = "#{RAILS_ROOT}/tmp/#{@project.identifier}"
+ @string_output = `analizo metrics #{project_path}`
+ end
+
+ def create_hash
+ @hash_output = {}
+ first_line = true
+
+ @string_output.lines.each do |line|
+ if line =~ /---/
+ if first_line
+ first_line = false
+ else
+ break
+ end
+ end
+
+ if line =~ /(\S+): (~|(\d+)(\.\d+)?).*/
+ @hash_output[$1.to_sym] = $2
+ end
+ end
+ end
+
+ def save_metrics
+ @hash_output.each do | key, value |
+ MezuroPlugin::Metric.create(:name => key.to_s, :value => value.to_f, :metricable => @project)
+ end
+ end
+end
diff --git a/plugins/mezuro/lib/mezuro_plugin/calculate_metrics_job.rb b/plugins/mezuro/lib/mezuro_plugin/calculate_metrics_job.rb
new file mode 100644
index 0000000..cb671b3
--- /dev/null
+++ b/plugins/mezuro/lib/mezuro_plugin/calculate_metrics_job.rb
@@ -0,0 +1,7 @@
+class MezuroPlugin::CalculateMetricsJob < Struct.new(:project_id)
+ def perform
+ project = MezuroPlugin::Project.find project_id
+ project.calculate_metrics
+ end
+end
+
diff --git a/plugins/mezuro/lib/mezuro_plugin/metric.rb b/plugins/mezuro/lib/mezuro_plugin/metric.rb
new file mode 100644
index 0000000..f80f877
--- /dev/null
+++ b/plugins/mezuro/lib/mezuro_plugin/metric.rb
@@ -0,0 +1,19 @@
+class MezuroPlugin::Metric < Noosfero::Plugin::ActiveRecord
+ validates_presence_of :name, :metricable_id, :metricable_type
+
+ belongs_to :metricable, :polymorphic => true
+ before_save :round_value
+
+ def initialize params
+ params[:value] = nil if params[:value] == '~'
+ super params
+ end
+
+ def round_value
+ if self.value
+ multiplied = self.value * 100
+ rounded = multiplied.round
+ self.value = rounded / 100.0
+ end
+ end
+end
diff --git a/plugins/mezuro/lib/mezuro_plugin/project.rb b/plugins/mezuro/lib/mezuro_plugin/project.rb
new file mode 100644
index 0000000..8d96da9
--- /dev/null
+++ b/plugins/mezuro/lib/mezuro_plugin/project.rb
@@ -0,0 +1,74 @@
+class MezuroPlugin::Project < Noosfero::Plugin::ActiveRecord
+ has_many :metrics, :as => :metricable
+
+ validates_presence_of :name, :repository_url, :identifier
+ validates_format_of :identifier, :with => /^[a-z0-9|\-|\.]*$/, :message => "Identifier can only have a combination of lower case, number, hyphen and dot!"
+ validates_uniqueness_of :identifier
+
+ named_scope :with_tab, :conditions => {:with_tab => true}
+ named_scope :by_profile, lambda {|profile| {:conditions => {:profile_id => profile.id}}}
+
+
+ after_create :asynchronous_calculate_metrics
+
+ def calculate_metrics
+ begin
+ download_source_code
+ extractor = MezuroPlugin::AnalizoExtractor.new self
+ extractor.perform
+ rescue Svn::Error => error
+ update_attribute :svn_error, error.error_message
+ end
+ end
+
+ def asynchronous_calculate_metrics
+ Delayed::Job.enqueue MezuroPlugin::CalculateMetricsJob.new(id)
+ end
+
+ def download_source_code
+ download_prepare
+ Svn::Client::Context.new.checkout(repository_url, "#{RAILS_ROOT}/tmp/#{identifier}")
+ end
+
+ def download_prepare
+ project_path = "#{RAILS_ROOT}/tmp/#{identifier}"
+ FileUtils.rm_r project_path if (File.exists? project_path)
+ end
+
+ def metrics_calculated?
+ return !metrics.empty?
+ end
+
+ def total_metrics
+ total_metrics = metrics.select do |metric|
+ metric.name.start_with?("total")
+ end
+ return total_metrics.sort_by {|metric| metric.name}
+ end
+
+ def statistical_metrics
+ statistical_metrics = collect_statistical_metrics
+
+ hash = {}
+ statistical_metrics.each do |metric|
+ insert_metric_in_hash metric, hash
+ end
+ hash
+ end
+
+ def collect_statistical_metrics
+ statistical_metrics = metrics.select do |metric|
+ not metric.name.start_with?("total")
+ end
+ statistical_metrics.sort_by {|metric| metric.name}
+ end
+
+ def insert_metric_in_hash metric, hash
+ metric_name, metric_statistic = metric.name.split("_")
+ unless hash.key?(metric_name)
+ hash[metric_name] = {metric_statistic => metric.value}
+ else
+ hash[metric_name][metric_statistic] = metric.value
+ end
+ end
+end
diff --git a/plugins/mezuro/lib/tasks/cucumber.rake b/plugins/mezuro/lib/tasks/cucumber.rake
new file mode 100644
index 0000000..e0bc4ab
--- /dev/null
+++ b/plugins/mezuro/lib/tasks/cucumber.rake
@@ -0,0 +1,47 @@
+# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
+# It is recommended to regenerate this file in the future when you upgrade to a
+# newer version of cucumber-rails. Consider adding your own code to a new file
+# instead of editing this one. Cucumber will automatically load all features/**/*.rb
+# files.
+
+
+unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
+
+vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
+$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
+
+begin
+ require 'cucumber/rake/task'
+
+ namespace :cucumber do
+ Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
+ t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'default'
+ end
+
+ Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
+ t.binary = vendored_cucumber_bin
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'wip'
+ end
+
+ desc 'Run all features'
+ task :all => [:ok, :wip]
+ end
+ desc 'Alias for cucumber:ok'
+ task :cucumber => 'cucumber:ok'
+
+ task :default => :cucumber
+
+ task :features => :cucumber do
+ STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
+ end
+rescue LoadError
+ desc 'cucumber rake task not available (cucumber not installed)'
+ task :cucumber do
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
+ end
+end
+
+end
diff --git a/plugins/mezuro/lib/tasks/rspec.rake b/plugins/mezuro/lib/tasks/rspec.rake
new file mode 100644
index 0000000..dba3ffc
--- /dev/null
+++ b/plugins/mezuro/lib/tasks/rspec.rake
@@ -0,0 +1,144 @@
+gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9
+rspec_gem_dir = nil
+Dir["#{RAILS_ROOT}/vendor/gems/*"].each do |subdir|
+ rspec_gem_dir = subdir if subdir.gsub("#{RAILS_ROOT}/vendor/gems/","") =~ /^(\w+-)?rspec-(\d+)/ && File.exist?("#{subdir}/lib/spec/rake/spectask.rb")
+end
+rspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec')
+
+if rspec_gem_dir && (test ?d, rspec_plugin_dir)
+ raise "\n#{'*'*50}\nYou have rspec installed in both vendor/gems and vendor/plugins\nPlease pick one and dispose of the other.\n#{'*'*50}\n\n"
+end
+
+if rspec_gem_dir
+ $LOAD_PATH.unshift("#{rspec_gem_dir}/lib")
+elsif File.exist?(rspec_plugin_dir)
+ $LOAD_PATH.unshift("#{rspec_plugin_dir}/lib")
+end
+
+# Don't load rspec if running "rake gems:*"
+unless ARGV.any? {|a| a =~ /^gems/}
+
+begin
+ require 'spec/rake/spectask'
+rescue MissingSourceFile
+ module Spec
+ module Rake
+ class SpecTask
+ def initialize(name)
+ task name do
+ # if rspec-rails is a configured gem, this will output helpful material and exit ...
+ require File.expand_path(File.join(File.dirname(__FILE__),"..","..","config","environment"))
+
+ # ... otherwise, do this:
+ raise <<-MSG
+
+#{"*" * 80}
+* You are trying to run an rspec rake task defined in
+* #{__FILE__},
+* but rspec can not be found in vendor/gems, vendor/plugins or system gems.
+#{"*" * 80}
+MSG
+ end
+ end
+ end
+ end
+ end
+end
+
+Rake.application.instance_variable_get('@tasks').delete('default')
+
+spec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? "db:test:prepare" : :noop
+task :noop do
+end
+
+task :default => :spec
+task :stats => "spec:statsetup"
+
+desc "Run all specs in spec directory (excluding plugin specs)"
+Spec::Rake::SpecTask.new(:spec => spec_prereq) do |t|
+ t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end
+
+namespace :spec do
+ desc "Run all specs in spec directory with RCov (excluding plugin specs)"
+ Spec::Rake::SpecTask.new(:rcov) do |t|
+ t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.rcov = true
+ t.rcov_opts = lambda do
+ IO.readlines("#{RAILS_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
+ end
+ end
+
+ desc "Print Specdoc for all specs (excluding plugin specs)"
+ Spec::Rake::SpecTask.new(:doc) do |t|
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ end
+
+ desc "Print Specdoc for all plugin examples"
+ Spec::Rake::SpecTask.new(:plugin_doc) do |t|
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
+ t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*')
+ end
+
+ [:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|
+ desc "Run the code examples in spec/#{sub}"
+ Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|
+ t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
+ end
+ end
+
+ desc "Run the code examples in vendor/plugins (except RSpec's own)"
+ Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t|
+ t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
+ t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude("vendor/plugins/rspec-rails/*")
+ end
+
+ namespace :plugins do
+ desc "Runs the examples for rspec_on_rails"
+ Spec::Rake::SpecTask.new(:rspec_on_rails) do |t|
+ t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
+ t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb']
+ end
+ end
+
+ # Setup specs for stats
+ task :statsetup do
+ require 'code_statistics'
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models')
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views')
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers')
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers')
+ ::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib')
+ ::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing')
+ ::STATS_DIRECTORIES << %w(Integration\ specs spec/integration) if File.exist?('spec/integration')
+ ::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models')
+ ::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views')
+ ::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers')
+ ::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers')
+ ::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib')
+ ::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing')
+ ::CodeStatistics::TEST_TYPES << "Integration specs" if File.exist?('spec/integration')
+ end
+
+ namespace :db do
+ namespace :fixtures do
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z."
+ task :load => :environment do
+ ActiveRecord::Base.establish_connection(Rails.env)
+ base_dir = File.join(Rails.root, 'spec', 'fixtures')
+ fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
+
+ require 'active_record/fixtures'
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|
+ Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
+ end
+ end
+ end
+ end
+end
+
+end
diff --git a/plugins/mezuro/public/images/mezuro.gif b/plugins/mezuro/public/images/mezuro.gif
new file mode 100644
index 0000000..4e841f1
Binary files /dev/null and b/plugins/mezuro/public/images/mezuro.gif differ
diff --git a/plugins/mezuro/public/images/mezuro.png b/plugins/mezuro/public/images/mezuro.png
new file mode 100644
index 0000000..49aaeac
Binary files /dev/null and b/plugins/mezuro/public/images/mezuro.png differ
diff --git a/plugins/mezuro/public/images/minus.png b/plugins/mezuro/public/images/minus.png
new file mode 100644
index 0000000..6b8361e
Binary files /dev/null and b/plugins/mezuro/public/images/minus.png differ
diff --git a/plugins/mezuro/public/images/plus.png b/plugins/mezuro/public/images/plus.png
new file mode 100644
index 0000000..c541e6e
Binary files /dev/null and b/plugins/mezuro/public/images/plus.png differ
diff --git a/plugins/mezuro/public/stylesheets/base_layout.css b/plugins/mezuro/public/stylesheets/base_layout.css
new file mode 100644
index 0000000..947ac92
--- /dev/null
+++ b/plugins/mezuro/public/stylesheets/base_layout.css
@@ -0,0 +1,2 @@
+.controller-profile_editor a.control-panel-mezuro {background-image: url(../images/control-panel/mezuro.png)}
+.controller-profile_editor .msie6 a.control-panel-edit-location {background-image: url(../images/control-panel/mezuro.gif)}
diff --git a/plugins/mezuro/views/mezuro_plugin_myprofile/_form.html.erb b/plugins/mezuro/views/mezuro_plugin_myprofile/_form.html.erb
new file mode 100644
index 0000000..47c861e
--- /dev/null
+++ b/plugins/mezuro/views/mezuro_plugin_myprofile/_form.html.erb
@@ -0,0 +1,20 @@
+<%= error_messages_for 'project' %>
+
+<% labelled_form_for :project, @project, :url => @url do |f| %>
+ <%= hidden_field_tag 'project[profile_id]', profile.id %>
+ <%= hidden_field_tag 'id', @project.id %>
+
+ <%= required_fields_message %>
+
+ <%= required f.text_field(:name) %>
+ <%= required f.text_field(:repository_url) %>
+ <%= required f.text_field(:identifier) %>
+ <%= f.check_box(:with_tab) %>
+ <%= f.text_area(:description, :size => '30x3') %>
+
+ <% button_bar do %>
+ <%= submit_button(:save, @submit_button, :cancel => {:action => 'index'})%>
+ <% end %>
+<% end %>
+
+<%= javascript_tag "$('project_name').focus();" %>
diff --git a/plugins/mezuro/views/mezuro_plugin_myprofile/edit.html.erb b/plugins/mezuro/views/mezuro_plugin_myprofile/edit.html.erb
new file mode 100644
index 0000000..0b218e1
--- /dev/null
+++ b/plugins/mezuro/views/mezuro_plugin_myprofile/edit.html.erb
@@ -0,0 +1,4 @@
+
<%= _("Edit project") %>
+<% @url = {:action => 'update'} %>
+<% @submit_button = _("Update project") %>
+<%= render :partial => 'form' %>
diff --git a/plugins/mezuro/views/mezuro_plugin_myprofile/index.html.erb b/plugins/mezuro/views/mezuro_plugin_myprofile/index.html.erb
new file mode 100644
index 0000000..a3f15ef
--- /dev/null
+++ b/plugins/mezuro/views/mezuro_plugin_myprofile/index.html.erb
@@ -0,0 +1,28 @@
+
<%= _("%s's Mezuro projects") % profile.name %>
+
+<% if @projects.blank? %>
+ <%= _("%s has no projects registered.") % profile.name %>
+<% else %>
+
+
+ <%= _('Project') %> |
+ <%= _('Actions') %> |
+
+
+ <% @projects.each do |project| %>
+
+ <%= project.name %> |
+
+ <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => project.id %>
+ <%= button_without_text :delete, _('Delete'), { :action => 'destroy', :id => project.id },
+ :method => :post,
+ :confirm => _("Are you sure you want to remove this project?") %>
+ |
+
+ <% end %>
+
+<% end %>
+
+<% button_bar do %>
+ <%= button :new, _('Register a new project'), :action => 'new' %>
+<% end %>
diff --git a/plugins/mezuro/views/mezuro_plugin_myprofile/new.html.erb b/plugins/mezuro/views/mezuro_plugin_myprofile/new.html.erb
new file mode 100644
index 0000000..c451406
--- /dev/null
+++ b/plugins/mezuro/views/mezuro_plugin_myprofile/new.html.erb
@@ -0,0 +1,4 @@
+
<%= _("New project") %>
+<% @url = {:action => 'create'} %>
+<% @submit_button = _("Register project") %>
+<%= render :partial => 'form' %>
diff --git a/plugins/mezuro/views/show.html.erb b/plugins/mezuro/views/show.html.erb
new file mode 100644
index 0000000..fec090e
--- /dev/null
+++ b/plugins/mezuro/views/show.html.erb
@@ -0,0 +1,81 @@
+<% @project = locals[:current_project] %>
+<% @total_metrics = @project.total_metrics if @project != nil %>
+<% @statistical_metrics = @project.statistical_metrics if @project != nil %>
+<% @svn_error = @project.svn_error if (@project != nil && @project.svn_error) %>
+
+
<%= @project.name %>'s Info
+
+
+ <%= _("Name") %> |
+ <%= @project.name %> |
+
+ <% if (@project.description != nil && @project.description != "" ) %>
+
+ <%= _("Description") %> |
+ <%= @project.description %> |
+
+ <% end %>
+
+ <%= _("Repository address") %> |
+ <%= @project.repository_url %> |
+
+
+
+
+
+
+<% if @svn_error %>
+
ERROR
+
+ <%= @svn_error %>
+
+
+
+
+ <%= _("Possible causes:") %>
+
+ -
+ <%= _("Server is down") %>
+
+ -
+ <% _("URL invalid, in this case create another project with the correct URL
+ (Sorry for the incovenience, we're working for a better solution)") %>
+
+
+
+<%else%>
+
<%= _("Metric Results") %>
+ <% if @project.metrics_calculated? %>
+
<% _("Total Metrics") %>
+
+ <% @total_metrics.each_with_index do |metric, index| %>
+
+ <%= metric.name %> |
+ <%= metric.value %> |
+
+ <% end %>
+
+
+
<%= _("Statistical Metrics") %>
+ <% @statistical_metrics.each_key do |metric_name| %>
+
+ <%= "#{metric_name}_average: #{@statistical_metrics[metric_name]["average"]}" %>
+
+ <% @statistical_metrics[metric_name].each do |stat_name, stat_value| %>
+ <% if stat_name != "average" %>
+ -
+ <%= "#{metric_name}_#{stat_name}: #{stat_value}" %>
+
+ <% end %>
+ <% end %>
+
+
+ <% end %>
+
+ <% else %>
+
+ <%= _("Wait a moment while the metrics are calculated.
+ Reload the page manually in a few moment. ") %>
+
+ <% end %>
+<% end %>
diff --git a/test/functional/plugins_controller_test.rb b/test/functional/plugins_controller_test.rb
new file mode 100644
index 0000000..40b3d62
--- /dev/null
+++ b/test/functional/plugins_controller_test.rb
@@ -0,0 +1,68 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'plugins_controller'
+
+# Re-raise errors caught by the controller.
+class PluginsController; def rescue_action(e) raise e end; end
+
+class PluginsControllerTest < Test::Unit::TestCase
+
+ all_fixtures
+ def setup
+ @controller = PluginsController.new
+ @request = ActionController::TestRequest.new
+ @request.stubs(:ssl?).returns(true)
+ @response = ActionController::TestResponse.new
+ @environment = Environment.default
+ login_as(create_admin_user(@environment))
+ end
+ attr_reader :environment
+
+ def test_local_files_reference
+ assert_local_files_reference
+ end
+
+ def test_valid_xhtml
+ assert_valid_xhtml
+ end
+
+ should 'list system active plugins' do
+ class Plugin1 < Noosfero::Plugin
+ class << self
+ def plugin_name
+ "Plugin1"
+ end
+ def plugin_description
+ "This plugin is from hell!"
+ end
+ end
+ end
+
+ class Plugin2 < Noosfero::Plugin
+ class << self
+ def plugin_name
+ "Plugin2"
+ end
+ def plugin_description
+ "This plugin is from heaven!"
+ end
+ end
+ end
+
+ Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s,Plugin2.to_s])
+
+ get :index
+
+ assert_tag :tag => 'td', :content => /#{Plugin1.plugin_name}/
+ assert_tag :tag => 'td', :content => /#{Plugin1.plugin_description}/
+ assert_tag :tag => 'td', :content => /#{Plugin2.plugin_name}/
+ assert_tag :tag => 'td', :content => /#{Plugin2.plugin_description}/
+ end
+
+ should 'enable or disable plugins' do
+ assert_not_equal ['Plugin1'], environment.enabled_plugins
+ post :update, :environment => { :enabled_plugins => ['Plugin1']}
+ environment.reload
+ assert_equal ['Plugin1'], environment.enabled_plugins
+ end
+
+end
diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb
index 4ef1861..e287bbe 100644
--- a/test/functional/profile_controller_test.rb
+++ b/test/functional/profile_controller_test.rb
@@ -1113,4 +1113,18 @@ class ProfileControllerTest < Test::Unit::TestCase
assert_equal '', @response.body
end
+ should 'display plugins tabs' do
+ plugin1_tab = {:title => 'Plugin1 tab', :id => 'plugin1_tab', :content => 'Content from plugin1.'}
+ plugin2_tab = {:title => 'Plugin2 tab', :id => 'plugin2_tab', :content => 'Content from plugin2.'}
+ tabs = [plugin1_tab, plugin2_tab]
+ plugins = mock()
+ plugins.stubs(:map).with(:profile_tabs).returns(tabs)
+ Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
+
+ get :index, :profile => profile.identifier
+
+ assert_tag :tag => 'a', :content => /#{plugin1_tab[:title]}/, :attributes => {:href => /#{plugin1_tab[:id]}/}
+ assert_tag :tag => 'div', :content => /#{plugin1_tab[:content]}/, :attributes => {:id => /#{plugin1_tab[:id]}/}
+ end
+
end
diff --git a/test/functional/profile_editor_controller_test.rb b/test/functional/profile_editor_controller_test.rb
index f936fef..9cbfdf1 100644
--- a/test/functional/profile_editor_controller_test.rb
+++ b/test/functional/profile_editor_controller_test.rb
@@ -858,4 +858,18 @@ class ProfileEditorControllerTest < Test::Unit::TestCase
end
end
+ should 'display plugins buttons on the control panel' do
+ plugin1_button = {:title => "Plugin1 button", :icon => 'plugin1_icon', :url => 'plugin1_url'}
+ plugin2_button = {:title => "Plugin2 button", :icon => 'plugin2_icon', :url => 'plugin2_url'}
+ buttons = [plugin1_button, plugin2_button]
+ plugins = mock()
+ plugins.stubs(:map).with(:control_panel_buttons).returns(buttons)
+ Noosfero::Plugin::Manager.stubs(:new).returns(plugins)
+
+ get :index, :profile => profile.identifier
+
+ assert_tag :tag => 'a', :content => plugin1_button[:title], :attributes => {:class => /#{plugin1_button[:icon]}/, :href => /#{plugin1_button[:url]}/}
+ assert_tag :tag => 'a', :content => plugin2_button[:title], :attributes => {:class => /#{plugin2_button[:icon]}/, :href => /#{plugin2_button[:url]}/}
+ end
+
end
diff --git a/test/unit/manager_test.rb b/test/unit/manager_test.rb
new file mode 100644
index 0000000..eb8ef6d
--- /dev/null
+++ b/test/unit/manager_test.rb
@@ -0,0 +1,58 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ManagerTest < Test::Unit::TestCase
+
+ def setup
+ @environment = Environment.default
+ @controller = mock()
+ @controller.stubs(:profile).returns()
+ @controller.stubs(:request).returns()
+ @controller.stubs(:response).returns()
+ @controller.stubs(:environment).returns(@environment)
+ @controller.stubs(:params).returns()
+ @manager = Noosfero::Plugin::Manager.new(@controller)
+ end
+ attr_reader :environment
+ attr_reader :manager
+
+ should 'return the intersection between environment\'s enabled plugins and system available plugins' do
+ class Plugin1 < Noosfero::Plugin; end;
+ class Plugin2 < Noosfero::Plugin; end;
+ class Plugin3 < Noosfero::Plugin; end;
+ class Plugin4 < Noosfero::Plugin; end;
+ environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s])
+ Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s])
+ plugins = manager.enabled_plugins.map { |instance| instance.class.to_s }
+ assert_equal [Plugin1.to_s, Plugin4.to_s], plugins
+ end
+
+ should 'map events to registered plugins' do
+
+ class Noosfero::Plugin
+ def random_event
+ nil
+ end
+ end
+
+ class Plugin1 < Noosfero::Plugin
+ def random_event
+ 'Plugin 1 action.'
+ end
+ end
+
+ class Plugin2 < Noosfero::Plugin
+ def random_event
+ 'Plugin 2 action.'
+ end
+ end
+
+ environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s])
+
+ p1 = Plugin1.new
+ p2 = Plugin2.new
+
+ assert_equal [p1.random_event, p2.random_event], manager.map(:random_event)
+ end
+
+end
+
diff --git a/test/unit/plugin_test.rb b/test/unit/plugin_test.rb
new file mode 100644
index 0000000..cd4fcf6
--- /dev/null
+++ b/test/unit/plugin_test.rb
@@ -0,0 +1,23 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class PluginTest < Test::Unit::TestCase
+
+ def setup
+ @environment = Environment.default
+ end
+ attr_reader :environment
+
+ should 'keep the list of all loaded subclasses' do
+ class Plugin1 < Noosfero::Plugin
+ end
+
+ class Plugin2 < Noosfero::Plugin
+ end
+
+ assert_includes Noosfero::Plugin.all, Plugin1.to_s
+ assert_includes Noosfero::Plugin.all, Plugin1.to_s
+ end
+
+end
+
+
--
libgit2 0.21.2