aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2012-04-01 16:29:12 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2012-04-01 16:29:12 +0200
commit3fe232f417bf8f46eef517b74de596d4c9650006 (patch)
tree9e7a18c6470f1873f0c119648c16ec0e6665b209
parentbc058ab2299402a3263dae5fb2ef84eed3c72893 (diff)
downloadsonarqube-3fe232f417bf8f46eef517b74de596d4c9650006.tar.gz
sonarqube-3fe232f417bf8f46eef517b74de596d4c9650006.zip
Management console of project roles : add pagination and support of new resource types
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java1
-rw-r--r--sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java13
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb35
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/search_controller.rb4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/api/pagination.rb62
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/project.rb1
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/resource_index.rb2
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/roles/projects.html.erb183
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/utils/_tfoot_pagination.html.erb22
9 files changed, 235 insertions, 88 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java
index bf2632f271f..3ddd12dc63a 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java
@@ -37,6 +37,7 @@ public final class DefaultResourceTypes extends ExtensionProvider implements Bat
.addType(ResourceType.builder(Qualifiers.PROJECT)
.setProperty("deletable", "true")
.setProperty("modifiable_history", "true")
+ .setProperty("hasRolePolicy", "true")
.build())
.addType(ResourceType.builder(Qualifiers.MODULE).build())
.addType(ResourceType.builder(Qualifiers.DIRECTORY).build())
diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
index f2970d4e9d8..134ddfb54de 100644
--- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
+++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
@@ -19,6 +19,9 @@
*/
package org.sonar.server.ui;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
import org.apache.commons.configuration.Configuration;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
@@ -96,6 +99,16 @@ public final class JRubyFacade {
return null;
}
+ public List<String> getQualifiersWithProperty(final String propertyKey) {
+ List<String> qualifiers = Lists.newArrayList();
+ for (ResourceType type : getResourceTypes()) {
+ if (type.getBooleanProperty(propertyKey) == Boolean.TRUE) {
+ qualifiers.add(type.getQualifier());
+ }
+ }
+ return qualifiers;
+ }
+
public Boolean getResourceTypeBooleanProperty(String resourceTypeQualifier, String resourceTypeProperty) {
ResourceType resourceType = getResourceType(resourceTypeQualifier);
if (resourceType != null) {
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb
index fdb1a8d902e..4118f8da517 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/roles_controller.rb
@@ -19,20 +19,39 @@
#
class RolesController < ApplicationController
helper RolesHelper
-
+
SECTION=Navigation::SECTION_CONFIGURATION
-
+ PER_PAGE = 2
+
before_filter :admin_required
- verify :method => :post, :only => [:grant_users, :grant_groups ], :redirect_to => { :action => 'global' }
+ verify :method => :post, :only => [:grant_users, :grant_groups], :redirect_to => {:action => 'global'}
def global
end
def projects
+ @qualifiers = java_facade.getQualifiersWithProperty('hasRolePolicy')
+ @qualifier = params[:qualifier] || 'TRK'
+
+ # it's not possible to paginate directly in database because
+ # sort would be case-sensitive
+
+ conditions_sql = 'projects.enabled=:enabled and projects.qualifier=:qualifier'
+ conditions_values = {:enabled => true, :qualifier => @qualifier}
+
+ if params[:q].present? && params[:q].size>=ResourceIndex::MIN_SEARCH_SIZE
+ conditions_sql += ' and projects.id in (select ri.resource_id from resource_index ri where ri.qualifier=:qualifier and ri.kee like :filter)'
+ conditions_values[:filter]="#{params[:q].downcase}%"
+ end
+
+ @pagination = Api::Pagination.new(params)
+ @pagination.results= Project.count(:conditions => [conditions_sql, conditions_values])
@projects=Project.find(:all,
- :conditions => {:enabled=>true, :scope => Project::SCOPE_SET, :qualifier => [Project::QUALIFIER_VIEW, Project::QUALIFIER_SUBVIEW, Project::QUALIFIER_PROJECT]},
- :include => ['user_roles', 'group_roles'])
- Api::Utils.insensitive_sort!(@projects){|project| project.name}
+ :include => %w(user_roles group_roles index),
+ :conditions => [conditions_sql, conditions_values],
+ :order => 'resource_index.kee',
+ :offset => @pagination.offset,
+ :limit => @pagination.limit)
end
def edit_users
@@ -49,7 +68,7 @@ class RolesController < ApplicationController
UserRole.grant_users(params[:users], params[:role], params[:resource])
redirect
end
-
+
def grant_groups
GroupRole.grant_groups(params[:groups], params[:role], params[:resource])
redirect
@@ -57,6 +76,6 @@ class RolesController < ApplicationController
private
def redirect
- redirect_to(:action => params['redirect'] || 'global' )
+ redirect_to(:action => params['redirect'] || 'global')
end
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/search_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/search_controller.rb
index 171edc8a637..c4946d1f4ea 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/search_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/search_controller.rb
@@ -24,12 +24,10 @@ class SearchController < ApplicationController
# Do not exceed 1000 because of the Oracle limition on IN statements
MAX_RESULTS = 6
- MIN_SEARCH_SIZE=3
-
def index
@start_time = Time.now
search = params[:s]
- bad_request('Minimum search is 3 characters') if search.empty? || search.to_s.size<MIN_SEARCH_SIZE
+ bad_request("Minimum search is #{ResourceIndex::MIN_SEARCH_SIZE} characters") if search.empty? || search.to_s.size<ResourceIndex::MIN_SEARCH_SIZE
key = search.downcase
results = ResourceIndex.find(:all,
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/api/pagination.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/api/pagination.rb
new file mode 100644
index 00000000000..cb74b5299ea
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/api/pagination.rb
@@ -0,0 +1,62 @@
+#
+# 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
+#
+class Api::Pagination
+
+ DEFAULT_PER_PAGE=25
+ attr_accessor :per_page, :page, :results
+
+ def initialize(options={})
+ @per_page=options[:per_page]||DEFAULT_PER_PAGE
+ @page=options[:page].to_i
+ @page=1 if @page<1
+ @results = options[:results].to_i
+ end
+
+ def pages
+ @pages ||=
+ begin
+ p=(@results / @per_page)
+ p+=1 if @results % @per_page > 0
+ p
+ end
+ end
+
+ def offset
+ (page-1) * per_page
+ end
+
+ # alias
+ def limit
+ per_page
+ end
+
+ # inclusive index
+ #def to_index
+ # [results-1, (page * per_page)-1].min
+ #end
+
+ def previous?
+ page>1
+ end
+
+ def next?
+ page<pages
+ end
+end
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 844b4fb0070..d482c8670aa 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
@@ -33,6 +33,7 @@ class Project < ActiveRecord::Base
belongs_to :copy_resource, :class_name => 'Project', :foreign_key => 'copy_resource_id'
belongs_to :person, :class_name => 'Project', :foreign_key => 'person_id'
has_many :authors, :foreign_key => 'person_id', :dependent => :delete_all
+ has_one :index, :class_name => 'ResourceIndex', :foreign_key => 'resource_id', :conditions => 'position=0', :select => 'kee'
def self.by_key(k)
begin
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/resource_index.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/resource_index.rb
index 7415dc249bf..934649be8b8 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/resource_index.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/resource_index.rb
@@ -24,6 +24,8 @@ class ResourceIndex < ActiveRecord::Base
belongs_to :resource, :class_name => 'Project', :foreign_key => 'resource_id'
belongs_to :root_project, :class_name => 'Project', :foreign_key => 'root_project_id'
+ MIN_SEARCH_SIZE=3
+
def resource_id_for_authorization
root_project_id
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/roles/projects.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/roles/projects.html.erb
index 3331b8dadca..0d7cda524ac 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/roles/projects.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/roles/projects.html.erb
@@ -1,99 +1,128 @@
-<h1 class="marginbottom10">Default roles for new projects</h1>
+<h1 class="marginbottom10">Default roles for new <%= @qualifiers.map { |q| message("qualifiers.#{q}") }.join(', ') -%></h1>
<table class="data width100" id="default-project-roles">
<thead>
- <tr >
+ <tr>
<th>Role</th>
<th width="35%">Users</th>
<th width="35%">Groups</th>
</tr>
</thead>
<tbody>
- <tr class="even" >
- <td valign="top"><b>Administrators</b><br/><span class="small gray">Ability to perform administration functions for a project by accessing its settings.</span></td>
- <td valign="top" style="word-break:break-all;width:35%;">
+ <tr class="even">
+ <td valign="top"><b>Administrators</b><br/><span class="small gray">Ability to perform administration functions for a project by accessing its settings.</span></td>
+ <td valign="top" style="word-break:break-all;width:35%;">
<div style="vertical-align:top">
<span><%= users('default-admin').map(&:login).join(', ') %></span>
(<%= link_to "select", {:action => 'edit_users', :role => 'default-admin', :redirect => 'projects'}, :class => 'link-action' %>)
- </div>
- </td>
- <td valign="top" style="word-break:break-all;width:35%;">
- <span><%= groups('default-admin').map{|g| group_name(g)}.join(', ') %></span>
+ </div>
+ </td>
+ <td valign="top" style="word-break:break-all;width:35%;">
+ <span><%= groups('default-admin').map { |g| group_name(g) }.join(', ') %></span>
(<%= link_to "select", {:action => 'edit_groups', :role => 'default-admin', :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- </tr>
- <tr class="odd" >
- <td valign="top"><b>Users</b><br/><span class="small gray">Ability to navigate through every service of a project, except viewing source code and settings.</span></td>
- <td valign="top" style="word-break:break-all;width:35%;">
- <span><%= users('default-user').map(&:login).join(', ') %></span>
- (<%= link_to "select", {:action => 'edit_users', :role => 'default-user', :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- <td valign="top" style="word-break:break-all;width:35%;">
- <span><%= groups('default-user').map{|g| group_name(g)}.join(', ') %></span>
- (<%= link_to "select", {:action => 'edit_groups', :role => 'default-user', :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- </tr>
- <tr class="even" >
- <td valign="top"><b>Code viewers</b><br/><span class="small gray">Ability to view source code of a project.</span></td>
- <td valign="top" style="word-break:break-all;width:35%;">
- <span><%= users('default-codeviewer').map(&:login).join(', ') %></span>
- (<%= link_to "select", {:action => 'edit_users', :role => 'default-codeviewer', :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- <td valign="top" style="word-break:break-all;width:35%;">
- <span><%= groups('default-codeviewer').map{|g| group_name(g)}.join(', ') %></span>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td valign="top"><b>Users</b><br/><span class="small gray">Ability to navigate through every service of a project, except viewing source code and settings.</span></td>
+ <td valign="top" style="word-break:break-all;width:35%;">
+ <span><%= users('default-user').map(&:login).join(', ') %></span>
+ (<%= link_to "select", {:action => 'edit_users', :role => 'default-user', :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ <td valign="top" style="word-break:break-all;width:35%;">
+ <span><%= groups('default-user').map { |g| group_name(g) }.join(', ') %></span>
+ (<%= link_to "select", {:action => 'edit_groups', :role => 'default-user', :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ </tr>
+ <tr class="even">
+ <td valign="top"><b>Code viewers</b><br/><span class="small gray">Ability to view source code of a project.</span></td>
+ <td valign="top" style="word-break:break-all;width:35%;">
+ <span><%= users('default-codeviewer').map(&:login).join(', ') %></span>
+ (<%= link_to "select", {:action => 'edit_users', :role => 'default-codeviewer', :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ <td valign="top" style="word-break:break-all;width:35%;">
+ <span><%= groups('default-codeviewer').map { |g| group_name(g) }.join(', ') %></span>
(<%= link_to "select", {:action => 'edit_groups', :role => 'default-codeviewer', :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- </tr>
+ </td>
+ </tr>
</tbody>
</table>
<br/><br/>
-<h1 class="marginbottom10">Projects</h1>
+<% if @qualifiers.size>1 %>
-<table class="data width100" >
- <thead>
- <tr >
- <th>Project</th>
- <th>Role: Administrators</th>
- <th>Role: Users</th>
- <th>Role: Code viewers</th>
- </tr>
- </thead>
- <tbody>
+<ul class="tabs" id="qualifier-tabs">
+ <% @qualifiers.each do |q|
+ css_class = (q==@qualifier ? 'selected' : '')
+ %>
+ <li>
+ <%= link_to message("qualifiers.#{q}"), {:action => 'projects', :qualifier => q}, {:class => css_class} -%>
+ </li>
+ <% end %>
+</ul>
+<% else %>
+ <h1 class="spacer-bottom"><%= message("qualifiers.#{@qualifiers[0]}") -%></h1>
+<% end %>
+
+<div class="<%= @qualifiers.size>1 ? 'tabs-panel' : '' -%>">
+
+ <table class="data width100 ">
+ <thead>
+ <tr>
+ <th>Project</th>
+ <th>Role: Administrators</th>
+ <th>Role: Users</th>
+ <th>Role: Code viewers</th>
+ </tr>
+ </thead>
+
+ <%= render :partial => 'utils/tfoot_pagination', :locals => {:pagination => @pagination, :colspan => 4} %>
+
+ <tbody>
<% if @projects.empty? %>
- <tr class="even"><td colspan="4" align="left">No data</td></tr>
- <% else
- @projects.each do |project| %>
- <tr class="<%= cycle('even', 'odd') -%>">
- <td valign="top"><b><%= h project.name %></b><br/>
- <span class="small gray"><%= project.key -%></span>
- </td>
- <td valign="top">
- <%
- users=project.user_roles.select{|ur| ur.role=='admin'}.map{|ur| ur.user.login}
- groups=project.group_roles.select{|gr| gr.role=='admin'}.map{|gr| group_name(gr.group) }
- %>
- <%= users.join(', ') %> (<%= link_to "select users", {:action => 'edit_users', :role => 'admin', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
- <%= groups.join(', ') %> (<%= link_to "select groups", {:action => 'edit_groups', :role => 'admin', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- <td valign="top">
- <%
- users=project.user_roles.select{|ur| ur.role=='user'}.map{|ur| ur.user.login}
- groups=project.group_roles.select{|gr| gr.role=='user'}.map{|gr| group_name(gr.group) }
- %>
- <%= users.join(', ') %> (<%= link_to "select users", {:action => 'edit_users', :role => 'user', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
- <%= groups.join(', ') %> (<%= link_to "select groups", {:action => 'edit_groups', :role => 'user', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
- <td valign="top">
- <%
- users=project.user_roles.select{|ur| ur.role=='codeviewer'}.map{|ur| ur.user.login}
- groups=project.group_roles.select{|gr| gr.role=='codeviewer'}.map{|gr| group_name(gr.group) }
- %>
- <%= users.join(', ') %> (<%= link_to "select users", {:action => 'edit_users', :role => 'codeviewer', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
- <%= groups.join(', ') %> (<%= link_to "select groups", {:action => 'edit_groups', :role => 'codeviewer', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
- </td>
+ <tr class="even">
+ <td colspan="4" align="left"><%= message('no_results') %></td>
</tr>
<% end
- end %>
- </tbody>
-</table> \ No newline at end of file
+
+ @projects.each do |project|
+ %>
+ <tr class="<%= cycle('even', 'odd') -%>">
+ <td valign="top"><b><%= h project.name %></b><br/>
+ <span class="small gray"><%= project.key -%></span>
+ </td>
+ <td valign="top">
+ <%
+ users=project.user_roles.select { |ur| ur.role=='admin' }.map { |ur| ur.user.login }
+ groups=project.group_roles.select { |gr| gr.role=='admin' }.map { |gr| group_name(gr.group) }
+ %>
+ <%= users.join(', ') %>
+ (<%= link_to "select users", {:action => 'edit_users', :role => 'admin', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
+ <%= groups.join(', ') %>
+ (<%= link_to "select groups", {:action => 'edit_groups', :role => 'admin', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ <td valign="top">
+ <%
+ users=project.user_roles.select { |ur| ur.role=='user' }.map { |ur| ur.user.login }
+ groups=project.group_roles.select { |gr| gr.role=='user' }.map { |gr| group_name(gr.group) }
+ %>
+ <%= users.join(', ') %>
+ (<%= link_to "select users", {:action => 'edit_users', :role => 'user', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
+ <%= groups.join(', ') %>
+ (<%= link_to "select groups", {:action => 'edit_groups', :role => 'user', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ <td valign="top">
+ <%
+ users=project.user_roles.select { |ur| ur.role=='codeviewer' }.map { |ur| ur.user.login }
+ groups=project.group_roles.select { |gr| gr.role=='codeviewer' }.map { |gr| group_name(gr.group) }
+ %>
+ <%= users.join(', ') %>
+ (<%= link_to "select users", {:action => 'edit_users', :role => 'codeviewer', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)<br/>
+ <%= groups.join(', ') %>
+ (<%= link_to "select groups", {:action => 'edit_groups', :role => 'codeviewer', :resource => project.id, :redirect => 'projects'}, :class => 'link-action' %>)
+ </td>
+ </tr>
+ <%
+ end %>
+ </tbody>
+ </table>
+</div> \ No newline at end of file
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/utils/_tfoot_pagination.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/utils/_tfoot_pagination.html.erb
new file mode 100644
index 00000000000..3e27189cc4b
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/utils/_tfoot_pagination.html.erb
@@ -0,0 +1,22 @@
+<tfoot>
+<tr>
+ <td colspan="<%= colspan || 1 -%>">
+ <% if pagination.results>0 %>
+ <%= pagination.results -%> <%= message('results').downcase -%>
+ <% end %>
+ <%
+ if pagination.pages>1
+ %>
+ |
+ <%= link_to_if pagination.previous?, message('paging_previous'), params.merge(:page => pagination.page-1) %>
+ <%= link_to_if pagination.next?, message('paging_next'), params.merge(:page => pagination.page+1) %>
+ |
+ <% for index in 1..pagination.pages %>
+ <%= link_to_if index!=pagination.page, index.to_s, params.merge(:page => index) %>
+ <% end %>
+ <%
+ end
+ %>
+ </td>
+</tr>
+</tfoot> \ No newline at end of file