summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-12-19 10:29:17 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-12-19 10:29:27 +0100
commit79e8246a6449e1cac91d5c44262e791dba07e9e7 (patch)
treefdcc96fcde4d0c0309648e4f3b495a92b549875c
parentf1c12f9673545a181712a3c27cd655d59d567c86 (diff)
downloadsonarqube-79e8246a6449e1cac91d5c44262e791dba07e9e7.tar.gz
sonarqube-79e8246a6449e1cac91d5c44262e791dba07e9e7.zip
SONAR-5830 Possibility to map authors (from SCM) to SonarQube users
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/DefaultUserService.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/DefaultUserServiceTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java15
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/users_controller.rb13
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_create_form.html.erb39
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_edit_form.html.erb71
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb84
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties1
9 files changed, 180 insertions, 79 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/DefaultUserService.java b/server/sonar-server/src/main/java/org/sonar/server/user/DefaultUserService.java
index 7de63a17920..9bd6465ebf6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/DefaultUserService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/DefaultUserService.java
@@ -28,6 +28,7 @@ import org.sonar.api.user.UserQuery;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.user.UserDao;
import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.user.index.UserDoc;
import org.sonar.server.util.RubyUtils;
import javax.annotation.CheckForNull;
@@ -69,17 +70,9 @@ public class DefaultUserService implements RubyUserService {
return builder.build();
}
- public void deactivate(String login) {
- if (Strings.isNullOrEmpty(login)) {
- throw new BadRequestException("Login is missing");
- }
- UserSession userSession = UserSession.get();
- userSession.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
- if (Objects.equal(userSession.login(), login)) {
- throw new BadRequestException("Self-deactivation is not possible");
- }
- dao.deactivateUserByLogin(login);
- userService.index();
+ @CheckForNull
+ public UserDoc getByLogin(String login) {
+ return userService.getNullableByLogin(login);
}
public boolean create(Map<String, Object> params) {
@@ -111,6 +104,19 @@ public class DefaultUserService implements RubyUserService {
userService.update(updateUser);
}
+ public void deactivate(String login) {
+ if (Strings.isNullOrEmpty(login)) {
+ throw new BadRequestException("Login is missing");
+ }
+ UserSession userSession = UserSession.get();
+ userSession.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+ if (Objects.equal(userSession.login(), login)) {
+ throw new BadRequestException("Self-deactivation is not possible");
+ }
+ dao.deactivateUserByLogin(login);
+ userService.index();
+ }
+
public void index() {
userService.index();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
index dff44ab1916..48bf1c9864d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/UserUpdater.java
@@ -47,6 +47,7 @@ import javax.annotation.Nullable;
import java.io.StringWriter;
import java.security.SecureRandom;
+import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -257,6 +258,7 @@ public class UserUpdater implements ServerComponent {
@CheckForNull
private static String convertScmAccountsToCsv(@Nullable List<String> scmAccounts) {
if (scmAccounts != null) {
+ scmAccounts.removeAll(Arrays.asList(null, ""));
int size = scmAccounts.size();
StringWriter writer = new StringWriter(size);
CsvWriter csv = CsvWriter.of(writer);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/DefaultUserServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/DefaultUserServiceTest.java
index b8d17b96fa6..98a8f308a8a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/DefaultUserServiceTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/DefaultUserServiceTest.java
@@ -231,6 +231,12 @@ public class DefaultUserServiceTest {
}
@Test
+ public void get_by_login() throws Exception {
+ service.getByLogin("john");
+ verify(userService).getNullableByLogin("john");
+ }
+
+ @Test
public void index() throws Exception {
service.index();
verify(userService).index();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java
index 582eaa1ca37..0ae9a1a9b08 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/UserUpdaterTest.java
@@ -142,6 +142,21 @@ public class UserUpdaterTest {
}
@Test
+ public void create_user_with_scm_accounts_containing_blank_entry() throws Exception {
+ when(system2.now()).thenReturn(1418215735482L);
+ createDefaultGroup();
+
+ userUpdater.create(NewUser.create()
+ .setLogin("user")
+ .setName("User")
+ .setPassword("password")
+ .setPasswordConfirmation("password")
+ .setScmAccounts(newArrayList("u1", "", null)));
+
+ assertThat(userDao.selectNullableByLogin(session, "user").getScmAccounts()).doesNotContain(",");
+ }
+
+ @Test
public void fail_to_create_user_with_missing_login() throws Exception {
try {
userUpdater.create(NewUser.create()
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/users_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/users_controller.rb
index 948aa8bcbbf..779a828b329 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/users_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/users_controller.rb
@@ -63,12 +63,7 @@ class UsersController < ApplicationController
end
def create_form
- if params[:id]
- # TODO is it really used ?
- @user = User.find(params[:id])
- else
- @user = User.new
- end
+ @user = User.new
render :partial => 'users/create_form'
end
@@ -77,8 +72,10 @@ class UsersController < ApplicationController
end
def edit_form
- @user = User.find(params[:id])
- render :partial => 'users/edit_form', :status => 200
+ call_backend do
+ @user = Internal.users_api.getByLogin(params[:id])
+ render :partial => 'users/edit_form', :status => 200
+ end
end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_create_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_create_form.html.erb
index 140d52a7d91..b0bd112c40d 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_create_form.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_create_form.html.erb
@@ -6,12 +6,7 @@
<div class="modal-body">
<div class="modal-error"/>
<div class="modal-field"><label for="user[login]">Login <em class="mandatory">*</em></label>
- <% if @user.id %>
- <%= @user.login %>
- <%= f.hidden_field :login %>
- <% else %>
- <%= f.text_field :login, :size => 30, :maxLength => 255 %>
- <% end %>
+ <%= f.text_field :login, :size => 30, :maxLength => 255 %>
</div>
<div class="modal-field">
<label for="user[]">Name <em class="mandatory">*</em></label>
@@ -23,6 +18,27 @@
<label for="user[password]">Password <em class="mandatory">*</em></label><%= f.password_field :password, :size => 30, :maxLength => 50, :autocomplete => 'off' %></div>
<div class="modal-field"><label for="user[password_confirmation]">Confirm password
<em class="mandatory">*</em></label><%= f.password_field :password_confirmation, :size => 30, :maxLength => 50, :autocomplete => 'off' %></div>
+
+ <div class="modal-field">
+ <label for="user[scm_accounts]">SCM accounts</label>
+ <table>
+ <tr class="scm_account">
+ <td>
+ <input id="user_scm_accounts" type="text" size="30" name="user[scm_accounts][]"/>
+ </td>
+ </tr>
+ <tr class="scm_account template" style="display:none">
+ <td>
+ <input id="user_scm_accounts" type="text" size="30" name="user[scm_accounts][]"/>
+ <a href="#" class="delete link-action"><%= message('delete') -%></a>
+ <br/>
+ </td>
+ </tr>
+ </table>
+ <div class="note marginbottom10">Note that login and email are automatically considered as SCM accounts</div>
+ <button class="add_value"><%= message('user.add_scm_account') -%></button>
+ </div>
+
</div>
<div class="modal-foot">
<%= submit_tag 'Create' %>
@@ -33,4 +49,15 @@
<script>
$j("#user_create_form").modalForm();
+
+ $j('#user_create_form .delete').click(function () {
+ $j(this).parents('.scm_account').remove();
+ return false;
+ });
+
+ $j('#user_create_form .add_value').click(function () {
+ var template = $j(this).parents('#user_create_form').find('.template').last();
+ template.clone().insertBefore(template).show();
+ return false;
+ });
</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_edit_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_edit_form.html.erb
index 54144e89ac8..59d0216f32d 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_edit_form.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/_edit_form.html.erb
@@ -1,33 +1,78 @@
-<% form_for :user, @user, :url => { :id => @user.id, :action => 'update'}, :html => { :id =>'user_edit_form', :method => @user.id.nil? ? :post : :put} do |f| %>
- <fieldset>
+<form id="user_edit_form" method="post" action="<%= ApplicationController.root_context -%>/users/update">
+<fieldset>
<div class="modal-head">
- <h2>Edit user: <%= h @user.login -%></h2>
+ <h2>Edit user: <%= h @user.login() -%></h2>
</div>
<div class="modal-body">
<div class="modal-error"></div>
<div class="modal-field">
- <% if @user.id %>
- <%= f.hidden_field :login %>
- <% else %>
- <%= f.text_field :login, :size => 30, :maxLength => 255 %>
- <% end %>
+ <input type="hidden" value="<%= @user.login() %>" name="user[login]" id="user_name"/>
</div>
<div class="modal-field">
<label for="user[]">Name<em class="mandatory">*</em></label>
- <%= f.text_field :name, :size => 30, :maxLength => 200 %>
+ <input type="text" value="<%= @user.name() %>" size="30" name="user[name]" maxlength="200" id="user_name"/>
</div>
<div class="modal-field">
<label for="user[]">Email</label>
- <%= f.text_field :email, :size => 30, :maxLength => 100 %>
+ <input type="text" value="<%= @user.email() %>" size="30" name="user[email]" maxlength="100" id="user_email">
+ </div>
+ <div class="modal-field">
+ <label for="user[scm_accounts]">SCM accounts</label>
+ <table>
+ <% scmAccounts = @user.scmAccounts().to_a %>
+ <% if scmAccounts.empty? %>
+ <tr class="scm_account">
+ <td>
+ <input id="user_scm_accounts" type="text" size="30" name="user[scm_accounts][]"/>
+ </td>
+ </tr>
+ <% else %>
+ <tr class="scm_account">
+ <td>
+ <input id="user_scm_accounts" value="<%= scmAccounts.first() %>" type="text" size="30" name="user[scm_accounts][]"/>
+ </td>
+ </tr>
+ <%
+ scmAccounts.shift
+ scmAccounts.each do |scmAccount| %>
+ <tr class="scm_account">
+ <td>
+ <input id="user_scm_accounts" value="<%= scmAccount %>" type="text" size="30" name="user[scm_accounts][]"/>
+ <a href="#" class="delete link-action"><%= message('delete') -%></a>
+ </td>
+ </tr>
+ <% end %>
+ <% end %>
+ <tr class="scm_account template" style="display:none">
+ <td>
+ <input id="user_scm_accounts" type="text" size="30" name="user[scm_accounts][]"/>
+ <a href="#" class="delete link-action"><%= message('delete') -%></a>
+ <br/>
+ </td>
+ </tr>
+ </table>
+ <div class="note marginbottom10">Note that login and email are automatically considered as SCM accounts</div>
+ <button class="add_value"><%= message('user.add_scm_account') -%></button>
</div>
</div>
<div class="modal-foot">
- <%= submit_tag 'Save' %>
- <%= link_to 'Cancel', { :controller => 'users', :action => 'index'}, { :class => 'action' } %><br/>
+ <input type="submit" value="Save" name="commit">
+ <a class="action" href="#" onclick="return closeModalWindow()"><%= h message('cancel') -%></a>
</div>
</fieldset>
-<% end %>
+</form>
<script>
$j("#user_edit_form").modalForm();
+
+ $j('#user_edit_form .delete').click(function () {
+ $j(this).parents('.scm_account').remove();
+ return false;
+ });
+
+ $j('#user_edit_form .add_value').click(function () {
+ var template = $j(this).parents('#user_edit_form').find('.template').last();
+ template.clone().insertBefore(template).show();
+ return false;
+ });
</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb
index 131c2491982..11369d6ed8f 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/users/index.html.erb
@@ -3,15 +3,16 @@
<% end %>
<div>
- <% if profiles_administrator? %>
- <ul style="float: right" class="horizontal">
- <li class="marginleft10 add">
- <a id="create-link-user" href="<%=ApplicationController.root_context-%>/users/create_form" id="create-link-user" class="open-modal link-action">Add new user</a>
- </li>
- </ul>
- <% end %>
- <h1 class="admin-page-title"><%= message('users.page') -%></h1>
- <p class="admin-page-description"><%= message('users.page.description') -%> </p>
+ <% if profiles_administrator? %>
+ <ul style="float: right" class="horizontal">
+ <li class="marginleft10 add">
+ <a id="create-link-user" href="<%= ApplicationController.root_context -%>/users/create_form" id="create-link-user" class="open-modal link-action">Add new user</a>
+ </li>
+ </ul>
+ <% end %>
+ <h1 class="admin-page-title"><%= message('users.page') -%></h1>
+
+ <p class="admin-page-description"><%= message('users.page.description') -%> </p>
</div>
<table width="100%">
@@ -19,39 +20,40 @@
<td valign="top">
<table class="data width100 sortable" id="users">
<thead>
- <tr>
- <th class="left"><a>Login</a></th>
- <th class="left sortfirstasc"><a>Name</a></th>
- <th class="left"><a>Email</a></th>
- <th class="left nosort"><a>Groups</a></th>
- <th class="right nosort" nowrap><a>Operations</a></th>
- </tr>
+ <tr>
+ <th class="left"><a>Login</a></th>
+ <th class="left sortfirstasc"><a>Name</a></th>
+ <th class="left"><a>Email</a></th>
+ <th class="left nosort"><a>Groups</a></th>
+ <th class="right nosort" nowrap><a>Operations</a></th>
+ </tr>
</thead>
- <tbody >
- <% @users.each do |user|%>
- <tr id="user-<%= user.login.parameterize -%>">
- <td class="left" valign="top"><%=h user.login -%></td>
- <td class="left" valign="top"><%= h user.name -%></td>
- <td class="left" valign="top"><%= h user.email -%></td>
- <td class="left" valign="top">
- <%= h user.groups.sort.map(&:name).join(', ') %> (<%= link_to "select", {:action => 'select_group', :id => user.id}, {:id => "select-#{user.login.parameterize}", :class => 'open-modal link-action'} %>)
- </td>
- <td class="right" valign="top">
- <a id="edit-<%= user.login -%>" class="open-modal link-action" href="<%=ApplicationController.root_context-%>/users/edit_form/<%= user.id -%>">Edit</a>
- &nbsp;
- <%= link_to 'Change password', { :id => user.id, :action => 'change_password_form'}, {:id => "change-password-#{user.login.parameterize}", :class => 'open-modal link-action'} -%>
- &nbsp;
- <%= link_to_action message('delete'), "#{ApplicationController.root_context}/users/delete/#{user.id}",
- :class => 'link-action link-red',
- :id => "delete-#{user.login}",
- :confirm_button => message('delete'),
- :confirm_title => 'Delete user: '+user.login,
- :confirm_msg => 'Warning : are you sure to delete the user "' + user.name+'"?' ,
- :confirm_msg_params => [user.name]
- -%>
- </td>
- </tr>
- <% end %>
+ <tbody>
+ <% @users.each do |user| %>
+ <tr id="user-<%= user.login.parameterize -%>">
+ <td class="left" valign="top"><%= h user.login -%></td>
+ <td class="left" valign="top"><%= h user.name -%></td>
+ <td class="left" valign="top"><%= h user.email -%></td>
+ <td class="left" valign="top">
+ <%= h user.groups.sort.map(&:name).join(', ') %>
+ (<%= link_to "select", {:action => 'select_group', :id => user.id}, {:id => "select-#{user.login.parameterize}", :class => 'open-modal link-action'} %>)
+ </td>
+ <td class="right" valign="top">
+ <a id="edit-<%= user.login -%>" class="open-modal link-action" href="<%= ApplicationController.root_context -%>/users/edit_form/<%= u user.login -%>">Edit</a>
+ &nbsp;
+ <%= link_to 'Change password', {:id => user.id, :action => 'change_password_form'}, {:id => "change-password-#{user.login.parameterize}", :class => 'open-modal link-action'} -%>
+ &nbsp;
+ <%= link_to_action message('delete'), "#{ApplicationController.root_context}/users/delete/#{user.id}",
+ :class => 'link-action link-red',
+ :id => "delete-#{user.login}",
+ :confirm_button => message('delete'),
+ :confirm_title => 'Delete user: '+user.login,
+ :confirm_msg => 'Warning : are you sure to delete the user "' + user.name+'"?',
+ :confirm_msg_params => [user.name]
+ -%>
+ </td>
+ </tr>
+ <% end %>
</tbody>
</table>
<script>jQuery('#users').sortable();</script>
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 2a3fa55a00b..08e7ae9e741 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1968,6 +1968,7 @@ events.name_required=Name (required)
user.bad_login=Use only letters, numbers, and .-_@ please.
user.password_doesnt_match_confirmation=Password doesn't match confirmation.
user.reactivated=The user '{0}' has been reactivated.
+user.add_scm_account=Add SCM account
#------------------------------------------------------------------------------