aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server/src/main/webapp/WEB-INF
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-server/src/main/webapp/WEB-INF')
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb17
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb154
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb28
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb6
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/profile.rb147
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/project.rb5
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/property.rb16
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_copy_form.html.erb14
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_rename_form.html.erb6
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb9
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/profiles/projects.html.erb115
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/project/profile.html.erb40
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/project/quality_profile.html.erb23
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/db/migrate/331_remove_projects_profile_id.rb45
16 files changed, 408 insertions, 225 deletions
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb
index 8636de40e54..e125aaefe2d 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb
@@ -125,6 +125,23 @@ class ApplicationController < ActionController::Base
raise Errors::AccessDenied
end
+ # since 3.3
+ def require_parameters(*keys)
+ keys.each do |key|
+ bad_request("Missing parameter: #{key}") if params[key].blank?
+ end
+ end
+
+ # since 3.3
+ def verify_post_request
+ bad_request('Not a POST request') unless request.post?
+ end
+
+ # since 3.3
+ def verify_ajax_request
+ bad_request('Not an AJAX request') unless request.xhr?
+ end
+
def render_not_found(error)
render :file => "#{Rails.public_path}/404.html", :status => 404
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
index d380dbff837..50fbf55c26f 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
@@ -20,38 +20,37 @@
class ProfilesController < ApplicationController
SECTION=Navigation::SECTION_CONFIGURATION
- # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
- verify :method => :post, :only => ['create', 'delete', 'copy', 'set_as_default', 'restore', 'set_projects', 'rename', 'change_parent'], :redirect_to => {:action => 'index'}
-
# the backup action is allow to non-admin users : see http://jira.codehaus.org/browse/SONAR-2039
before_filter :admin_required, :only => ['create', 'delete', 'set_as_default', 'copy', 'restore', 'change_parent', 'set_projects', 'rename_form', 'rename']
# GET /profiles/index
def index
- @profiles = Profile.find(:all, :conditions => ['enabled=?', true], :order => 'name')
+ @profiles = Profile.find(:all, :order => 'name')
end
# GET /profiles/show/<id>
def show
+ require_parameters 'id'
@profile = Profile.find(params[:id])
end
# GET /profiles/create_form?language=<language>
def create_form
- language = params[:language]
- bad_request 'Missing parameter: language' if language.blank?
- profile = Profile.new(:language => language)
- render :partial => 'profiles/create_form', :locals => {:language_key => language}
+ require_parameters 'language'
+ render :partial => 'profiles/create_form', :locals => {:language_key => params[:language]}
end
# POST /profiles/create?name=<profile name>&language=<language>&[backup=<file>]
def create
+ verify_post_request
+ require_parameters 'language'
+
profile_name=params[:name]
language=params[:language]
- profile = Profile.create(:name => profile_name, :language => language, :default_profile => false, :enabled => true)
+ profile = Profile.create(:name => profile_name, :language => language, :default_profile => false)
ok = profile.errors.empty?
if ok && params[:backup]
params[:backup].each_pair do |importer_key, file|
@@ -75,9 +74,12 @@ class ProfilesController < ApplicationController
# POST /profiles/delete/<id>
def delete
+ verify_post_request
+ require_parameters 'id'
+
@profile = Profile.find(params[:id])
if @profile && @profile.deletable?
- java_facade.deleteProfile(@profile.id)
+ @profile.destroy
end
redirect_to(:controller => 'profiles', :action => 'index')
end
@@ -85,40 +87,50 @@ class ProfilesController < ApplicationController
# POST /profiles/set_as_default/<id>
def set_as_default
+ verify_post_request
+ require_parameters 'id'
+
profile = Profile.find(params[:id])
profile.set_as_default
- flash[:notice]=message('quality_profiles.default_profile_is_x', :params => profile.name)
+ #TODO remove l10n key: flash[:notice]=message('quality_profiles.default_profile_is_x', :params => profile.name)
redirect_to :action => 'index'
end
# GET /profiles/copy_form/<profile id>
def copy_form
+ require_parameters 'id'
@profile = Profile.find(params[:id])
render :partial => 'profiles/copy_form'
end
# POST /profiles/copy/<id>?name=<name of new profile>
def copy
- render :text => 'Not an ajax request', :status => '400' unless request.xhr?
+ verify_post_request
+ verify_ajax_request
+ require_parameters 'id'
@profile = Profile.find(params[:id])
name = params['name']
- validation_errors = @profile.validate_copy(name)
- if validation_errors.empty?
+ target_profile=Profile.new(:name => name, :language => @profile.language, :provided => false, :default_profile => false)
+ if target_profile.valid?
java_facade.copyProfile(@profile.id, name)
flash[:notice]= message('quality_profiles.profile_x_not_activated', :params => name)
render :text => 'ok', :status => 200
else
- @error = validation_errors.full_messages.first
+ @errors = []
+ target_profile.errors.each{|attr,msg| @errors<<msg}
render :partial => 'profiles/copy_form', :status => 400
end
end
- # POST /profiles/backup/<id>
+ # POST /profiles/backup?id=<profile id>
def backup
+ verify_post_request
+ require_parameters 'id'
+
profile = Profile.find(params[:id])
xml = java_facade.backupProfile(profile.id)
filename=profile.name.gsub(' ', '_')
@@ -129,11 +141,13 @@ class ProfilesController < ApplicationController
# Modal window to restore profile backup
# GET /profiles/restore_form/<profile id>
def restore_form
+ verify_ajax_request
render :partial => 'profiles/restore_form'
end
# POST /profiles/restore?backup=<file>
def restore
+ verify_post_request
if params[:backup].blank?
flash[:warning]=message('quality_profiles.please_upload_backup_file')
else
@@ -148,7 +162,7 @@ class ProfilesController < ApplicationController
def export
language = params[:language]
if (params[:name].blank?)
- profile = Profile.find_active_profile_by_language(language)
+ profile = Profile.by_default(language)
else
profile = Profile.find_by_name_and_language(CGI::unescape(params[:name]), language)
end
@@ -165,24 +179,18 @@ class ProfilesController < ApplicationController
end
end
- #
- #
# GET /profiles/inheritance?id=<profile id>
- #
- #
def inheritance
+ require_parameters 'id'
@profile = Profile.find(params[:id])
- profiles=Profile.find(:all, :conditions => ['language=? and id<>? and (parent_name is null or parent_name<>?) and enabled=?', @profile.language, @profile.id, @profile.name, true], :order => 'name')
+ profiles=Profile.find(:all, :conditions => ['language=? and id<>? and (parent_name is null or parent_name<>?)', @profile.language, @profile.id, @profile.name], :order => 'name')
@select_parent = [[message('none'), nil]] + profiles.collect { |profile| [profile.name, profile.name] }
end
- #
- #
# GET /profiles/changelog?id=<profile id>
- #
- #
def changelog
+ require_parameters 'id'
@profile = Profile.find(params[:id])
versions = ActiveRuleChange.find(:all, :select => 'profile_version, MAX(change_date) AS change_date', :conditions => ['profile_id=?', @profile.id], :group => 'profile_version')
@@ -210,12 +218,11 @@ class ProfilesController < ApplicationController
end
- #
- #
# POST /profiles/change_parent?id=<profile id>&parent_name=<parent profile name>
- #
- #
def change_parent
+ verify_post_request
+ require_parameters 'id'
+
id = params[:id].to_i
parent_name = params[:parent_name]
if parent_name.blank?
@@ -234,6 +241,7 @@ class ProfilesController < ApplicationController
#
#
def permalinks
+ require_parameters 'id'
@profile = Profile.find(params[:id])
end
@@ -244,62 +252,68 @@ class ProfilesController < ApplicationController
#
#
def projects
+ require_parameters 'id'
@profile = Profile.find(params[:id])
- @available_projects=Project.find(:all,
- :include => ['profile', 'snapshots'],
- :conditions => ['projects.qualifier=? AND projects.scope=? AND snapshots.islast=?', Project::QUALIFIER_PROJECT, Project::SCOPE_SET, true],
- :order => 'projects.name asc')
- @available_projects-=@profile.projects
end
- #
- #
- # POST /profiles/set_projects/<id>?projects=<project ids>
- #
- #
- def set_projects
- @profile = Profile.find(params[:id])
- @profile.projects.clear
+ # POST /profiles/add_project?id=<profile id>&project_id=<project id>
+ def add_project
+ verify_post_request
+ require_parameters 'id', 'project_id'
+ admin_required
+
+ profile=Profile.find(params[:id])
+ bad_request('Unknown profile') unless profile
+ project=Project.find(params[:project_id])
+ bad_request('Unknown project') unless project
- projects=Project.find(params[:projects] || [])
- @profile.projects=projects
- flash[:notice]=message('quality_profiles.profile_x_associated_to_x_projects', :params => [@profile.name, projects.size])
- redirect_to :action => 'projects', :id => @profile.id
+ profile.add_project_id(project.id)
+ redirect_to :action => 'projects', :id => profile.id
end
+ # POST /profiles/remove_project?id=<profile id>&project_id=<project id>
+ def remove_project
+ verify_post_request
+ require_parameters 'id', 'project_id'
+ admin_required
+
+ profile=Profile.find(params[:id])
+ bad_request('Unknown profile') unless profile
+
+ Profile.reset_default_profile_for_project_id(profile.language, params[:project_id])
+ redirect_to :action => 'projects', :id => profile.id
+ end
+
+ # POST /profiles/remove_projects?id=<profile id>
+ def remove_projects
+ verify_post_request
+ require_parameters 'id'
+ admin_required
+
+ profile=Profile.find(params[:id])
+ bad_request('Unknown profile') unless profile
+
+ profile.remove_projects
+ redirect_to :action => 'projects', :id => profile.id
+ end
# GET /profiles/rename_form?id=<id>
def rename_form
+ require_parameters 'id'
@profile = Profile.find(params[:id])
render :partial => 'profiles/rename_form'
end
- #
- #
# POST /profiles/rename?id=<id>&name=<new name>
- #
- #
def rename
- render :text => 'Not an ajax request', :status => '400' unless request.xhr?
+ verify_post_request
+ verify_ajax_request
+ require_parameters 'id'
@profile = Profile.find(params[:id])
- name = params[:name]
- success=false
- if name.blank?
- @error=message('quality_profiles.profile_name_cant_be_blank')
- else
- existing=Profile.find(:first, :conditions => {:name => name, :language => @profile.language, :enabled => true})
- if existing
- @error=message('quality_profiles.already_exists')
- elsif !@profile.provided?
- java_facade.renameProfile(@profile.id, name)
- success=true
- end
- end
-
- if success
+ if @profile.rename(params[:name]).errors.empty?
render :text => 'ok', :status => 200
else
render :partial => 'profiles/rename_form', :status => 400
@@ -307,13 +321,9 @@ class ProfilesController < ApplicationController
end
- #
- #
# GET /profiles/compare?id1=<profile1 id>&id2=<profile2 id>
- #
- #
def compare
- @profiles = Profile.find(:all, :conditions => ['enabled=?', true], :order => 'language asc, name')
+ @profiles = Profile.find(:all, :order => 'language asc, name')
if params[:id1].present? && params[:id2].present?
@profile1 = Profile.find(params[:id1])
@profile2 = Profile.find(params[:id2])
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
index a993d5331ec..5e59296c6e3 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
#
class ProjectController < ApplicationController
- verify :method => :post, :only => [:set_links, :set_exclusions, :delete_exclusions, :update_key, :perform_key_bulk_update, :update_quality_profile],
+ verify :method => :post, :only => [:set_links, :set_exclusions, :delete_exclusions, :update_key, :perform_key_bulk_update],
:redirect_to => {:action => :index}
verify :method => :delete, :only => [:delete], :redirect_to => {:action => :index}
@@ -75,25 +75,29 @@ class ProjectController < ApplicationController
redirect_to :action => 'deletion', :id => params[:id]
end
- def quality_profile
+ # GET /project/profile?id=<project id>
+ def profile
+ require_parameters :id
@project = get_current_project(params[:id])
- @profiles = Profile.find(:all, :conditions => {:language => @project.language, :enabled => true})
end
- def update_quality_profile
+ # POST /project/set_profile?id=<project id>&language=<language>[&profile_id=<profile id>]
+ def set_profile
+ require_parameters :id, :language
+ verify_post_request
+
+ language=params[:language]
project = get_current_project(params[:id])
- selected_profile = Profile.find(:first, :conditions => {:id => params[:quality_profile].to_i})
- if selected_profile && selected_profile.language == project.language
- project.profile = selected_profile
- project.save!
- flash[:notice] = message('project_quality_profile.profile_successfully_updated')
+ if params[:profile_id].blank?
+ Profile.reset_default_profile_for_project_id(language, project.id)
else
- selected_profile_name = selected_profile ? selected_profile.name + "(" + selected_profile.language + ")" : "Unknown profile"
- flash[:error] = message('project_quality_profile.project_cannot_be_update_with_profile_x', :params => selected_profile_name)
+ profile = Profile.find(params[:profile_id])
+ bad_request('Bad language') if profile.language!=language
+ profile.add_project_id(project.id)
end
- redirect_to :action => 'quality_profile', :id => project.id
+ redirect_to :action => 'profile', :id => project.id
end
def key
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb
index 39b9ac0f3ab..8720d718e20 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb
@@ -721,7 +721,7 @@ module ApplicationHelper
end
#
- # Creates a button linked to a POST action. A confirmation popup is opened when user clicks on the button.
+ # Creates a link linked to a POST action. A confirmation popup is opened when user clicks on the button.
# ==== Options
# * <tt>:id</tt> - HTML ID of the button
# * <tt>:class</tt> - Additional CSS class, generally 'red-button' for deletions
@@ -731,7 +731,7 @@ module ApplicationHelper
# * <tt>:message_params</tt> -
# * <tt>:width</tt> - width in pixels
#
- def button_to_action(label, post_url, options={})
+ def link_to_action(label, post_url, options={})
clazz = options[:class]
id = "id='#{options[:id]}'" if options[:id]
title_key = options[:title_key]
@@ -750,6 +750,6 @@ module ApplicationHelper
url += "&bk=#{button_key}"
end
- "<a href='#{url}' modal-width='#{width}' class='open-modal button #{clazz}' #{id}>#{h label}</a>"
+ "<a href='#{url}' modal-width='#{width}' class='open-modal #{clazz}' #{id}>#{h label}</a>"
end
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb
index ddf214b88e2..81e74632ca9 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/api/utils.rb
@@ -169,4 +169,8 @@ class Api::Utils
def self.java_facade
Java::OrgSonarServerUi::JRubyFacade.getInstance()
end
+
+ def self.languages
+ java_facade.getLanguages()
+ end
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/profile.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/profile.rb
index 079645ff6c6..a9bb3d3a20e 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/profile.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/profile.rb
@@ -22,13 +22,21 @@ class Profile < ActiveRecord::Base
has_many :alerts, :dependent => :delete_all
has_many :active_rules, :class_name => 'ActiveRule', :foreign_key => 'profile_id', :dependent => :destroy, :include => ['rule']
- has_many :projects, :order => 'name asc'
- has_many :active_rules_with_params, :class_name => 'ActiveRule', :foreign_key => 'profile_id',
- :include => ['active_rule_parameters', 'active_rule_note']
+ has_many :active_rules_with_params, :class_name => 'ActiveRule', :foreign_key => 'profile_id', :include => ['active_rule_parameters', 'active_rule_note']
+ has_many :projects, :class_name => 'Project', :finder_sql => %q(
+ select prj.* from projects prj, properties prop where prj.id=prop.resource_id and prop.resource_id is not null and prop.prop_key='sonar.profile.#{language}' and prop.text_value='#{name}'
+ )
+ has_many :changes, :class_name => 'ActiveRuleChange', :dependent => :destroy
+ has_many :children, :class_name => 'Profile', :finder_sql => %q(
+ select c.* from rules_profiles c where c.parent_name='#{name}' and c.language='#{language}'
+ )
validates_uniqueness_of :name, :scope => :language, :case_sensitive => false, :message => Api::Utils.message('quality_profiles.already_exists')
validates_presence_of :name, :message => Api::Utils.message('quality_profiles.please_type_profile_name')
+ MAX_NAME_LENGTH = 100
+ validates_length_of :name, :maximum => MAX_NAME_LENGTH, :message => Api::Utils.message('name_too_long_x', :params => [MAX_NAME_LENGTH])
+
# The warnings that are set on this record, equivalent to normal ActiveRecord errors but does not prevent
# the record from saving.
def warnings
@@ -36,7 +44,7 @@ class Profile < ActiveRecord::Base
end
def warnings?
- not warnings.empty?
+ !warnings.empty?
end
def notices
@@ -59,34 +67,16 @@ class Profile < ActiveRecord::Base
provided
end
- def validate_copy(name)
- new_rule_profile = Profile.new(:name => name, :provided => false, :default_profile => false, :language => language)
- new_rule_profile.valid?
- new_rule_profile.errors
- end
-
- def self.find_by_name_and_language(name, language)
- Profile.find(:first, :conditions => {:name => name, :language => language, :enabled => true})
- end
-
- def self.find_active_profile_by_language(language)
- Profile.find(:first, :conditions => {:default_profile => true, :language => language, :enabled => true})
- end
-
- def self.default_profile
- Profile.find(:first, :conditions => {:default_profile => true, :enabled => true})
- end
-
def set_as_default
- default_profile=nil
- Profile.find(:all, :conditions => {:language => language, :enabled => true}).each do |profile|
- if profile.id==id
- profile.default_profile=true
- default_profile=profile
- else
- profile.default_profile=false
+ Profile.transaction do
+ Profile.find(:all, :conditions => {:language => language}).each do |profile|
+ if profile.id==id
+ profile.default_profile=true
+ else
+ profile.default_profile=false
+ end
+ profile.save
end
- profile.save
end
self
end
@@ -97,7 +87,7 @@ class Profile < ActiveRecord::Base
def self.options_for_select
array=[]
- Profile.find(:all, :conditions => {:enabled => true}, :order => 'name').each do |profile|
+ Profile.find(:all, :order => 'name').each do |profile|
label = profile.name
label = label + ' (active)' if profile.default_profile?
array<<[label, profile.id]
@@ -123,9 +113,9 @@ class Profile < ActiveRecord::Base
def count_overriding_rules
@count_overriding_rules||=
- begin
- active_rules.count(:conditions => ['inheritance=?', 'OVERRIDES'])
- end
+ begin
+ active_rules.count(:conditions => ['inheritance=?', 'OVERRIDES'])
+ end
end
def inherited?
@@ -134,13 +124,13 @@ class Profile < ActiveRecord::Base
def parent
@parent||=
- begin
- if parent_name.present?
- Profile.find(:first, :conditions => ['language=? and name=? and enabled=?', language, parent_name, true])
- else
- nil
- end
+ begin
+ if parent_name.present?
+ Profile.find(:first, :conditions => ['language=? and name=?', language, parent_name])
+ else
+ nil
end
+ end
end
def count_active_rules
@@ -149,21 +139,14 @@ class Profile < ActiveRecord::Base
def ancestors
@ancestors ||=
- begin
- array=[]
- if parent
- array<<parent
- array.concat(parent.ancestors)
- end
- array
- end
- end
-
- def children
- @children ||=
- begin
- Profile.find(:all, :conditions => ['language=? and parent_name=? and enabled=?', language, name, true], :order => 'name')
+ begin
+ array=[]
+ if parent
+ array<<parent
+ array.concat(parent.ancestors)
end
+ array
+ end
end
def import_configuration(importer_key, file)
@@ -178,4 +161,60 @@ class Profile < ActiveRecord::Base
notices.add_to_base msg
end
end
+
+ def before_destroy
+ Property.clear_for_resources("sonar.profile.#{language}", name)
+ #TODO clear global property sonar.profile.#{language} with value #{name}
+ end
+
+ def rename(new_name)
+ old_name=self.name
+ Profile.transaction do
+ children_to_be_renamed=children()
+ self.name=new_name
+ if save
+ children_to_be_renamed.each do |child|
+ child.parent_name=new_name
+ child.save
+ end
+ Property.update_all("text_value='#{new_name}'", ['prop_key=? and text_value=?', "sonar.profile.#{language}", old_name])
+ end
+ end
+ self
+ end
+
+ def add_project_id(project_id)
+ Property.set("sonar.profile.#{language}", name, project_id)
+ end
+
+ def remove_projects
+ Property.clear_for_resources("sonar.profile.#{language}", name)
+ end
+
+ def self.reset_default_profile_for_project_id(lang, project_id)
+ Property.clear("sonar.profile.#{lang}", project_id)
+ end
+
+ def self.by_project_id(language, project_id, returns_default_if_nil=false)
+ profile_name=Property.value("sonar.profile.#{language}", project_id)
+ profile = (profile_name.present? ? Profile.find_by_name_and_language(profile_name, language) : nil)
+
+ if !profile && returns_default_if_nil
+ profile = by_default(language)
+ end
+ profile
+ end
+
+ def self.by_default(language)
+ Profile.find(:first, :conditions => {:default_profile => true, :language => language})
+ end
+
+ # Results are NOT sorted
+ def self.all_by_language(language)
+ Profile.find(:all, :conditions => {:language => language})
+ end
+
+ def self.find_by_name_and_language(name, language)
+ Profile.find(:first, :conditions => {:name => name, :language => language})
+ end
end \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb
index 07e3a251282..4acf953c17c 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb
@@ -25,7 +25,6 @@ class Project < ActiveRecord::Base
has_many :processed_snapshots, :class_name => 'Snapshot', :conditions => "status='#{Snapshot::STATUS_PROCESSED}' AND qualifier<>'LIB'", :order => 'created_at asc'
has_many :events, :foreign_key => 'resource_id', :order => 'event_date DESC'
has_many :project_links, :dependent => :delete_all, :order => 'link_type'
- belongs_to :profile, :class_name => 'Profile', :foreign_key => 'profile_id'
has_many :user_roles, :foreign_key => 'resource_id'
has_many :group_roles, :foreign_key => 'resource_id'
has_many :manual_measures, :foreign_key => 'resource_id'
@@ -182,6 +181,10 @@ class Project < ActiveRecord::Base
last_snapshot ? last_snapshot.path_name : nil
end
+ def profile(lang, returns_default_if_nil=false)
+ Profile.by_project_id(lang, id, returns_default_if_nil)
+ end
+
private
def create_chart_measures(results, date_column_name, value_column_name)
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb
index 976fdf7480a..6371b51242d 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/property.rb
@@ -21,9 +21,11 @@ class Property < ActiveRecord::Base
validates_presence_of :prop_key
named_scope :with_key, lambda { |value| {:conditions => {:prop_key, value}} }
+ named_scope :with_value, lambda { |value| {:conditions => {:text_value, value}} }
named_scope :with_resource, lambda { |value| {:conditions => {:resource_id => value}} }
named_scope :with_user, lambda { |value| {:conditions => {:user_id => value}} }
- named_scope :on_resource, :conditions => ['resource_id is not ?', nil]
+ named_scope :with_resources, :conditions => 'resource_id is not null'
+ named_scope :with_users, :conditions => 'user_id is not null'
def key
prop_key
@@ -47,6 +49,18 @@ class Property < ActiveRecord::Base
end
end
+ def self.clear_for_resources(key, value=nil)
+ scope=Property.with_resources().with_key(key)
+ if value
+ scope.with_value(value)
+ end
+ scope.delete_all
+ end
+
+ def self.clear_for_users(key)
+ Property.with_users().with_key(key).delete_all
+ end
+
def self.by_key(key, resource_id=nil, user_id=nil)
all(key, resource_id, user_id).first
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
index 9788893ab96..96d831919b5 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
@@ -89,8 +89,8 @@
<% if has_role?(:admin, @project) %>
<li class="h2"><%= message('sidebar.project_settings') -%></li>
<% if (@project.project?) %>
- <li class="<%= 'selected' if request.request_uri.include?('/project/quality_profile') -%>">
- <a href="<%= ApplicationController.root_context -%>/project/quality_profile/<%= @project.id -%>"><%= message('project_quality_profile.page') -%></a></li>
+ <li class="<%= 'selected' if request.request_uri.include?('/project/profile') -%>">
+ <a href="<%= ApplicationController.root_context -%>/project/profile/<%= @project.id -%>"><%= message('project_quality_profile.page') -%></a></li>
<% end %>
<li class="<%= 'selected' if request.request_uri.include?('/manual_measures') -%>">
<a href="<%= ApplicationController.root_context -%>/manual_measures/index/<%= @project.id -%>"><%= message('manual_measures.page') -%></a></li>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_copy_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_copy_form.html.erb
index bff1d8c7bfc..535ea549a10 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_copy_form.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_copy_form.html.erb
@@ -2,14 +2,18 @@
<input type="hidden" name="id" value="<%= @profile.id -%>"/>
<fieldset>
<div class="form-head">
- <h2>Copy Profile: <%= h @profile.name -%></h2>
+ <h2> <%= message('quality_profiles.copy_x_title', :params => [h @profile.name]) -%></h2>
</div>
<div class="form-body">
- <% if @error %>
- <p class="error"><%= h @error -%></p>
- <% end %>
+ <% if @errors
+ @errors.each do |error|
+ %>
+ <p class="error"><%= h error -%></p>
+ <% end
+ end
+ %>
<div class="form-field">
- <label for="name">New name <em>*</em></label>
+ <label for="name"><%= message 'quality_profiles.copy_new_name' -%> <em>*</em></label>
<input id="copy-name" name="name" type="text" size="50" maxlength="100"/>
</div>
</div>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_rename_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_rename_form.html.erb
index 4da833e138d..b7c11aa4ac7 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_rename_form.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/_rename_form.html.erb
@@ -3,12 +3,12 @@
<fieldset>
<div class="form-head">
- <h2>Rename Profile: <%= h @profile.name -%></h2>
+ <h2>Rename Profile: <%= h @profile.name_was -%></h2>
</div>
<div class="form-body">
- <% if @error %>
- <p class="error"><%= h @error -%></p>
+ <% @profile.errors.each do |attr, msg| %>
+ <p class="error"><%= h msg -%></p>
<% end %>
<div class="form-field">
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb
index 201a7718682..50efc517ad0 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/index.html.erb
@@ -49,7 +49,7 @@
</td>
<td align="right">
- <span id="activated_rules_<%= u profile.key -%>"><%= profile.count_active_rules -%></span>
+ <span id="activated_rules_<%= u profile.key -%>"><%= profile.active_rules.count -%></span>
</td>
<td align="right"><span id="alerts_<%= u profile.key -%>"><%= profile.alerts.size -%></span></td>
@@ -62,8 +62,9 @@
<td align="right">
<% if !profile.default_profile? && administrator? %>
- <%= button_to_action message('set_as_default'), "profiles/set_as_default?id=#{profile.id}",
+ <%= link_to_action message('set_as_default'), "profiles/set_as_default?id=#{profile.id}",
:id => "activate_#{profile.key.parameterize}",
+ :class => 'button',
:title_key => 'set_as_default',
:message_key => 'quality_profiles.are_you_sure_want_x_profile_as_default',
:message_params => [profile.name] -%>
@@ -96,8 +97,8 @@
<td>
<% if profile.deletable? %>
- <%= button_to_action message('delete'), "profiles/delete/#{profile.id}",
- :class => 'red-button',
+ <%= link_to_action message('delete'), "profiles/delete/#{profile.id}",
+ :class => 'button red-button',
:id => "delete_#{profile.key.parameterize}",
:button_key => 'delete',
:title_key => 'quality_profiles.delete_confirm_title',
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/projects.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/projects.html.erb
index 8a155a8adbd..df77976eb84 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/projects.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/profiles/projects.html.erb
@@ -1,54 +1,79 @@
-<h1 class="marginbottom10"><%= link_to message('quality_profiles.quality_profiles'), :controller => 'profiles', :action => 'index' -%> / <%= h @profile.language -%> / <%= h @profile.name %></h1>
-<%= render :partial => 'profiles/tabs', :locals => {:selected_tab=>'Projects'} %>
+<h1 class="marginbottom10"><%= link_to message('quality_profiles.quality_profiles'), :controller => 'profiles', :action => 'index' -%> / <%= h @profile.language -%>
+ / <%= h @profile.name %></h1>
+<%= render :partial => 'profiles/tabs', :locals => {:selected_tab => 'Projects'} %>
<div class="tabs-panel">
-<% if is_admin? %>
-<form action="<%= url_for :action => 'set_projects' -%>" method="post" id="select_projects_form">
- <input type="hidden" name="id" value="<%= @profile.id -%>"/>
-<table>
- <tr>
- <td style="padding: 5px 0" valign="top">
- <h3><%= message('quality_profiles.available_projects') -%></h3>
- <select name="from" id="from" size="10" style="max-width:380px;margin-top: 5px" multiple="multiple">
- <% @available_projects.each do |project| %>
- <option value="<%= project.id -%>"><%= project.name %><%= " (#{project.profile.name})" if project.profile %></option>
+ <% if is_admin? %>
+ <form method="POST" action="<%= ApplicationController.root_context -%>/profiles/add_project" id="add_project_form">
+ <input type="hidden" name="id" value="<%= @profile.id -%>"/>
+
+ Add project: <%= resource_select_tag 'project_id', {
+ :qualifiers => ['TRK'],
+ :width => '400px',
+ :html_id => "select-project",
+ } -%>
+ <script>$j('#select-project').on("change", function (e) {
+ $j(this).select2("disable");
+ $j('#add_project_form').submit();
+ })</script>
+ </form>
+
+ <% unless @profile.projects.empty? %>
+ <table class="data">
+ <thead>
+ <tr>
+ <th></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @profile.projects.each do |project| %>
+ <tr class="<%= cycle('even', 'odd') -%>">
+ <td class="thin">
+ <%= link_to_action message('remove'),
+ "#{ApplicationController.root_context}/profiles/remove_project?id=#{@profile.id}&project_id=#{project.id}",
+ :class => 'link-action',
+ :id => "link-remove-#{project.key.parameterize}" -%>
+ </td>
+ <td><%= h project.name -%> <span class="small gray"><%= h project.key -%></span></td>
+ </tr>
<% end %>
- </select>
- </td>
- <td align="center" style="padding: 0 10px;">
- <button id="select_right" onclick="SelectBox.move('from', 'to');SelectBox.sort('to');SelectBox.redisplay('to');return false;"><%= message('select_verb').downcase -%> &raquo;</button><br/>
- <button id="select_right_all" onclick="SelectBox.move_all('from', 'to');return false;"><%= message('select_all').downcase -%> &raquo;</button><br/><br/>
- <button id="select_left" onclick="SelectBox.move('to', 'from');return false;">&laquo; <%= message('unselect_verb').downcase -%></button><br/>
- <button id="select_left_all" onclick="SelectBox.move_all('to', 'from');return false;">&laquo; <%= message('unselect_all').downcase -%></button>
- </td>
- <td class="box" style="padding: 5px 10px;" valign="top">
- <h3><%= message('quality_profiles.associated_projects') -%></h3>
- <select name="projects[]" id="to" size="10" multiple="multiple" style="min-width: 300px;margin: 5px 0;">
- <%= options_from_collection_for_select(@profile.projects, "id", "name") %>
- </select><br/>
- <div style="padding:5px 0">
- <input type="submit" id="save" value="<%= message('save') -%>" onclick="SelectBox.select_all('to');submit();"/>
- </div>
- </td>
-</tr>
-</table>
-</form>
-<script>
-SelectBox.init('from');
-SelectBox.init('to');
-</script>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="2">
+ <%= link_to_action message('quality_profiles.remove_projects_action'),
+ "#{ApplicationController.root_context}/profiles/remove_projects?id=#{@profile.id}",
+ :class => 'link-action',
+ :id => "link-remove-projects" -%>
+ </td>
+ </tr>
+ </tfoot>
+ </table>
-<% else %>
- <% if @profile.projects.empty? %>
- <p><%= message('quality_profiles.no_projects_associated_to_profile_x', :params => @profile.name) -%></p>
+ <% end %>
<% else %>
- <p><%= message('quality_profiles.projects_warning') -%></p>
- <ol>
- <% @profile.projects.each do |project| %>
- <li><%= project.name %></li>
+
+ <% if @profile.projects.empty? %>
+ <p><%= message('quality_profiles.no_projects_associated_to_profile_x', :params => @profile.name) -%></p>
+ <% else %>
+ <p><%= message('quality_profiles.projects_warning') -%></p>
+
+ <table class="data">
+ <thead>
+ <tr>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @profile.projects.each do |project| %>
+ <tr class="<%= cycle('even', 'odd') -%>">
+ <td><%= h project.name -%> <span class="small gray"><%= h project.key -%></span></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
<% end %>
- </ol>
<% end %>
-<% end %>
</div> \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/project/profile.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/project/profile.html.erb
new file mode 100644
index 00000000000..a52e06af2ec
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/project/profile.html.erb
@@ -0,0 +1,40 @@
+<h1 class="marginbottom10"><%= message('project_quality_profile.page') -%></h1>
+
+<table class="data">
+ <thead>
+ <tr>
+ <th><%= message 'language' -%></th>
+ <th>Quality Profile</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+ Api::Utils.languages.sort_by { |l| l.getKey() }.each do |language|
+ selected_profile=@project.profile(language.getKey(), false)
+ %>
+ <tr class="<%= cycle 'even', 'odd' -%>">
+ <td class="thin"><%= h language.getName() -%></td>
+ <td>
+ <form id="form-<%= language.getKey().parameterize -%>" method="POST" action="<%= ApplicationController.root_context -%>/project/set_profile">
+ <input type="hidden" name="id" value="<%= @project.id -%>"/>
+ <input type="hidden" name="language" value="<%= language.getKey() -%>"/>
+
+ <select id="select-profiles-<%= language.getKey().parameterize -%>" name="profile_id">
+ <option value="" <%= "selected='selected'" unless selected_profile -%>><%= message 'project_quality_profile.default_profile' -%></option>
+ <optgroup>
+ <%
+ profiles = Api::Utils.insensitive_sort(Profile.all_by_language(language.getKey())) { |profile| profile.name }
+ profiles.each do |profile|
+ %>
+ <option value="<%= profile.id -%>" <%= "selected='selected'" if selected_profile && selected_profile.id==profile.id -%>><%= h profile.name -%></option>
+ <% end %>
+ </optgroup>
+ </select>
+
+ <%= submit_tag message('update_verb'), :id => "submit-#{language.getKey()}", :disable_with => message('updating') %>
+ </form>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/project/quality_profile.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/project/quality_profile.html.erb
deleted file mode 100644
index f75218f7db9..00000000000
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/project/quality_profile.html.erb
+++ /dev/null
@@ -1,23 +0,0 @@
-<h1><%= message('project_quality_profile.page') -%></h1>
-<br/>
-<%
- form_tag( {:action => 'update_quality_profile', :id => @project.id }) do
- project_profile = @project.profile
-%>
-
- <span style= "padding-right: 10px"><%= message('project_quality_profile.select_profile_for_x', :params => @project.name) -%></span>
-
- <select name="quality_profile" id="quality_profile">
- <%
- @profiles.each do |profile|
- should_be_selected = (project_profile && project_profile==profile) || (!project_profile && profile.default_profile)
- label = profile.name
- label += ' (' + message('project_quality_profile.default_profile') + ')' if profile.default_profile
- %>
- <option <%= 'selected' if should_be_selected -%> value="<%= profile.id -%>"><%= label -%></option>
- <% end %>
- </select>
-
- <%= submit_tag message('update_verb'), :id => 'update_profile' %>
-
-<% end %>
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/331_remove_projects_profile_id.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/331_remove_projects_profile_id.rb
new file mode 100644
index 00000000000..68fc65062e4
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/331_remove_projects_profile_id.rb
@@ -0,0 +1,45 @@
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# Sonar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+
+#
+# Sonar 3.3
+#
+class RemoveProjectsProfileId < ActiveRecord::Migration
+
+ class Profile < ActiveRecord::Base
+ set_table_name 'rules_profiles'
+ end
+
+ class Project < ActiveRecord::Base
+ belongs_to :profile
+ end
+
+ class Property < ActiveRecord::Base
+ end
+
+ def self.up
+ projects=Project.find(:all, :conditions => ['profile_id is not null and copy_resource_id is null'], :include => :profile)
+ projects.each do |project|
+ Property.create(:prop_key => "sonar.profile.#{project.profile.language}", :text_value => project.profile.name, :resource_id => project.id)
+ end
+ remove_column('projects', 'profile_id')
+ end
+
+end