Browse Source

Support organizations in user group web services

tags/6.2-RC1
Simon Brandhof 7 years ago
parent
commit
73b71c9e8e
67 changed files with 1497 additions and 1000 deletions
  1. 4
    7
      server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java
  2. 18
    27
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java
  3. 40
    28
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/CreateAction.java
  4. 39
    31
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java
  5. 25
    22
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupId.java
  6. 73
    0
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupIdOrAnyone.java
  7. 163
    0
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupWsRef.java
  8. 195
    0
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupWsSupport.java
  9. 15
    53
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java
  10. 22
    20
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
  11. 75
    46
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java
  12. 0
    74
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupUpdater.java
  13. 1
    2
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java
  14. 0
    56
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsParameters.java
  15. 9
    16
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java
  16. 0
    63
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/WsGroupRef.java
  17. 0
    1
      server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java
  18. 1
    0
      server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-create.json
  19. 23
    26
      server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java
  20. 84
    88
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java
  21. 96
    26
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/CreateActionTest.java
  22. 118
    84
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/DeleteActionTest.java
  23. 89
    0
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/GroupWsRefTest.java
  24. 63
    82
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java
  25. 61
    49
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
  26. 80
    71
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UpdateActionTest.java
  27. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsModuleTest.java
  28. 5
    4
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
  29. 37
    62
      server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java
  30. 2
    1
      server/sonar-server/src/test/resources/org/sonar/server/user/UserUpdaterTest/associate_default_groups_when_reactivating_user.xml
  31. 2
    1
      server/sonar-server/src/test/resources/org/sonar/server/user/UserUpdaterTest/not_associate_default_group_when_updating_user_if_already_existing.xml
  32. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1404_add_root_column_on_table_users.rb
  33. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1405_populate_root_column_on_table_users.rb
  34. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1406_make_root_column_not_null_on_table_users.rb
  35. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1407_populate_organization_uuid_of_groups.rb
  36. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1408_make_organization_uuid_not_null_on_groups.rb
  37. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1409_add_organization_uuid_to_user_roles.rb
  38. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1410_populate_organization_uuid_of_user_roles.rb
  39. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1411_make_organization_uuid_not_null_on_user_roles.rb
  40. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1412_add_organization_uuid_to_permission_templates.rb
  41. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1413_populate_organization_uuid_of_permission_templates.rb
  42. 0
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1414_make_organization_uuid_not_null_on_permission_templates.rb
  43. 1
    1
      sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
  44. 1
    0
      sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
  45. 4
    2
      sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java
  46. 1
    1
      sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
  47. 2
    1
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_global_permissions_for_group_anyone.xml
  48. 4
    2
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_group_global_permissions.xml
  49. 6
    3
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_user_global_permissions.xml
  50. 14
    7
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/apply_default_permission_template-result.xml
  51. 10
    5
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/apply_default_permission_template_by_component_id-result.xml
  52. 10
    5
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_apply_permission_template-result.xml
  53. 4
    2
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_count_component_permissions.xml
  54. 2
    1
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_remove_all_permissions-result.xml
  55. 4
    2
      sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_remove_all_permissions.xml
  56. 2
    1
      sonar-db/src/test/resources/org/sonar/db/permission/template/PermissionTemplateDaoTest/selectEmptyPermissionTemplate.xml
  57. 0
    2
      sonar-db/src/test/resources/org/sonar/db/permission/template/PermissionTemplateDaoTest/selectPermissionTemplate.xml
  58. 2
    1
      sonar-db/src/test/resources/org/sonar/db/user/GroupDaoTest/find_by_user_login.xml
  59. 6
    3
      sonar-db/src/test/resources/org/sonar/db/user/GroupMembershipDaoTest/shared.xml
  60. 8
    4
      sonar-db/src/test/resources/org/sonar/db/user/GroupMembershipDaoTest/shared_plus_empty_group.xml
  61. 4
    2
      sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_count_component_permissions.xml
  62. 2
    1
      sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_remove_all_permissions-result.xml
  63. 4
    2
      sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_remove_all_permissions.xml
  64. 8
    4
      sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/countRoles.xml
  65. 6
    3
      sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/deleteRolesByResourceId-result.xml
  66. 8
    4
      sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/deleteRolesByResourceId.xml
  67. 43
    0
      sonar-ws/src/main/protobuf/ws-user_groups.proto

+ 4
- 7
server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java View File

@@ -94,22 +94,19 @@ public class GroupsAction implements UsersWsAction {
.pageSize(pageSize)
.build();

DbSession session = dbClient.openSession(false);
try {
UserDto user = dbClient.userDao().selectByLogin(session, login);
try (DbSession dbSession = dbClient.openSession(false)) {
UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
if (user == null) {
throw new NotFoundException(String.format("User with login '%s' has not been found", login));
}
int total = dbClient.groupMembershipDao().countGroups(session, query, user.getId());
int total = dbClient.groupMembershipDao().countGroups(dbSession, query, user.getId());
Paging paging = forPageIndex(page).withPageSize(pageSize).andTotal(total);
List<GroupMembershipDto> groups = dbClient.groupMembershipDao().selectGroups(session, query, user.getId(), paging.offset(), pageSize);
List<GroupMembershipDto> groups = dbClient.groupMembershipDao().selectGroups(dbSession, query, user.getId(), paging.offset(), pageSize);

JsonWriter json = response.newJsonWriter().beginObject();
writeGroups(json, groups);
writePaging(json, paging);
json.endObject().close();
} finally {
session.close();
}
}


+ 18
- 27
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/AddUserAction.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.usergroups.ws;

import java.util.Arrays;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
@@ -27,30 +26,28 @@ import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;

import static java.lang.String.format;
import static org.sonar.db.MyBatis.closeQuietly;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.createGroupParameters;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.createLoginParameter;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineGroupWsParameters;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineLoginWsParameter;

public class AddUserAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserGroupFinder userGroupFinder;
private final UserSession userSession;
private final GroupWsSupport support;

public AddUserAction(DbClient dbClient, UserGroupFinder userGroupFinder, UserSession userSession) {
public AddUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
this.dbClient = dbClient;
this.userGroupFinder = userGroupFinder;
this.userSession = userSession;
this.support = support;
}

@Override
@@ -62,40 +59,34 @@ public class AddUserAction implements UserGroupsWsAction {
.setPost(true)
.setSince("5.2");

createGroupParameters(action);
createLoginParameter(action);
defineGroupWsParameters(action);
defineLoginWsParameter(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

WsGroupRef wsGroupRef = WsGroupRef.newWsGroupRefFromUserGroupRequest(request);
String login = request.mandatoryParam(PARAM_LOGIN);

DbSession dbSession = dbClient.openSession(false);
try {
GroupDto group = userGroupFinder.getGroup(dbSession, wsGroupRef);
try (DbSession dbSession = dbClient.openSession(false)) {
GroupId groupId = support.findGroup(dbSession, request);

String login = request.mandatoryParam(PARAM_LOGIN);
UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login);
if (user == null) {
throw new NotFoundException(format("Could not find a user with login '%s'", login));
}

if (userIsNotYetMemberOf(dbSession, login, group)) {
UserGroupDto userGroup = new UserGroupDto().setGroupId(group.getId()).setUserId(user.getId());
dbClient.userGroupDao().insert(dbSession, userGroup);
if (userIsNotYetMemberOf(dbSession, user.getId(), groupId)) {
UserGroupDto membershipDto = new UserGroupDto().setGroupId(groupId.getId()).setUserId(user.getId());
dbClient.userGroupDao().insert(dbSession, membershipDto);
dbSession.commit();
}

response.noContent();
} finally {
closeQuietly(dbSession);
}

}

private boolean userIsNotYetMemberOf(DbSession dbSession, String login, GroupDto group) {
return !dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, Arrays.asList(login)).get(login).contains(group.getName());
private boolean userIsNotYetMemberOf(DbSession dbSession, long userId, GroupId groupId) {
return !dbClient.groupMembershipDao().selectGroupIdsByUserId(dbSession, userId).contains(groupId.getId());
}
}

+ 40
- 28
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/CreateAction.java View File

@@ -23,47 +23,56 @@ import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.user.UserGroupValidation;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsUserGroups;

import static org.sonar.api.user.UserGroupValidation.GROUP_NAME_MAX_LENGTH;
import static org.sonar.db.MyBatis.closeQuietly;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.DESCRIPTION_MAX_LENGTH;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.PARAM_DESCRIPTION;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.PARAM_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.DESCRIPTION_MAX_LENGTH;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_DESCRIPTION;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;
import static org.sonar.server.usergroups.ws.GroupWsSupport.toProtobuf;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class CreateAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final UserGroupUpdater groupUpdater;
private final GroupWsSupport support;

public CreateAction(DbClient dbClient, UserSession userSession, UserGroupUpdater groupUpdater) {
public CreateAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
this.dbClient = dbClient;
this.groupUpdater = groupUpdater;
this.userSession = userSession;
this.support = support;
}

@Override
public void define(NewController context) {
NewAction action = context.createAction("create")
public void define(NewController controller) {
NewAction action = controller.createAction("create")
.setDescription("Create a group.")
.setHandler(this)
.setPost(true)
.setResponseExample(getClass().getResource("example-create.json"))
.setSince("5.2");

action.createParam(PARAM_NAME)
action.createParam(PARAM_ORGANIZATION_KEY)
.setDescription("Key of organization. If unset then default organization is used.")
.setExampleValue("my-org")
.setSince("6.2");

action.createParam(PARAM_GROUP_NAME)
.setDescription(String.format("Name for the new group. A group name cannot be larger than %d characters and must be unique. " +
"The value 'anyone' (whatever the case) is reserved and cannot be used.", GROUP_NAME_MAX_LENGTH))
.setExampleValue("sonar-users")
.setRequired(true);

action.createParam(PARAM_DESCRIPTION)
action.createParam(PARAM_GROUP_DESCRIPTION)
.setDescription(String.format("Description for the new group. A group description cannot be larger than %d characters.", DESCRIPTION_MAX_LENGTH))
.setExampleValue("Default group for new users");
}
@@ -72,25 +81,28 @@ public class CreateAction implements UserGroupsWsAction {
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

String name = request.mandatoryParam(PARAM_NAME);
String description = request.param(PARAM_DESCRIPTION);
try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = support.findOrganizationByKey(dbSession, request.param(PARAM_ORGANIZATION_KEY));
GroupDto group = new GroupDto()
.setOrganizationUuid(organization.getUuid())
.setName(request.mandatoryParam(PARAM_GROUP_NAME))
.setDescription(request.param(PARAM_GROUP_DESCRIPTION));

groupUpdater.validateName(name);
if (description != null) {
groupUpdater.validateDescription(description);
}
// validations
UserGroupValidation.validateGroupName(group.getName());
support.validateDescription(group.getDescription());
support.checkNameDoesNotExist(dbSession, group.getOrganizationUuid(), group.getName());

DbSession session = dbClient.openSession(false);
try {
groupUpdater.checkNameIsUnique(name, session);
GroupDto newGroup = dbClient.groupDao().insert(session, new GroupDto().setName(name).setDescription(description));
session.commit();
dbClient.groupDao().insert(dbSession, group);
dbSession.commit();

JsonWriter json = response.newJsonWriter().beginObject();
groupUpdater.writeGroup(json, newGroup, 0);
json.endObject().close();
} finally {
closeQuietly(session);
writeResponse(request, response, organization, group);
}
}

private void writeResponse(Request request, Response response, OrganizationDto organization, GroupDto group) {
WsUserGroups.CreateResponse.Builder respBuilder = WsUserGroups.CreateResponse.newBuilder();
respBuilder.setGroup(toProtobuf(organization, group, 0));
writeProtobuf(respBuilder.build(), request, response);
}
}

+ 39
- 31
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/DeleteAction.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.usergroups.ws;

import java.util.Optional;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.Request;
@@ -28,28 +29,32 @@ import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.user.GroupDto;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineGroupWsParameters;

public class DeleteAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserGroupFinder userGroupFinder;
private final UserSession userSession;
private final GroupWsSupport support;
private final Settings settings;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public DeleteAction(DbClient dbClient, UserGroupFinder userGroupFinder, UserSession userSession, Settings settings) {
public DeleteAction(DbClient dbClient, UserSession userSession, GroupWsSupport support, Settings settings,
DefaultOrganizationProvider defaultOrganizationProvider) {
this.dbClient = dbClient;
this.userGroupFinder = userGroupFinder;
this.userSession = userSession;
this.support = support;
this.settings = settings;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
@@ -63,62 +68,65 @@ public class DeleteAction implements UserGroupsWsAction {
.setSince("5.2")
.setPost(true);

UserGroupsWsParameters.createGroupParameters(action);
defineGroupWsParameters(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

WsGroupRef groupRef = WsGroupRef.newWsGroupRefFromUserGroupRequest(request);

DbSession dbSession = dbClient.openSession(false);
try {
GroupDto group = userGroupFinder.getGroup(dbSession, groupRef);
long groupId = group.getId();
try (DbSession dbSession = dbClient.openSession(false)) {
GroupId groupId = support.findGroup(dbSession, request);

checkNotTryingToDeleteDefaultGroup(dbSession, groupId);
checkNotTryingToDeleteLastSystemAdminGroup(dbSession, group.getName());
checkNotTryingToDeleteLastSystemAdminGroup(dbSession, groupId);
removeGroupMembers(dbSession, groupId);
removeGroupPermissions(dbSession, groupId);
removeFromPermissionTemplates(dbSession, groupId);
dbClient.groupDao().deleteById(dbSession, groupId);
dbClient.groupDao().deleteById(dbSession, groupId.getId());

dbSession.commit();
response.noContent();
} finally {
MyBatis.closeQuietly(dbSession);
}
}

private void checkNotTryingToDeleteDefaultGroup(DbSession dbSession, long groupId) {
/**
* The property "default group" is used when registering a new user so that
* he automatically becomes a member of this group. This feature does not
* not exist on non-default organizations yet as organization settings
* are not implemented.
*/
private void checkNotTryingToDeleteDefaultGroup(DbSession dbSession, GroupId group) {
String defaultGroupName = settings.getString(CoreProperties.CORE_DEFAULT_GROUP);
GroupDto defaultGroup = dbClient.groupDao().selectOrFailByName(dbSession, defaultGroupName);
checkArgument(groupId != defaultGroup.getId(),
format("Default group '%s' cannot be deleted", defaultGroupName));
if (defaultGroupName != null && group.getOrganizationUuid().equals(defaultOrganizationProvider.get().getUuid())) {
Optional<GroupDto> defaultGroup = dbClient.groupDao().selectByName(dbSession, group.getOrganizationUuid(), defaultGroupName);
checkArgument(!defaultGroup.isPresent() || defaultGroup.get().getId() != group.getId(),
format("Default group '%s' cannot be deleted", defaultGroupName));
}
}

private void checkNotTryingToDeleteLastSystemAdminGroup(DbSession dbSession, String groupName) {
boolean hasAdminPermission = dbClient.roleDao()
.selectGroupPermissions(dbSession, groupName, null)
private void checkNotTryingToDeleteLastSystemAdminGroup(DbSession dbSession, GroupId group) {
boolean hasAdminPermission = dbClient.groupPermissionDao()
.selectGroupPermissions(dbSession, group.getId(), null)
.contains(GlobalPermissions.SYSTEM_ADMIN);
// TODO support organizations
boolean isOneRemainingAdminGroup = dbClient.groupPermissionDao().countGroups(dbSession, GlobalPermissions.SYSTEM_ADMIN, null) == 1;
boolean hasNoStandaloneAdminUser = dbClient.userPermissionDao().countUsers(dbSession,
PermissionQuery.builder().setPermission(GlobalPermissions.SYSTEM_ADMIN).withAtLeastOnePermission().build()) == 0;
boolean isLastAdminGroup = hasAdminPermission && isOneRemainingAdminGroup && hasNoStandaloneAdminUser;

checkArgument(!isLastAdminGroup, "The last system admin group '%s' cannot be deleted", groupName);
checkArgument(!isLastAdminGroup, "The last system admin group cannot be deleted");
}

private void removeGroupMembers(DbSession dbSession, long groupId) {
dbClient.userGroupDao().deleteMembersByGroupId(dbSession, groupId);
private void removeGroupMembers(DbSession dbSession, GroupId groupId) {
dbClient.userGroupDao().deleteByGroupId(dbSession, groupId.getId());
}

private void removeGroupPermissions(DbSession dbSession, long groupId) {
dbClient.roleDao().deleteGroupRolesByGroupId(dbSession, groupId);
private void removeGroupPermissions(DbSession dbSession, GroupId groupId) {
dbClient.roleDao().deleteGroupRolesByGroupId(dbSession, groupId.getId());
}

private void removeFromPermissionTemplates(DbSession dbSession, long groupId) {
dbClient.permissionTemplateDao().deleteByGroup(dbSession, groupId);
private void removeFromPermissionTemplates(DbSession dbSession, GroupId groupId) {
dbClient.permissionTemplateDao().deleteByGroup(dbSession, groupId.getId());
}
}

server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupFinder.java → server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupId.java View File

@@ -19,35 +19,38 @@
*/
package org.sonar.server.usergroups.ws;

import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import javax.annotation.concurrent.Immutable;
import org.sonar.db.user.GroupDto;

import static org.sonar.server.ws.WsUtils.checkFound;
import static java.util.Objects.requireNonNull;

public class UserGroupFinder {
private final DbClient dbClient;

public UserGroupFinder(DbClient dbClient) {
this.dbClient = dbClient;
}
/**
* Reference to a user group, as used internally by the backend. It does
* not support reference to virtual groups "anyone".
*
* @see GroupWsRef
* @see GroupIdOrAnyone
*/
@Immutable
public class GroupId {

public GroupDto getGroup(DbSession dbSession, WsGroupRef group) {
Long groupId = group.id();
String groupName = group.name();
private final long id;
private final String organizationUuid;

GroupDto groupDto = null;
public GroupId(String organizationUuid, long id) {
this.id = id;
this.organizationUuid = requireNonNull(organizationUuid);
}

if (groupId != null) {
groupDto = checkFound(dbClient.groupDao().selectById(dbSession, groupId),
"Group with id '%d' is not found", groupId);
}
public long getId() {
return id;
}

if (groupName != null) {
groupDto = checkFound(dbClient.groupDao().selectByName(dbSession, groupName),
"Group with name '%s' is not found", groupName);
}
public String getOrganizationUuid() {
return organizationUuid;
}

return groupDto;
public static GroupId from(GroupDto dto) {
return new GroupId(dto.getOrganizationUuid(), dto.getId());
}
}

+ 73
- 0
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupIdOrAnyone.java View File

@@ -0,0 +1,73 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.db.user.GroupDto;

import static java.util.Objects.requireNonNull;

/**
* Reference to a user group, as used internally by the backend. Contrary to
* {@link GroupId}, it supports reference to virtual groups "anyone". In these
* cases {@link #getId()} returns {@code null}
*
* @see GroupWsRef
* @see GroupId
*/
@Immutable
public class GroupIdOrAnyone {

private final Long id;
private final String organizationUuid;

public GroupIdOrAnyone(String organizationUuid, @Nullable Long id) {
this.id = id;
this.organizationUuid = requireNonNull(organizationUuid);
}

public GroupIdOrAnyone(GroupDto group) {
this.id = requireNonNull(group.getId());
this.organizationUuid = requireNonNull(group.getOrganizationUuid());
}

public boolean isAnyone() {
return id == null;
}

@CheckForNull
public Long getId() {
return id;
}

public String getOrganizationUuid() {
return organizationUuid;
}

public static GroupIdOrAnyone from(GroupDto dto) {
return new GroupIdOrAnyone(dto.getOrganizationUuid(), dto.getId());
}

public static GroupIdOrAnyone forAnyone(String organizationUuid) {
return new GroupIdOrAnyone(organizationUuid, null);
}
}

+ 163
- 0
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupWsRef.java View File

@@ -0,0 +1,163 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.security.DefaultGroups;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.server.ws.WsUtils.checkRequest;

/**
* Reference to a user group <b>as declared by web service requests</b>. It is one, and only one,
* of these two options:
* <ul>
* <li>group id, for instance 1234</li>
* <li>group name and optional organization key</li>
* </ul>
*
* The reference is then converted to a {@link GroupId} or {@link GroupIdOrAnyone}.
*/
@Immutable
public class GroupWsRef {

private static final int NULL_ID = -1;

private final long id;
private final String organizationKey;
private final String name;

private GroupWsRef(long id, @Nullable String organizationKey, @Nullable String name) {
this.id = id;
this.organizationKey = organizationKey;
this.name = name;
}

/**
* @return {@code true} if id is defined and {@link #getId()} can be called. If {@code false}, then
* the couple {organizationKey, name} is defined and the methods {@link #getOrganizationKey()}/{@link #getName()}
* can be called.
*/
public boolean hasId() {
return id != NULL_ID;
}

/**
* @return the group id
* @throws IllegalStateException if {@link #getId()} is {@code false}
*/
public long getId() {
checkState(hasId(), "Id is not present. Please see hasId().");
return id;
}

/**
* @return the organization key
* @throws IllegalStateException if {@link #getId()} is {@code true}
*/
@CheckForNull
public String getOrganizationKey() {
checkState(!hasId(), "Organization is not present. Please see hasId().");
return organizationKey;
}

/**
* @return the non-null group name. Can be anyone.
* @throws IllegalStateException if {@link #getId()} is {@code true}
*/
public String getName() {
checkState(!hasId(), "Name is not present. Please see hasId().");
return name;
}

/**
* Creates a reference to a group by its id. Virtual groups "Anyone" can't be returned
* as they can't be referenced by an id.
*/
static GroupWsRef fromId(long id) {
checkArgument(id > -1, "Group id must be positive: %s", id);
return new GroupWsRef(id, null, null);
}

/**
* Creates a reference to a group by its organization and name. Virtual groups "Anyone" are
* supported.
*
* @param organizationKey key of organization. If {@code null}, then default organization will be used.
* @param name non-null name. Can refer to anyone group (case-insensitive {@code "anyone"}).
*/
static GroupWsRef fromName(@Nullable String organizationKey, String name) {
return new GroupWsRef(NULL_ID, organizationKey, requireNonNull(name));
}

public static GroupWsRef create(@Nullable Long id, @Nullable String organizationKey, @Nullable String name) {
if (id != null) {
checkRequest(organizationKey == null && name == null, "Either group id or couple organization/group name must be set");
return fromId(id);
}

checkRequest(name != null, "Group name or group id must be provided");
return fromName(organizationKey, name);
}

public boolean isAnyone() {
return !hasId() && DefaultGroups.isAnyone(name);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
GroupWsRef groupRef = (GroupWsRef) o;
if (id != groupRef.id) {
return false;
}
if (organizationKey != null ? !organizationKey.equals(groupRef.organizationKey) : (groupRef.organizationKey != null)) {
return false;
}
return name != null ? name.equals(groupRef.name) : (groupRef.name == null);
}

@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (organizationKey != null ? organizationKey.hashCode() : 0);
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("GroupWsRef{");
sb.append("id=").append(id);
sb.append(", organizationKey='").append(organizationKey).append('\'');
sb.append(", name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}

+ 195
- 0
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupWsSupport.java View File

@@ -0,0 +1,195 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.user.UserGroupValidation;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonarqube.ws.WsUserGroups;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;

/**
* Factorizes code about user groups between web services
*/
public class GroupWsSupport {

static final String PARAM_GROUP_ID = "id";
static final String PARAM_ORGANIZATION_KEY = "organization";
static final String PARAM_GROUP_NAME = "name";
static final String PARAM_GROUP_DESCRIPTION = "description";
static final String PARAM_LOGIN = "login";

// Database column size should be 500 (since migration #353),
// but on some instances, column size is still 200,
// hence the validation is done with 200
static final int DESCRIPTION_MAX_LENGTH = 200;

private final DbClient dbClient;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public GroupWsSupport(DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider) {
this.dbClient = dbClient;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

/**
* Find a group by its id (parameter {@link #PARAM_GROUP_ID}) or couple organization key/group name
* (parameters {@link #PARAM_ORGANIZATION_KEY} and {@link #PARAM_GROUP_NAME}). The virtual
* group "Anyone" is not supported.
*
* @throws NotFoundException if parameters are missing/incorrect, if the requested group does not exist
* or if the virtual group "Anyone" is requested.
*/
public GroupId findGroup(DbSession dbSession, Request request) {
Long id = request.paramAsLong(PARAM_GROUP_ID);
String organizationKey = request.param(PARAM_ORGANIZATION_KEY);
String name = request.param(PARAM_GROUP_NAME);
return findGroup(dbSession, GroupWsRef.create(id, organizationKey, name));
}

/**
* Finds a user group by its reference. If organization is not defined then group
* is searched in default organization.
*
* @return non-null group
* @throws NotFoundException if the requested group does not exist
* @throws NotFoundException if the requested group is Anyone
*/
public GroupId findGroup(DbSession dbSession, GroupWsRef ref) {
if (ref.hasId()) {
GroupDto group = dbClient.groupDao().selectById(dbSession, ref.getId());
checkFound(group, "No group with id '%s'", ref.getId());
return GroupId.from(group);
}

OrganizationDto org = findOrganizationByKey(dbSession, ref.getOrganizationKey());
Optional<GroupDto> group = dbClient.groupDao().selectByName(dbSession, org.getUuid(), ref.getName());
checkFoundWithOptional(group, "No group with name '%s' in organization '%s'", ref.getName(), org.getKey());
return GroupId.from(group.get());
}

public GroupIdOrAnyone findGroupOrAnyone(DbSession dbSession, GroupWsRef ref) {
if (ref.hasId()) {
GroupDto group = dbClient.groupDao().selectById(dbSession, ref.getId());
checkFound(group, "No group with id '%s'", ref.getId());
return GroupIdOrAnyone.from(group);
}

OrganizationDto org = findOrganizationByKey(dbSession, ref.getOrganizationKey());
if (ref.isAnyone()) {
return GroupIdOrAnyone.forAnyone(org.getUuid());
}

Optional<GroupDto> group = dbClient.groupDao().selectByName(dbSession, org.getUuid(), ref.getName());
checkFoundWithOptional(group, "No group with name '%s' in organization '%s'", ref.getName(), org.getKey());
return GroupIdOrAnyone.from(group.get());
}

/**
* Loads organization from database by its key.
* @param dbSession
* @param key the organization key, or {@code null} to get the default organization
* @return non-null organization
* @throws NotFoundException if no organizations match the provided key
*/
public OrganizationDto findOrganizationByKey(DbSession dbSession, @Nullable String key) {
String effectiveKey = key;
if (effectiveKey == null) {
effectiveKey = defaultOrganizationProvider.get().getKey();
}
Optional<OrganizationDto> org = dbClient.organizationDao().selectByKey(dbSession, effectiveKey);
checkFoundWithOptional(org, "No organization with key '%s'", key);
return org.get();
}

/**
* Similar to {@link UserGroupValidation#validateGroupName(String)} but kept internal. No need to publish
* this method in public API.
* @return the same description
*/
@CheckForNull
String validateDescription(@Nullable String description) {
checkArgument(description == null || description.length() <= DESCRIPTION_MAX_LENGTH,
"Description cannot be longer than %s characters", DESCRIPTION_MAX_LENGTH);
return description;
}

void checkNameDoesNotExist(DbSession dbSession, String organizationUuid, String name) {
// There is no database constraint on column groups.name
// because MySQL cannot create a unique index
// on a UTF-8 VARCHAR larger than 255 characters on InnoDB
if (dbClient.groupDao().selectByName(dbSession, organizationUuid, name).isPresent()) {
throw new BadRequestException(format("Group '%s' already exists", name));
}
}

static WsUserGroups.Group.Builder toProtobuf(OrganizationDto organization, GroupDto group, int membersCount) {
WsUserGroups.Group.Builder wsGroup = WsUserGroups.Group.newBuilder()
.setId(group.getId())
.setOrganization(organization.getKey())
.setName(group.getName())
.setMembersCount(membersCount);
if (group.getDescription() != null) {
wsGroup.setDescription(group.getDescription());
}
return wsGroup;
}

static void defineGroupWsParameters(WebService.NewAction action) {
defineGroupIdWsParameter(action);
defineGroupNameWsParameter(action);
}

private static void defineGroupIdWsParameter(WebService.NewAction action) {
action.createParam(PARAM_GROUP_ID)
.setDescription("Group id")
.setExampleValue("42");
}

private static void defineGroupNameWsParameter(WebService.NewAction action) {
action.createParam(PARAM_ORGANIZATION_KEY)
.setDescription("Key of organization")
.setExampleValue("my-org")
.setSince("6.2");
action.createParam(PARAM_GROUP_NAME)
.setDescription("Group name")
.setExampleValue("sonar-administrators");
}

static WebService.NewParam defineLoginWsParameter(WebService.NewAction action) {
return action.createParam(PARAM_LOGIN)
.setDescription("User login")
.setExampleValue("g.hopper");
}
}

+ 15
- 53
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/RemoveUserAction.java View File

@@ -19,8 +19,6 @@
*/
package org.sonar.server.usergroups.ws;

import javax.annotation.CheckForNull;
import org.sonar.api.security.DefaultGroups;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
@@ -28,29 +26,27 @@ import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.user.UserSession;

import static java.lang.String.format;
import static org.sonar.api.security.DefaultGroups.isAnyone;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.createGroupParameters;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.createLoginParameter;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineGroupWsParameters;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineLoginWsParameter;
import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonar.server.ws.WsUtils.checkRequest;

public class RemoveUserAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final GroupWsSupport support;

public RemoveUserAction(DbClient dbClient, UserSession userSession) {
public RemoveUserAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
this.dbClient = dbClient;
this.userSession = userSession;
this.support = support;
}

@Override
@@ -62,59 +58,25 @@ public class RemoveUserAction implements UserGroupsWsAction {
.setPost(true)
.setSince("5.2");

createGroupParameters(action);
createLoginParameter(action);
defineGroupWsParameters(action);
defineLoginWsParameter(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

WsGroupRef wsGroupRef = WsGroupRef.newWsGroupRefFromUserGroupRequest(request);
String login = request.mandatoryParam(PARAM_LOGIN);
try (DbSession dbSession = dbClient.openSession(false)) {
GroupId group = support.findGroup(dbSession, request);

DbSession dbSession = dbClient.openSession(false);
try {
GroupDto group = getGroup(dbSession, wsGroupRef);
checkRequest(group != null, "It is not possible to remove a user from the '%s' group.", DefaultGroups.ANYONE);
String login = request.mandatoryParam(PARAM_LOGIN);
UserDto user = getUser(dbSession, login);

UserGroupDto userGroup = new UserGroupDto().setGroupId(group.getId()).setUserId(user.getId());
dbClient.userGroupDao().delete(dbSession, userGroup);
dbClient.userGroupDao().delete(dbSession, group.getId(), user.getId());
dbSession.commit();
response.noContent();
} finally {
dbClient.closeSession(dbSession);
}

}

/**
*
* @return null if it's the anyone group
*/
@CheckForNull
private GroupDto getGroup(DbSession dbSession, WsGroupRef group) {
Long groupId = group.id();
String groupName = group.name();

if (isAnyone(groupName)) {
return null;
}

GroupDto groupDto = null;

if (groupId != null) {
groupDto = checkFound(dbClient.groupDao().selectById(dbSession, groupId),
"Group with id '%d' is not found", groupId);
}

if (groupName != null) {
groupDto = checkFound(dbClient.groupDao().selectByName(dbSession, groupName),
"Group with name '%s' is not found", groupName);
response.noContent();
}

return groupDto;
}

private UserDto getUser(DbSession dbSession, String userLogin) {

+ 22
- 20
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java View File

@@ -19,28 +19,28 @@
*/
package org.sonar.server.usergroups.ws;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.user.UserSession;

import static org.apache.commons.lang.StringUtils.defaultIfBlank;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;

public class SearchAction implements UserGroupsWsAction {

@@ -52,15 +52,17 @@ public class SearchAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final GroupWsSupport groupWsSupport;

public SearchAction(DbClient dbClient, UserSession userSession) {
public SearchAction(DbClient dbClient, UserSession userSession, GroupWsSupport groupWsSupport) {
this.dbClient = dbClient;
this.userSession = userSession;
this.groupWsSupport = groupWsSupport;
}

@Override
public void define(NewController context) {
context.createAction("search")
WebService.NewAction action = context.createAction("search")
.setDescription("Search for user groups.<br>" +
"Requires to be logged.")
.setHandler(this)
@@ -69,37 +71,37 @@ public class SearchAction implements UserGroupsWsAction {
.addFieldsParam(ALL_FIELDS)
.addPagingParams(100, MAX_LIMIT)
.addSearchQuery("sonar-users", "names");

action.createParam(PARAM_ORGANIZATION_KEY)
.setDescription("Key of organization. If not set then groups are searched in default organization.")
.setExampleValue("my-org")
.setSince("6.2");
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn();

int page = request.mandatoryParamAsInt(Param.PAGE);
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
SearchOptions options = new SearchOptions()
.setPage(page, pageSize);

String query = StringUtils.defaultIfBlank(request.param(Param.TEXT_QUERY), "");
String query = defaultIfBlank(request.param(Param.TEXT_QUERY), "");
Set<String> fields = neededFields(request);

DbSession dbSession = dbClient.openSession(false);
try {
int limit = dbClient.groupDao().countByQuery(dbSession, query);
List<GroupDto> groups = dbClient.groupDao().selectByQuery(dbSession, query, options.getOffset(), pageSize);
Collection<Long> groupIds = Collections2.transform(groups, new Function<GroupDto, Long>() {
@Override
public Long apply(@Nonnull GroupDto input) {
return input.getId();
}
});
try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = groupWsSupport.findOrganizationByKey(dbSession, request.param(PARAM_ORGANIZATION_KEY));

int limit = dbClient.groupDao().countByQuery(dbSession, organization.getUuid(), query);
List<GroupDto> groups = dbClient.groupDao().selectByQuery(dbSession, organization.getUuid(), query, options.getOffset(), pageSize);
List<Long> groupIds = groups.stream().map(GroupDto::getId).collect(Collectors.toList(groups.size()));
Map<String, Integer> userCountByGroup = dbClient.groupMembershipDao().countUsersByGroups(dbSession, groupIds);

JsonWriter json = response.newJsonWriter().beginObject();
options.writeJson(json, limit);
writeGroups(json, groups, userCountByGroup, fields);
json.endObject().close();
} finally {
dbClient.closeSession(dbSession);
}
}


+ 75
- 46
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java View File

@@ -20,40 +20,50 @@
package org.sonar.server.usergroups.ws;

import java.util.Objects;
import java.util.Optional;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.user.UserGroupValidation;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.db.user.GroupMembershipQuery;
import org.sonar.db.user.UserMembershipQuery;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsUserGroups;

import static java.util.Collections.singletonList;
import static org.sonar.api.CoreProperties.CORE_DEFAULT_GROUP;
import static org.sonar.api.user.UserGroupValidation.GROUP_NAME_MAX_LENGTH;
import static org.sonar.db.MyBatis.closeQuietly;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.DESCRIPTION_MAX_LENGTH;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.PARAM_DESCRIPTION;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.PARAM_ID;
import static org.sonar.server.usergroups.ws.UserGroupUpdater.PARAM_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.DESCRIPTION_MAX_LENGTH;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_DESCRIPTION;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_ID;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.toProtobuf;
import static org.sonar.server.ws.WsUtils.checkFound;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class UpdateAction implements UserGroupsWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final GroupWsSupport support;
private final PersistentSettings persistentSettings;
private final UserGroupUpdater groupUpdater;
private final DefaultOrganizationProvider defaultOrganizationProvider;

public UpdateAction(DbClient dbClient, UserSession userSession, UserGroupUpdater groupUpdater, PersistentSettings persistentSettings) {
public UpdateAction(DbClient dbClient, UserSession userSession, GroupWsSupport support, PersistentSettings persistentSettings,
DefaultOrganizationProvider defaultOrganizationProvider) {
this.dbClient = dbClient;
this.groupUpdater = groupUpdater;
this.userSession = userSession;
this.support = support;
this.persistentSettings = persistentSettings;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}

@Override
@@ -65,18 +75,19 @@ public class UpdateAction implements UserGroupsWsAction {
.setResponseExample(getClass().getResource("example-update.json"))
.setSince("5.2");

action.createParam(PARAM_ID)
action.createParam(PARAM_GROUP_ID)
.setDescription("Identifier of the group.")
.setExampleValue("42")
.setRequired(true);

action.createParam(PARAM_NAME)
.setDescription(String.format("New name for the group. A group name cannot be larger than %d characters and must be unique. " +
"The value 'anyone' (whatever the case) is reserved and cannot be used.", GROUP_NAME_MAX_LENGTH))
action.createParam(PARAM_GROUP_NAME)
.setDescription(String.format("New optional name for the group. A group name cannot be larger than %d characters and must be unique. " +
"The value 'anyone' (whatever the case) is reserved and cannot be used. If value is empty or not defined, then name is not changed.", GROUP_NAME_MAX_LENGTH))
.setExampleValue("sonar-users");

action.createParam(PARAM_DESCRIPTION)
.setDescription(String.format("New description for the group. A group description cannot be larger than %d characters.", DESCRIPTION_MAX_LENGTH))
action.createParam(PARAM_GROUP_DESCRIPTION)
.setDescription(String.format("New optional description for the group. A group description cannot be larger than %d characters. " +
"If value is not defined, then description is not changed.", DESCRIPTION_MAX_LENGTH))
.setExampleValue("Default group for new users");
}

@@ -84,42 +95,60 @@ public class UpdateAction implements UserGroupsWsAction {
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

Long groupId = request.mandatoryParamAsLong(PARAM_ID);
String name = request.param(PARAM_NAME);
String description = request.param(PARAM_DESCRIPTION);

DbSession dbSession = dbClient.openSession(false);
try {
try (DbSession dbSession = dbClient.openSession(false)) {
long groupId = request.mandatoryParamAsLong(PARAM_GROUP_ID);
GroupDto group = dbClient.groupDao().selectById(dbSession, groupId);
if (group == null) {
throw new NotFoundException(String.format("Could not find a user group with id '%s'.", groupId));
}
String oldName = group.getName();
if (name != null) {
groupUpdater.checkNameIsUnique(name, dbSession);
groupUpdater.validateName(name);
group.setName(name);
updateDefaultGroupIfNeeded(dbSession, oldName, name);
checkFound(group, "Could not find a user group with id '%s'.", groupId);
Optional<OrganizationDto> org = dbClient.organizationDao().selectByUuid(dbSession, group.getOrganizationUuid());
checkFoundWithOptional(org, "Could not find organization with id '%s'.", group.getOrganizationUuid());

boolean changed = false;
String newName = request.param(PARAM_GROUP_NAME);
if (newName != null) {
changed = true;
UserGroupValidation.validateGroupName(newName);
support.checkNameDoesNotExist(dbSession, group.getOrganizationUuid(), newName);

String oldName = group.getName();
group.setName(newName);
updateDefaultGroupIfNeeded(dbSession, org.get(), oldName, newName);
}

String description = request.param(PARAM_GROUP_DESCRIPTION);
if (description != null) {
groupUpdater.validateDescription(description);
group.setDescription(description);
changed = true;
group.setDescription(support.validateDescription(description));
}

if (changed) {
dbClient.groupDao().update(dbSession, group);
dbSession.commit();
}
dbClient.groupDao().update(dbSession, group);
dbSession.commit();

JsonWriter json = response.newJsonWriter().beginObject();
groupUpdater.writeGroup(json, group, dbClient.groupMembershipDao().countUsersByGroups(dbSession, singletonList(groupId)).get(group.getName()));
json.endObject().close();
} finally {
closeQuietly(dbSession);

writeResponse(dbSession, request, response, org.get(), group);
}
}

private void updateDefaultGroupIfNeeded(DbSession dbSession, String oldName, String newName) {
String defaultGroupName = persistentSettings.getString(CORE_DEFAULT_GROUP);
if (Objects.equals(defaultGroupName, oldName)) {
persistentSettings.saveProperty(dbSession, CORE_DEFAULT_GROUP, newName);
private void updateDefaultGroupIfNeeded(DbSession dbSession, OrganizationDto org, String oldName, String newName) {
// The feature "default group" relies on a property. As organization properties are
// not implemented yet, default groups are not supported on non-default organizations
if (defaultOrganizationProvider.get().getUuid().equals(org.getUuid())) {
String defaultGroupName = persistentSettings.getString(CORE_DEFAULT_GROUP);
if (Objects.equals(defaultGroupName, oldName)) {
persistentSettings.saveProperty(dbSession, CORE_DEFAULT_GROUP, newName);
}
}
}

private void writeResponse(DbSession dbSession, Request request, Response response, OrganizationDto organization, GroupDto group) {
UserMembershipQuery query = UserMembershipQuery.builder()
.groupId(group.getId())
.membership(GroupMembershipQuery.IN)
.build();
int membersCount = dbClient.groupMembershipDao().countMembers(dbSession, query);

WsUserGroups.UpdateResponse.Builder respBuilder = WsUserGroups.UpdateResponse.newBuilder();
respBuilder.setGroup(toProtobuf(organization, group, membersCount));
writeProtobuf(respBuilder.build(), request, response);
}
}

+ 0
- 74
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupUpdater.java View File

@@ -1,74 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import com.google.common.base.Preconditions;
import org.sonar.api.server.ServerSide;
import org.sonar.api.user.UserGroupValidation;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.BadRequestException;

@ServerSide
public class UserGroupUpdater {

static final String PARAM_ID = "id";
static final String PARAM_DESCRIPTION = "description";
static final String PARAM_NAME = "name";

// Database column size should be 500 (since migration #353),
// but on some instances, column size is still 255,
// hence the validation is done with 255
static final int DESCRIPTION_MAX_LENGTH = 200;

private final DbClient dbClient;

public UserGroupUpdater(DbClient dbClient) {
this.dbClient = dbClient;
}

protected void validateName(String name) {
UserGroupValidation.validateGroupName(name);
}

protected void checkNameIsUnique(String name, DbSession session) {
// There is no database constraint on column groups.name
// because MySQL cannot create a unique index
// on a UTF-8 VARCHAR larger than 255 characters on InnoDB
if (dbClient.groupDao().selectByName(session, name) != null) {
throw new BadRequestException(String.format("Name '%s' is already taken", name));
}
}

protected void validateDescription(String description) {
Preconditions.checkArgument(description.length() <= DESCRIPTION_MAX_LENGTH, String.format("Description cannot be longer than %d characters", DESCRIPTION_MAX_LENGTH));
}

protected void writeGroup(JsonWriter json, GroupDto group, int membersCount) {
json.name("group").beginObject()
.prop(PARAM_ID, group.getId().toString())
.prop(PARAM_NAME, group.getName())
.prop(PARAM_DESCRIPTION, group.getDescription())
.prop("membersCount", membersCount)
.endObject();
}
}

+ 1
- 2
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java View File

@@ -27,8 +27,7 @@ public class UserGroupsModule extends Module {
protected void configureModule() {
add(
UserGroupsWs.class,
UserGroupUpdater.class,
UserGroupFinder.class,
GroupWsSupport.class,
// actions
SearchAction.class,
CreateAction.class,

+ 0
- 56
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsParameters.java View File

@@ -1,56 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.NewParam;

public class UserGroupsWsParameters {
static final String PARAM_GROUP_NAME = "name";
static final String PARAM_GROUP_ID = "id";
static final String PARAM_LOGIN = "login";

private UserGroupsWsParameters() {
// static methods only
}

static void createGroupParameters(NewAction action) {
createGroupIdParameter(action);
createGroupNameParameter(action);
}

private static void createGroupIdParameter(NewAction action) {
action.createParam(PARAM_GROUP_ID)
.setDescription("Group id")
.setExampleValue("42");
}

private static void createGroupNameParameter(NewAction action) {
action.createParam(PARAM_GROUP_NAME)
.setDescription("Group name")
.setExampleValue("sonar-administrators");
}

static NewParam createLoginParameter(NewAction action) {
return action.createParam(PARAM_LOGIN)
.setDescription("User login")
.setExampleValue("g.hopper");
}
}

+ 9
- 16
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java View File

@@ -31,15 +31,13 @@ import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupMembershipQuery;
import org.sonar.db.user.UserMembershipDto;
import org.sonar.db.user.UserMembershipQuery;
import org.sonar.server.user.UserSession;

import static org.sonar.api.utils.Paging.forPageIndex;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.createGroupParameters;
import static org.sonar.server.usergroups.ws.GroupWsSupport.defineGroupWsParameters;

public class UsersAction implements UserGroupsWsAction {

@@ -48,13 +46,13 @@ public class UsersAction implements UserGroupsWsAction {
private static final String FIELD_LOGIN = "login";

private final DbClient dbClient;
private final UserGroupFinder userGroupFinder;
private final UserSession userSession;
private final GroupWsSupport support;

public UsersAction(DbClient dbClient, UserGroupFinder userGroupFinder, UserSession userSession) {
public UsersAction(DbClient dbClient, UserSession userSession, GroupWsSupport support) {
this.dbClient = dbClient;
this.userGroupFinder = userGroupFinder;
this.userSession = userSession;
this.support = support;
}

@Override
@@ -68,26 +66,23 @@ public class UsersAction implements UserGroupsWsAction {
.addSearchQuery("freddy", "names", "logins")
.addPagingParams(25);

createGroupParameters(action);
defineGroupWsParameters(action);
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.SYSTEM_ADMIN);

WsGroupRef wsGroupRef = WsGroupRef.newWsGroupRefFromUserGroupRequest(request);
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
int page = request.mandatoryParamAsInt(Param.PAGE);
String queryString = request.param(Param.TEXT_QUERY);
String selected = request.mandatoryParam(Param.SELECTED);

DbSession dbSession = dbClient.openSession(false);
try {
GroupDto group = userGroupFinder.getGroup(dbSession, wsGroupRef);
long groupId = group.getId();
try (DbSession dbSession = dbClient.openSession(false)) {
GroupId group = support.findGroup(dbSession, request);

UserMembershipQuery query = UserMembershipQuery.builder()
.groupId(groupId)
.groupId(group.getId())
.memberSearch(queryString)
.membership(getMembership(selected))
.pageIndex(page)
@@ -101,8 +96,6 @@ public class UsersAction implements UserGroupsWsAction {
writeMembers(json, users);
writePaging(json, paging);
json.endObject().close();
} finally {
MyBatis.closeQuietly(dbSession);
}
}

@@ -124,7 +117,7 @@ public class UsersAction implements UserGroupsWsAction {
.prop("total", paging.total());
}

private String getMembership(String selected) {
private static String getMembership(String selected) {
SelectionMode selectionMode = SelectionMode.fromParam(selected);
String membership = GroupMembershipQuery.ANY;
if (SelectionMode.SELECTED == selectionMode) {

+ 0
- 63
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/WsGroupRef.java View File

@@ -1,63 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;

import static org.sonar.server.ws.WsUtils.checkRequest;

/**
* Group from a WS request. Guaranties the group id or the group name is provided, not both.
*/
public class WsGroupRef {

private final Long id;
private final String name;

private WsGroupRef(@Nullable Long id, @Nullable String name) {
checkRequest(id != null ^ name != null, "Group name or group id must be provided, not both.");

this.id = id;
this.name = name;
}

public static WsGroupRef newWsGroupRef(@Nullable Long id, @Nullable String name) {
return new WsGroupRef(id, name);
}

public static WsGroupRef newWsGroupRefFromUserGroupRequest(Request wsRequest) {
Long id = wsRequest.paramAsLong(UserGroupsWsParameters.PARAM_GROUP_ID);
String name = wsRequest.param(UserGroupsWsParameters.PARAM_GROUP_NAME);

return new WsGroupRef(id, name);
}

@CheckForNull
public Long id() {
return this.id;
}

@CheckForNull
public String name() {
return this.name;
}
}

+ 0
- 1
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java View File

@@ -21,4 +21,3 @@
package org.sonar.server.usergroups.ws;

import javax.annotation.ParametersAreNonnullByDefault;


+ 1
- 0
server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-create.json View File

@@ -1,6 +1,7 @@
{
"group": {
"id": "42",
"organization": "my-org",
"name": "some-product-bu",
"description": "Business Unit for Some Awesome Product",
"membersCount": 0

+ 23
- 26
server/sonar-server/src/test/java/org/sonar/server/user/ServerUserSessionTest.java View File

@@ -30,11 +30,8 @@ import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.ForbiddenException;

@@ -60,22 +57,19 @@ public class ServerUserSessionTest {
}}.setLogin("regular_user");

@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public ExpectedException expectedException = ExpectedException.none();

private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
private DbClient dbClient = dbTester.getDbClient();
private DbSession dbSession = dbTester.getSession();
private DbClient dbClient = db.getDbClient();
private UserDto userDto = newUserDto().setLogin(LOGIN);
private ComponentDto project;

@Before
public void setUp() throws Exception {
project = componentDbTester.insertComponent(ComponentTesting.newProjectDto(PROJECT_UUID));
componentDbTester.insertComponent(ComponentTesting.newFileDto(project, null, FILE_UUID).setKey(FILE_KEY));
dbClient.userDao().insert(dbSession, userDto);
dbSession.commit();
project = db.components().insertComponent(ComponentTesting.newProjectDto(PROJECT_UUID));
db.components().insertComponent(ComponentTesting.newFileDto(project, null, FILE_UUID).setKey(FILE_KEY));
db.users().insertUser(userDto);
}

@Test
@@ -221,8 +215,8 @@ public class ServerUserSessionTest {

@Test
public void checkComponentPermission_throws_FE_when_user_has_not_permission_for_specified_key_in_db() {
ComponentDto project2 = componentDbTester.insertComponent(ComponentTesting.newProjectDto());
ComponentDto file2 = componentDbTester.insertComponent(ComponentTesting.newFileDto(project2, null));
ComponentDto project2 = db.components().insertComponent(ComponentTesting.newProjectDto());
ComponentDto file2 = db.components().insertComponent(ComponentTesting.newFileDto(project2, null));
addProjectPermissions(project, UserRole.USER);
UserSession session = newUserSession(userDto);

@@ -243,8 +237,8 @@ public class ServerUserSessionTest {

@Test
public void checkComponentPermission_fails_with_FE_when_project_of_specified_uuid_can_not_be_found() {
ComponentDto project2 = componentDbTester.insertComponent(ComponentTesting.newProjectDto());
ComponentDto file2 = componentDbTester.insertComponent(ComponentTesting.newFileDto(project2, null)
ComponentDto project2 = db.components().insertComponent(ComponentTesting.newProjectDto());
ComponentDto file2 = db.components().insertComponent(ComponentTesting.newFileDto(project2, null)
// Simulate file is linked to an invalid project
.setProjectUuid("INVALID"));
addProjectPermissions(project, UserRole.USER);
@@ -307,7 +301,7 @@ public class ServerUserSessionTest {

@Test
public void has_global_permission_for_anonymous() throws Exception {
addAnonymousPermissions(null, "profileadmin", "admin");
addAnyonePermissions(null, "profileadmin", "admin");
UserSession session = newAnonymousSession();

assertThat(session.getLogin()).isNull();
@@ -320,7 +314,7 @@ public class ServerUserSessionTest {

@Test
public void has_project_permission_for_anonymous() throws Exception {
addAnonymousPermissions(project, UserRole.USER);
addAnyonePermissions(project, UserRole.USER);
UserSession session = newAnonymousSession();

assertThat(session.hasComponentPermission(UserRole.USER, FILE_KEY)).isTrue();
@@ -344,20 +338,24 @@ public class ServerUserSessionTest {
addPermissions(component, permissions);
}

private void addPermissions( @Nullable ComponentDto component, String... permissions) {
private void addPermissions(@Nullable ComponentDto component, String... permissions) {
for (String permission : permissions) {
dbClient.userPermissionDao().insert(dbSession, new UserPermissionDto(permission, userDto.getId(), component == null ? null : component.getId()));
if (component == null) {
db.users().insertPermissionOnUser(userDto, permission);
} else {
db.users().insertProjectPermissionOnUser(userDto, permission, component);
}
}
dbSession.commit();
}

private void addAnonymousPermissions(@Nullable ComponentDto component, String... permissions) {
private void addAnyonePermissions(@Nullable ComponentDto component, String... permissions) {
for (String permission : permissions) {
dbClient.roleDao().insertGroupRole(dbSession, new GroupPermissionDto()
.setRole(permission)
.setResourceId(component == null ? null : component.getId()));
if (component == null) {
db.users().insertPermissionOnAnyone(permission);
} else {
db.users().insertProjectPermissionOnAnyone(permission, component);
}
}
dbSession.commit();
}

private void expectInsufficientPrivilegesForbiddenException() {
@@ -365,5 +363,4 @@ public class ServerUserSessionTest {
expectedException.expectMessage("Insufficient privileges");
}


}

+ 84
- 88
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/AddUserActionTest.java View File

@@ -19,164 +19,153 @@
*/
package org.sonar.server.usergroups.ws;

import com.google.common.collect.Multimap;
import java.util.Arrays;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupMembershipDao;
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_LOGIN;

import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;

public class AddUserActionTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public final UserSessionRule userSession = UserSessionRule.standalone();
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public final ExpectedException expectedException = ExpectedException.none();
public ExpectedException expectedException = ExpectedException.none();

private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private WsTester ws;
private GroupDao groupDao;
private UserDao userDao;
private GroupMembershipDao groupMembershipDao;
private UserGroupDao userGroupDao;
private DbSession dbSession;

@Before
public void setUp() {
dbSession = db.getSession();
DbClient dbClient = db.getDbClient();

groupDao = dbClient.groupDao();
userDao = dbClient.userDao();
groupMembershipDao = dbClient.groupMembershipDao();
userGroupDao = dbClient.userGroupDao();

ws = new WsTester(new UserGroupsWs(new AddUserAction(dbClient, new UserGroupFinder(dbClient), userSession)));
ws = new WsTester(new UserGroupsWs(new AddUserAction(db.getDbClient(), userSession, newGroupWsSupport())));
}

@Test
public void add_user_nominal() throws Exception {
GroupDto group = insertGroup("admins");
UserDto user = insertUser("my-admin");
dbSession.commit();
public void add_user_to_group_referenced_by_its_id() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "admins");
UserDto user = db.users().insertUser("my-admin");

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.containsOnly(group.getName());
assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(group.getId());
}

@Test
public void add_user_with_group_name() throws Exception {
GroupDto group = insertGroup("group_name");
UserDto user = insertUser("user_login");
assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.isEmpty();
dbSession.commit();
public void add_user_to_group_referenced_by_its_name() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a-group");
UserDto user = db.users().insertUser("user_login");

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_LOGIN, user.getLogin())
.execute()
.assertNoContent();

assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(group.getId());
}

@Test
public void add_user_to_group_referenced_by_its_name_and_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org, "a-group");
UserDto user = db.users().insertUser("user_login");

loginAsAdmin();
newRequest()
.setParam(PARAM_ORGANIZATION_KEY, org.getKey())
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_LOGIN, user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.containsOnly(group.getName());
assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(group.getId());
}

@Test
public void add_user_to_another_group() throws Exception {
GroupDto admins = insertGroup("admins");
GroupDto users = insertGroup("users");
UserDto user = insertUser("my-admin");
insertMember(users.getId(), user.getId());
dbSession.commit();
OrganizationDto defaultOrg = defaultOrganizationProvider.getDto();
GroupDto admins = db.users().insertGroup(defaultOrg, "admins");
GroupDto users = db.users().insertGroup(defaultOrg, "users");
UserDto user = db.users().insertUser("my-admin");
db.users().insertMember(users, user);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", admins.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.containsOnly(admins.getName(), users.getName());
assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(admins.getId(), users.getId());
}

@Test
public void add_user_already_in_group() throws Exception {
GroupDto users = insertGroup("users");
UserDto user = insertUser("my-admin");
insertMember(users.getId(), user.getId());
dbSession.commit();
public void user_is_already_member_of_group() throws Exception {
GroupDto users = db.users().insertGroup(defaultOrganizationProvider.getDto(), "users");
UserDto user = db.users().insertUser("my-admin");
db.users().insertMember(users, user);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", users.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.containsOnly(users.getName());
// do not insert duplicated row
assertThat(db.users().selectGroupIdsOfUser(user)).hasSize(1).containsOnly(users.getId());
}

@Test
public void add_another_user_to_group() throws Exception {
GroupDto users = insertGroup("user");
UserDto user1 = insertUser("user1");
UserDto user2 = insertUser("user2");
insertMember(users.getId(), user1.getId());
dbSession.commit();
public void group_has_multiple_members() throws Exception {
GroupDto users = db.users().insertGroup(defaultOrganizationProvider.getDto(), "user");
UserDto user1 = db.users().insertUser("user1");
UserDto user2 = db.users().insertUser("user2");
db.users().insertMember(users, user1);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", users.getId().toString())
.setParam("login", user2.getLogin())
.execute()
.assertNoContent();

Multimap<String, String> groupsByLogins = groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user1.getLogin(), user2.getLogin()));
assertThat(groupsByLogins.get(user1.getLogin())).containsOnly(users.getName());
assertThat(groupsByLogins.get(user2.getLogin())).containsOnly(users.getName());
assertThat(db.users().selectGroupIdsOfUser(user1)).containsOnly(users.getId());
assertThat(db.users().selectGroupIdsOfUser(user2)).containsOnly(users.getId());
}

@Test
public void unknown_group() throws Exception {
UserDto user = insertUser("my-admin");
dbSession.commit();
public void fail_if_group_does_not_exist() throws Exception {
UserDto user = db.users().insertUser("my-admin");

expectedException.expect(NotFoundException.class);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", "42")
.setParam("login", user.getLogin())
@@ -184,34 +173,41 @@ public class AddUserActionTest {
}

@Test
public void unknown_user() throws Exception {
GroupDto group = insertGroup("admins");
dbSession.commit();
public void fail_if_user_does_not_exist() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "admins");

expectedException.expect(NotFoundException.class);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.setParam("login", "my-admin")
.execute();
}

@Test
public void fail_if_not_administrator() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "admins");
UserDto user = db.users().insertUser("my-admin");

expectedException.expect(UnauthorizedException.class);

newRequest()
.setParam("id", group.getId().toString())
.setParam("login", user.getLogin())
.execute();
}

private WsTester.TestRequest newRequest() {
return ws.newPostRequest("api/user_groups", "add_user");
}

private GroupDto insertGroup(String groupName) {
return groupDao.insert(dbSession, new GroupDto()
.setName(groupName)
.setDescription(StringUtils.capitalize(groupName)));
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}

private UserDto insertUser(String login) {
return userDao.insert(dbSession, new UserDto().setLogin(login).setName(login).setActive(true));
private GroupWsSupport newGroupWsSupport() {
return new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
}

private void insertMember(long groupId, long userId) {
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(groupId).setUserId(userId));
}
}

+ 96
- 26
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/CreateActionTest.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.usergroups.ws;

import java.net.HttpURLConnection;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -27,16 +26,19 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.organization.DefaultOrganization;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;

public class CreateActionTest {

@@ -47,37 +49,62 @@ public class CreateActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();

private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private WsTester ws;
private GroupDao groupDao;
private DbSession dbSession;

@Before
public void setUp() {
DbClient dbClient = db.getDbClient();
groupDao = dbClient.groupDao();
dbSession = db.getSession();
ws = new WsTester(new UserGroupsWs(new CreateAction(db.getDbClient(), userSession, newGroupWsSupport())));
}

@Test
public void create_group_on_default_organization() throws Exception {
loginAsAdmin();

ws = new WsTester(new UserGroupsWs(new CreateAction(dbClient, userSession, new UserGroupUpdater(dbClient))));
newRequest()
.setParam("name", "some-product-bu")
.setParam("description", "Business Unit for Some Awesome Product")
.execute()
.assertJson("{" +
" \"group\": {" +
" \"organization\": \"" + getDefaultOrganization().getKey() + "\"," +
" \"name\": \"some-product-bu\"," +
" \"description\": \"Business Unit for Some Awesome Product\"," +
" \"membersCount\": 0" +
" }" +
"}");

assertThat(db.users().selectGroup(defaultOrganizationProvider.getDto(), "some-product-bu")).isPresent();
}

@Test
public void create_nominal() throws Exception {
public void create_group_on_specific_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());

loginAsAdmin();
newRequest()
.setParam("organization", org.getKey())
.setParam("name", "some-product-bu")
.setParam("description", "Business Unit for Some Awesome Product")
.execute().assertJson("{" +
.execute()
.assertJson("{" +
" \"group\": {" +
" \"organization\": \"" + org.getKey() + "\"," +
" \"name\": \"some-product-bu\"," +
" \"description\": \"Business Unit for Some Awesome Product\"," +
" \"membersCount\": 0" +
" }" +
"}");

GroupDto createdGroup = db.users().selectGroup(org, "some-product-bu").get();
assertThat(createdGroup.getId()).isNotNull();
assertThat(createdGroup.getOrganizationUuid()).isEqualTo(org.getUuid());
}

@Test(expected = ForbiddenException.class)
public void require_admin_permission() throws Exception {
userSession.login("not-admin");

newRequest()
.setParam("name", "some-product-bu")
.setParam("description", "Business Unit for Some Awesome Product")
@@ -85,7 +112,7 @@ public class CreateActionTest {
}

@Test(expected = IllegalArgumentException.class)
public void name_too_short() throws Exception {
public void fail_if_name_is_too_short() throws Exception {
loginAsAdmin();
newRequest()
.setParam("name", "")
@@ -93,7 +120,7 @@ public class CreateActionTest {
}

@Test(expected = IllegalArgumentException.class)
public void name_too_long() throws Exception {
public void fail_if_name_is_too_long() throws Exception {
loginAsAdmin();
newRequest()
.setParam("name", StringUtils.repeat("a", 255 + 1))
@@ -101,7 +128,7 @@ public class CreateActionTest {
}

@Test(expected = IllegalArgumentException.class)
public void forbidden_name() throws Exception {
public void fail_if_name_is_anyone() throws Exception {
loginAsAdmin();
newRequest()
.setParam("name", "AnYoNe")
@@ -109,27 +136,62 @@ public class CreateActionTest {
}

@Test
public void non_unique_name() throws Exception {
String groupName = "conflicting-name";
groupDao.insert(dbSession, new GroupDto()
.setName(groupName));
db.commit();
public void fail_if_group_with_same_name_already_exists() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "the-group");

expectedException.expect(ServerException.class);
expectedException.expectMessage("already taken");
expectedException.expectMessage("Group '" + group.getName() + "' already exists");

loginAsAdmin();
newRequest()
.setParam("name", groupName)
.execute().assertStatus(HttpURLConnection.HTTP_CONFLICT);
.setParam("name", group.getName())
.execute();
}

@Test
public void fail_if_group_with_same_name_already_exists_in_the_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org, "the-group");

expectedException.expect(ServerException.class);
expectedException.expectMessage("Group '" + group.getName() + "' already exists");

loginAsAdmin();
newRequest()
.setParam("organization", org.getKey())
.setParam("name", group.getName())
.execute();
}

@Test
public void add_group_with_a_name_that_already_exists_in_another_organization() throws Exception {
String name = "the-group";
OrganizationDto org1 = OrganizationTesting.insert(db, newOrganizationDto());
OrganizationDto org2 = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org1, name);

loginAsAdmin();
newRequest()
.setParam("organization", org2.getKey())
.setParam("name", name)
.execute()
.assertJson("{" +
" \"group\": {" +
" \"organization\": \"" + org2.getKey() + "\"," +
" \"name\": \"" + group.getName() + "\"," +
" }" +
"}");

assertThat(db.users().selectGroups(org1)).extracting(GroupDto::getName).containsOnly(name);
assertThat(db.users().selectGroups(org2)).extracting(GroupDto::getName).containsOnly(name);
}

@Test(expected = IllegalArgumentException.class)
public void description_too_long() throws Exception {
public void fail_if_description_is_too_long() throws Exception {
loginAsAdmin();
newRequest()
.setParam("name", "long-group-description-is-looooooooooooong")
.setParam("description", StringUtils.repeat("a", 200 + 1))
.setParam("name", "long-desc")
.setParam("description", StringUtils.repeat("a", 1_000))
.execute();
}

@@ -140,4 +202,12 @@ public class CreateActionTest {
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}

private GroupWsSupport newGroupWsSupport() {
return new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
}

private DefaultOrganization getDefaultOrganization() {
return defaultOrganizationProvider.get();
}
}

+ 118
- 84
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/DeleteActionTest.java View File

@@ -28,30 +28,24 @@ import org.sonar.api.config.MapSettings;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.permission.GroupPermissionDao;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.user.GroupDao;
import org.sonar.db.user.GroupDbTester;
import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.RoleDao;
import org.sonar.db.user.UserDbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;

public class DeleteActionTest {

@@ -61,127 +55,164 @@ public class DeleteActionTest {
public ExpectedException expectedException = ExpectedException.none();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
GroupDbTester groupDb = new GroupDbTester(db);
UserDbTester userDb = new UserDbTester(db);
DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();
GroupDao groupDao = dbClient.groupDao();
UserGroupDao userGroupDao = dbClient.userGroupDao();
RoleDao roleDao = dbClient.roleDao();
PermissionTemplateDao permissionTemplateDao = dbClient.permissionTemplateDao();
GroupPermissionDao groupPermissionDao = dbClient.groupPermissionDao();

private ComponentDbTester componentTester = new ComponentDbTester(db);
private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private GroupDto defaultGroup;
private WsTester ws;
private Long defaultGroupId;

@Before
public void setUp() {
defaultGroup = db.users().insertGroup(defaultOrganizationProvider.getDto(), CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE);
Settings settings = new MapSettings().setProperty(CoreProperties.CORE_DEFAULT_GROUP, CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE);
GroupDto defaultGroup = groupDao.insert(dbSession, new GroupDto().setName(CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE));
defaultGroupId = defaultGroup.getId();
dbSession.commit();

ws = new WsTester(new UserGroupsWs(
new DeleteAction(
dbClient,
new UserGroupFinder(dbClient),
db.getDbClient(),
userSession,
settings)));
newGroupWsSupport(),
settings, defaultOrganizationProvider)));
}

@Test
public void delete_simple() throws Exception {
GroupDto group = groupDao.insert(dbSession, new GroupDto().setName("to-delete"));
dbSession.commit();
public void delete_by_id() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "to-delete");

loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.execute().assertNoContent();
.execute()
.assertNoContent();

assertThat(db.users().selectGroupById(group.getId())).isNull();
}

@Test
public void delete_with_group_name() throws Exception {
GroupDto group = groupDao.insert(dbSession, newGroupDto().setName("group_name"));
assertThat(groupDao.selectById(dbSession, group.getId())).isNotNull();
dbSession.commit();
public void delete_by_name_on_default_organization() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "to-delete");

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
.execute().assertNoContent();
.execute()
.assertNoContent();

assertThat(db.users().selectGroupById(group.getId())).isNull();
}

@Test
public void delete_by_name_and_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org, "to-delete");

loginAsAdmin();
newRequest()
.setParam(PARAM_ORGANIZATION_KEY, org.getKey())
.setParam(PARAM_GROUP_NAME, group.getName())
.execute()
.assertNoContent();

assertThat(db.users().selectGroupById(group.getId())).isNull();
}

@Test
public void delete_by_name_fails_if_organization_is_not_correct() throws Exception {
OrganizationDto org = newOrganizationDto().setUuid("org1");
OrganizationTesting.insert(db, org);

loginAsAdmin();

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("No organization with key 'org1'");

assertThat(groupDao.selectById(dbSession, group.getId())).isNull();
newRequest()
.setParam(PARAM_ORGANIZATION_KEY, "org1")
.setParam(PARAM_GROUP_NAME, "a-group")
.execute();
}

@Test
public void delete_with_members() throws Exception {
GroupDto group = groupDao.insert(dbSession, new GroupDto().setName("to-delete"));
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(group.getId()).setUserId(42L));
dbSession.commit();
public void delete_members() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "to-be-deleted");
UserDto user = db.users().insertUser("a-user");
db.users().insertMember(group, user);

loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.execute().assertNoContent();
.execute()
.assertNoContent();

assertThat(db.select("SELECT group_id FROM groups_users")).isEmpty();
assertThat(db.countRowsOfTable("groups_users")).isEqualTo(0);
}

@Test
public void delete_with_permissions() throws Exception {
GroupDto group = groupDao.insert(dbSession, new GroupDto().setName("to-delete"));
roleDao.insertGroupRole(dbSession, new GroupPermissionDto().setGroupId(group.getId()).setResourceId(42L).setRole(UserRole.ADMIN));
dbSession.commit();
public void delete_permissions() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "to-be-deleted");
ComponentDto project = componentTester.insertComponent(ComponentTesting.newProjectDto());
db.users().insertProjectPermissionOnGroup(group, UserRole.ADMIN, project);

loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.execute().assertNoContent();
.execute()
.assertNoContent();

assertThat(db.select("SELECT group_id FROM group_roles")).isEmpty();
assertThat(db.countRowsOfTable("group_roles")).isEqualTo(0);
}

@Test
public void delete_with_permission_templates() throws Exception {
GroupDto group = groupDao.insert(dbSession, new GroupDto().setName("to-delete"));
permissionTemplateDao.insertGroupPermission(dbSession, 42L, group.getId(), UserRole.ADMIN);
dbSession.commit();
public void delete_permission_templates() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "to-be-deleted");
// TODO

loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.execute().assertNoContent();

assertThat(db.select("SELECT group_id FROM perm_templates_groups")).isEmpty();
assertThat(db.countRowsOfTable("perm_templates_groups")).isEqualTo(0);
}

@Test(expected = NotFoundException.class)
public void not_found() throws Exception {
public void fail_if_id_does_not_exist() throws Exception {
loginAsAdmin();
newRequest()
.setParam("id", String.valueOf(defaultGroupId + 1L))
.setParam("id", String.valueOf(defaultGroup.getId() + 123))
.execute();
}

@Test(expected = IllegalArgumentException.class)
public void cannot_delete_default_group() throws Exception {
public void cannot_delete_default_group_of_default_organization() throws Exception {
loginAsAdmin();
newRequest()
.setParam("id", defaultGroup.getId().toString())
.execute();
}

@Test
public void delete_group_of_an_organization_even_if_name_is_default_group_of_default_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org, defaultGroup.getName());

loginAsAdmin();
newRequest()
.setParam("id", defaultGroupId.toString())
.setParam("id", group.getId().toString())
.execute();

assertThat(db.users().selectGroupById(defaultGroup.getId())).isNotNull();
assertThat(db.users().selectGroupById(group.getId())).isNull();
}

@Test
public void cannot_delete_last_system_admin_group() throws Exception {
GroupDto group = groupDb.insertGroup(newGroupDto().setName("system-admins"));
roleDao.insertGroupRole(dbSession, new GroupPermissionDto().setGroupId(group.getId()).setRole(GlobalPermissions.SYSTEM_ADMIN));
assertThat(groupPermissionDao.countGroups(dbSession, GlobalPermissions.SYSTEM_ADMIN, null)).isEqualTo(1);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "system-admins");
db.users().insertPermissionOnGroup(group, SYSTEM_ADMIN);

loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The last system admin group 'system-admins' cannot be deleted");
expectedException.expectMessage("The last system admin group cannot be deleted");

newRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
@@ -189,12 +220,12 @@ public class DeleteActionTest {
}

@Test
public void can_delete_system_admin_group_if_not_last() throws Exception {
GroupDto funkyAdmins = groupDb.insertGroup(newGroupDto().setName("funky-admins"));
roleDao.insertGroupRole(dbSession, new GroupPermissionDto().setGroupId(funkyAdmins.getId()).setRole(GlobalPermissions.SYSTEM_ADMIN));
GroupDto boringAdmins = groupDb.insertGroup(newGroupDto().setName("boring-admins"));
roleDao.insertGroupRole(dbSession, new GroupPermissionDto().setGroupId(boringAdmins.getId()).setRole(GlobalPermissions.SYSTEM_ADMIN));
dbSession.commit();
public void delete_system_admin_group_if_not_last() throws Exception {
OrganizationDto defaultOrg = defaultOrganizationProvider.getDto();
GroupDto funkyAdmins = db.users().insertGroup(defaultOrg, "funky-admins");
db.users().insertPermissionOnGroup(funkyAdmins, SYSTEM_ADMIN);
GroupDto boringAdmins = db.users().insertGroup(defaultOrg, "boring-admins");
db.users().insertPermissionOnGroup(boringAdmins, SYSTEM_ADMIN);

loginAsAdmin();

@@ -202,29 +233,32 @@ public class DeleteActionTest {
.setParam(PARAM_GROUP_NAME, boringAdmins.getName())
.execute();

assertThat(groupPermissionDao.countGroups(dbSession, GlobalPermissions.SYSTEM_ADMIN, null)).isEqualTo(1);
assertThat(db.getDbClient().groupPermissionDao().countGroups(db.getSession(), SYSTEM_ADMIN, null)).isEqualTo(1);
}

@Test
public void can_delete_last_system_admin_group_if_admin_user_left() throws Exception {
GroupDto lastGroup = groupDb.insertGroup(newGroupDto().setName("last-group"));
roleDao.insertGroupRole(dbSession, new GroupPermissionDto().setGroupId(lastGroup.getId()).setRole(GlobalPermissions.SYSTEM_ADMIN));
UserDto bigBoss = userDb.insertUser(newUserDto("big.boss", "Big Boss", "big@boss.com"));
dbClient.userPermissionDao().insert(dbSession, new UserPermissionDto(GlobalPermissions.SYSTEM_ADMIN, bigBoss.getId(), null));
dbSession.commit();
public void delete_last_system_admin_group_if_admin_user_left() throws Exception {
GroupDto lastGroup = db.users().insertGroup(defaultOrganizationProvider.getDto(), "last-group");
db.users().insertPermissionOnGroup(lastGroup, SYSTEM_ADMIN);
UserDto bigBoss = db.users().insertUser("big.boss");
db.users().insertPermissionOnUser(bigBoss, SYSTEM_ADMIN);

loginAsAdmin();

newRequest().setParam(PARAM_GROUP_NAME, lastGroup.getName()).execute();

assertThat(groupDao.selectById(dbSession, lastGroup.getId())).isNull();
assertThat(db.users().selectGroupById(lastGroup.getId())).isNull();
}

private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
}

private WsTester.TestRequest newRequest() {
return ws.newPostRequest("api/user_groups", "delete");
}

private GroupWsSupport newGroupWsSupport() {
return new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
}

}

+ 89
- 0
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/GroupWsRefTest.java View File

@@ -0,0 +1,89 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.usergroups.ws;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.usergroups.ws.GroupWsRef.fromName;

public class GroupWsRefTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void test_ref_by_id() {
GroupWsRef ref = GroupWsRef.fromId(10L);
assertThat(ref.hasId()).isTrue();
assertThat(ref.getId()).isEqualTo(10L);
assertThat(ref.isAnyone()).isFalse();
}

@Test
public void test_ref_by_name() {
GroupWsRef ref = fromName("ORG1", "the-group");
assertThat(ref.hasId()).isFalse();
assertThat(ref.getOrganizationKey()).isEqualTo("ORG1");
assertThat(ref.getName()).isEqualTo("the-group");
assertThat(ref.isAnyone()).isFalse();
}

@Test
public void test_equals_and_hashCode() {
GroupWsRef refId1 = GroupWsRef.fromId(10L);
GroupWsRef refId2 = GroupWsRef.fromId(11L);
assertThat(refId1.equals(refId1)).isTrue();
assertThat(refId1.equals(GroupWsRef.fromId(10L))).isTrue();
assertThat(refId1.hashCode()).isEqualTo(GroupWsRef.fromId(10L).hashCode());
assertThat(refId1.equals(refId2)).isFalse();

GroupWsRef refName1 = fromName("ORG1", "the-group");
GroupWsRef refName2 = fromName("ORG1", "the-group2");
GroupWsRef refName3 = fromName("ORG2", "the-group2");
assertThat(refName1.equals(refName1)).isTrue();
assertThat(refName1.equals(fromName("ORG1", "the-group"))).isTrue();
assertThat(refName1.hashCode()).isEqualTo(fromName("ORG1", "the-group").hashCode());
assertThat(refName1.equals(refName2)).isFalse();
assertThat(refName2.equals(refName3)).isFalse();
}

@Test
public void test_toString() {
GroupWsRef refId = GroupWsRef.fromId(10L);
assertThat(refId.toString()).isEqualTo("GroupWsRef{id=10, organizationKey='null', name='null'}");
}

@Test
public void reference_anyone_by_its_name() {
GroupWsRef ref = GroupWsRef.fromName("my-org", "Anyone");
assertThat(ref.getOrganizationKey()).isEqualTo("my-org");
assertThat(ref.getName()).isEqualTo("Anyone");
assertThat(ref.isAnyone()).isTrue();

// case-insensitive
ref = GroupWsRef.fromName("my-org", "anyone");
assertThat(ref.getOrganizationKey()).isEqualTo("my-org");
assertThat(ref.getName()).isEqualTo("anyone");
assertThat(ref.isAnyone()).isTrue();
}
}

+ 63
- 82
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/RemoveUserActionTest.java View File

@@ -19,145 +19,136 @@
*/
package org.sonar.server.usergroups.ws;

import java.util.Arrays;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupMembershipDao;
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_LOGIN;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;

public class RemoveUserActionTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public final UserSessionRule userSession = UserSessionRule.standalone();
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public final ExpectedException expectedException = ExpectedException.none();
public ExpectedException expectedException = ExpectedException.none();

private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private WsTester ws;
private GroupDao groupDao;
private UserDao userDao;
private GroupMembershipDao groupMembershipDao;
private UserGroupDao userGroupDao;
private DbSession dbSession;

@Before
public void setUp() {
dbSession = db.getSession();

org.sonar.db.DbClient dbClient = db.getDbClient();
groupDao = dbClient.groupDao();
userDao = dbClient.userDao();
groupMembershipDao = dbClient.groupMembershipDao();
userGroupDao = dbClient.userGroupDao();

ws = new WsTester(new UserGroupsWs(new RemoveUserAction(dbClient, userSession)));
GroupWsSupport groupSupport = new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
ws = new WsTester(new UserGroupsWs(new RemoveUserAction(db.getDbClient(), userSession, groupSupport)));
}

@Test
public void remove_user_not_in_group() throws Exception {
GroupDto group = insertGroup("admins");
UserDto user = insertUser("my-admin");
dbSession.commit();
public void does_nothing_if_user_is_not_in_group() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "admins");
UserDto user = db.users().insertUser("my-admin");

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.isEmpty();
assertThat(db.users().selectGroupIdsOfUser(user)).isEmpty();
}

@Test
public void remove_user_nominal() throws Exception {
GroupDto users = insertGroup("users");
UserDto user = insertUser("my-admin");
insertMember(users.getId(), user.getId());
dbSession.commit();

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
public void remove_user_by_group_id() throws Exception {
GroupDto users = db.users().insertGroup(defaultOrganizationProvider.getDto(), "users");
UserDto user = db.users().insertUser("my-admin");
db.users().insertMember(users, user);

loginAsAdmin();
newRequest()
.setParam("id", users.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.isEmpty();
assertThat(db.users().selectGroupIdsOfUser(user)).isEmpty();
}

@Test
public void remove_user_by_group_name() throws Exception {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
GroupDto group = insertGroup("group_name");
UserDto user = insertUser("user_login");
insertMember(group.getId(), user.getId());
assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.isNotEmpty();
db.commit();
public void remove_user_by_group_name_in_default_organization() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "group_name");
UserDto user = db.users().insertUser("user_login");
db.users().insertMember(group, user);

loginAsAdmin();
newRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_LOGIN, user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.isEmpty();
assertThat(db.users().selectGroupIdsOfUser(user)).isEmpty();
}

@Test
public void remove_user_only_from_one_group() throws Exception {
GroupDto users = insertGroup("user");
GroupDto admins = insertGroup("admins");
UserDto user = insertUser("user");
insertMember(users.getId(), user.getId());
insertMember(admins.getId(), user.getId());
dbSession.commit();
public void remove_user_by_group_name_in_specific_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, OrganizationTesting.newOrganizationDto());
GroupDto group = db.users().insertGroup(org, "a_group");
UserDto user = db.users().insertUser("user_login");
db.users().insertMember(group, user);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam(PARAM_ORGANIZATION_KEY, org.getKey())
.setParam(PARAM_GROUP_NAME, group.getName())
.setParam(PARAM_LOGIN, user.getLogin())
.execute()
.assertNoContent();

assertThat(db.users().selectGroupIdsOfUser(user)).isEmpty();
}

@Test
public void remove_user_only_from_one_group() throws Exception {
OrganizationDto defaultOrg = defaultOrganizationProvider.getDto();
GroupDto users = db.users().insertGroup(defaultOrg, "user");
GroupDto admins = db.users().insertGroup(defaultOrg, "admins");
UserDto user = db.users().insertUser("user");
db.users().insertMember(users, user);
db.users().insertMember(admins, user);

loginAsAdmin();
newRequest()
.setParam("id", admins.getId().toString())
.setParam("login", user.getLogin())
.execute()
.assertNoContent();

assertThat(groupMembershipDao.selectGroupsByLogins(dbSession, Arrays.asList(user.getLogin())).get(user.getLogin()))
.containsOnly(users.getName());
assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(users.getId());
}

@Test
public void unknown_group() throws Exception {
UserDto user = insertUser("my-admin");
dbSession.commit();
public void fail_if_unknown_group() throws Exception {
UserDto user = db.users().insertUser("my-admin");

expectedException.expect(NotFoundException.class);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", "42")
.setParam("login", user.getLogin())
@@ -165,13 +156,12 @@ public class RemoveUserActionTest {
}

@Test
public void unknown_user() throws Exception {
GroupDto group = insertGroup("admins");
dbSession.commit();
public void fail_if_unknown_user() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "admins");

expectedException.expect(NotFoundException.class);

userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.setParam("login", "my-admin")
@@ -182,17 +172,8 @@ public class RemoveUserActionTest {
return ws.newPostRequest("api/user_groups", "remove_user");
}

private GroupDto insertGroup(String groupName) {
return groupDao.insert(dbSession, new GroupDto()
.setName(groupName)
.setDescription(StringUtils.capitalize(groupName)));
}

private UserDto insertUser(String login) {
return userDao.insert(dbSession, new UserDto().setLogin(login).setName(login).setActive(true));
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}

private void insertMember(long groupId, long userId) {
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(groupId).setUserId(userId));
}
}

+ 61
- 49
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java View File

@@ -19,27 +19,27 @@
*/
package org.sonar.server.usergroups.ws;

import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;

import static org.apache.commons.lang.StringUtils.capitalize;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;
import static org.sonar.db.user.GroupTesting.newGroupDto;


public class SearchActionTest {

@Rule
@@ -53,19 +53,9 @@ public class SearchActionTest {

private WsTester ws;

private GroupDao groupDao;
private UserGroupDao userGroupDao;
private DbSession dbSession;

@Before
public void setUp() {
DbClient dbClient = db.getDbClient();
groupDao = dbClient.groupDao();
userGroupDao = dbClient.userGroupDao();

ws = new WsTester(new UserGroupsWs(new SearchAction(dbClient, userSession)));

dbSession = dbClient.openSession(false);
ws = new WsTester(new UserGroupsWs(new SearchAction(db.getDbClient(), userSession, newGroupWsSupport())));
}

@Test
@@ -76,40 +66,49 @@ public class SearchActionTest {

@Test
public void search_without_parameters() throws Exception {
loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
dbSession.commit();
insertGroup(db.getDefaultOrganization(), "users", 0);
insertGroup(db.getDefaultOrganization(), "admins", 0);
insertGroup(db.getDefaultOrganization(), "customer1", 0);
insertGroup(db.getDefaultOrganization(), "customer2", 0);
insertGroup(db.getDefaultOrganization(), "customer3", 0);

loginAsSimpleUser();
newRequest().execute().assertJson(getClass(), "five_groups.json");
}

@Test
public void search_with_members() throws Exception {
loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
insertMembers("users", 5);
insertMembers("admins", 1);
insertMembers("customer2", 4);
dbSession.commit();
insertGroup(db.getDefaultOrganization(), "users", 5);
insertGroup(db.getDefaultOrganization(), "admins", 1);
insertGroup(db.getDefaultOrganization(), "customer1", 0);
insertGroup(db.getDefaultOrganization(), "customer2", 4);
insertGroup(db.getDefaultOrganization(), "customer3", 0);

loginAsSimpleUser();
newRequest().execute().assertJson(getClass(), "with_members.json");
}

@Test
public void search_with_query() throws Exception {
loginAsSimpleUser();
insertGroups("users", "admins", "customer%_%/1", "customer%_%/2", "customer%_%/3");
dbSession.commit();
insertGroup(db.getDefaultOrganization(), "users", 0);
insertGroup(db.getDefaultOrganization(), "admins", 0);
insertGroup(db.getDefaultOrganization(), "customer%_%/1", 0);
insertGroup(db.getDefaultOrganization(), "customer%_%/2", 0);
insertGroup(db.getDefaultOrganization(), "customer%_%/3", 0);

loginAsSimpleUser();
newRequest().setParam(Param.TEXT_QUERY, "tomer%_%/").execute().assertJson(getClass(), "customers.json");
}

@Test
public void search_with_paging() throws Exception {
loginAsSimpleUser();
insertGroups("users", "admins", "customer1", "customer2", "customer3");
dbSession.commit();
insertGroup(db.getDefaultOrganization(), "users", 0);
insertGroup(db.getDefaultOrganization(), "admins", 0);
insertGroup(db.getDefaultOrganization(), "customer1", 0);
insertGroup(db.getDefaultOrganization(), "customer2", 0);
insertGroup(db.getDefaultOrganization(), "customer3", 0);

loginAsSimpleUser();
newRequest()
.setParam(Param.PAGE_SIZE, "3").execute().assertJson(getClass(), "page_1.json");
newRequest()
@@ -120,10 +119,9 @@ public class SearchActionTest {

@Test
public void search_with_fields() throws Exception {
loginAsSimpleUser();
insertGroups("sonar-users");
dbSession.commit();
insertGroup(db.getDefaultOrganization(), "sonar-users", 0);

loginAsSimpleUser();
assertThat(newRequest().execute().outputAsString())
.contains("id")
.contains("name")
@@ -156,7 +154,23 @@ public class SearchActionTest {
}

@Test
public void fail_when_not_logged() throws Exception {
public void search_in_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
GroupDto group = db.users().insertGroup(org, "users");
// the group in default org is not returned
db.users().insertGroup(db.getDefaultOrganization(), "users");

loginAsSimpleUser();
newRequest()
.setParam("organization", org.getKey())
.execute()
.assertJson(
"{\"total\":1,\"p\":1,\"ps\":100," +
"\"groups\":[{\"id\":\"" + group.getId() + "\",\"name\":\"users\"}]}\n");
}

@Test
public void fail_when_not_logged_in() throws Exception {
userSession.anonymous();

expectedException.expect(UnauthorizedException.class);
@@ -167,18 +181,12 @@ public class SearchActionTest {
return ws.newGetRequest("api/user_groups", "search");
}

private void insertGroups(String... groupNames) {
for (String groupName : groupNames) {
groupDao.insert(dbSession, newGroupDto()
.setName(groupName)
.setDescription(StringUtils.capitalize(groupName)));
}
}

private void insertMembers(String groupName, int count) {
long groupId = groupDao.selectOrFailByName(dbSession, groupName).getId();
for (int i = 0; i < count; i++) {
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(groupId).setUserId((long) i + 1));
private void insertGroup(OrganizationDto org, String name, int numberOfMembers) {
GroupDto group = newGroupDto().setName(name).setDescription(capitalize(name)).setOrganizationUuid(org.getUuid());
db.users().insertGroup(group);
for (int i = 0; i < numberOfMembers; i++) {
UserDto user = db.users().insertUser();
db.users().insertMember(group, user);
}
}

@@ -186,4 +194,8 @@ public class SearchActionTest {
userSession.login("user");
}

private GroupWsSupport newGroupWsSupport() {
return new GroupWsSupport(db.getDbClient(), DefaultOrganizationProviderRule.create(db));
}

}

+ 80
- 71
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UpdateActionTest.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.usergroups.ws;

import java.net.HttpURLConnection;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -27,16 +26,16 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDao;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserGroupDao;
import org.sonar.db.user.UserGroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
@@ -47,42 +46,40 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto;

public class UpdateActionTest {

static final String DEFAULT_GROUP_NAME_KEY = "sonar.defaultGroup";
static final String DEFAULT_GROUP_NAME_VALUE = "DEFAULT_GROUP_NAME_VALUE";
private static final String DEFAULT_GROUP_NAME_KEY = "sonar.defaultGroup";
private static final String DEFAULT_GROUP_NAME_VALUE = "DEFAULT_GROUP_NAME_VALUE";

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();

@Rule
public ExpectedException expectedException = ExpectedException.none();
DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();
GroupDao groupDao = dbClient.groupDao();
UserGroupDao userGroupDao = dbClient.userGroupDao();

PersistentSettings settings = mock(PersistentSettings.class);
WsTester ws = new WsTester(new UserGroupsWs(new UpdateAction(dbClient, userSession, new UserGroupUpdater(dbClient), settings)));
private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private PersistentSettings settings = mock(PersistentSettings.class);
private WsTester ws = new WsTester(new UserGroupsWs(new UpdateAction(db.getDbClient(), userSession, new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider), settings, defaultOrganizationProvider)));

@Before
public void setUp() throws Exception {
GroupWsSupport groupSupport = new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
ws = new WsTester(new UserGroupsWs(new UpdateAction(db.getDbClient(), userSession, groupSupport, settings, defaultOrganizationProvider)));
when(settings.getString(DEFAULT_GROUP_NAME_KEY)).thenReturn(DEFAULT_GROUP_NAME_VALUE);
}

@Test
public void update_nominal() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
userGroupDao.insert(dbSession, new UserGroupDto().setGroupId(existingGroup.getId()).setUserId(42L));

dbSession.commit();
public void update_both_name_and_description() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "Initial Name");
UserDto user = db.users().insertUser();
db.users().insertMember(group, user);

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "new-name")
.setParam("description", "New Description")
.execute().assertJson("{" +
@@ -96,17 +93,16 @@ public class UpdateActionTest {

@Test
public void update_only_name() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "Initial Name");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "new-name")
.execute().assertJson("{" +
" \"group\": {" +
" \"name\": \"new-name\"," +
" \"description\": \"Old Description\"," +
" \"description\": \"" + group.getDescription() + "\"," +
" \"membersCount\": 0" +
" }" +
"}");
@@ -114,16 +110,15 @@ public class UpdateActionTest {

@Test
public void update_only_description() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "Initial Name");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("description", "New Description")
.execute().assertJson("{" +
" \"group\": {" +
" \"name\": \"old-name\"," +
" \"name\": \"" + group.getName() + "\"," +
" \"description\": \"New Description\"," +
" \"membersCount\": 0" +
" }" +
@@ -132,12 +127,11 @@ public class UpdateActionTest {

@Test
public void update_default_group_name_also_update_default_group_property() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName(DEFAULT_GROUP_NAME_VALUE).setDescription("Default group name"));
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), DEFAULT_GROUP_NAME_VALUE);

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "new-name")
.execute();

@@ -147,12 +141,27 @@ public class UpdateActionTest {
@Test
public void update_default_group_name_does_not_update_default_group_setting_when_null() throws Exception {
when(settings.getString(DEFAULT_GROUP_NAME_KEY)).thenReturn(null);
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName(DEFAULT_GROUP_NAME_VALUE).setDescription("Default group name"));
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), DEFAULT_GROUP_NAME_VALUE);

loginAsAdmin();
newRequest()
.setParam("id", group.getId().toString())
.setParam("name", "new-name")
.execute();

verify(settings, never()).saveProperty(any(DbSession.class), eq(DEFAULT_GROUP_NAME_KEY), eq("new-name"));
}

@Test
public void do_not_update_default_group_of_default_organization_if_updating_group_on_non_default_organization() throws Exception {
OrganizationDto org = OrganizationTesting.insert(db, newOrganizationDto());
when(settings.getString(DEFAULT_GROUP_NAME_KEY)).thenReturn(DEFAULT_GROUP_NAME_VALUE);
GroupDto groupInDefaultOrg = db.users().insertGroup(defaultOrganizationProvider.getDto(), DEFAULT_GROUP_NAME_VALUE);
GroupDto group = db.users().insertGroup(org, DEFAULT_GROUP_NAME_VALUE);

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "new-name")
.execute();

@@ -161,9 +170,10 @@ public class UpdateActionTest {

@Test
public void require_admin_permission() throws Exception {
userSession.login("not-admin");

expectedException.expect(ForbiddenException.class);

userSession.login("not-admin");
newRequest()
.setParam("id", "42")
.setParam("name", "some-product-bu")
@@ -172,85 +182,86 @@ public class UpdateActionTest {
}

@Test
public void name_too_short() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
public void fail_if_name_is_too_short() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a name");
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Group name cannot be empty");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "")
.execute();
}

@Test
public void name_too_long() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
public void fail_if_name_is_too_long() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a name");
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Group name cannot be longer than 255 characters");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", StringUtils.repeat("a", 255 + 1))
.execute();
}

@Test
public void forbidden_name() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
public void fail_if_new_name_is_anyone() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a name");
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Anyone group cannot be used");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "AnYoNe")
.execute();
}

@Test
public void non_unique_name() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
String groupName = "conflicting-name";
groupDao.insert(dbSession, new GroupDto()
.setName(groupName));
dbSession.commit();
public void fail_to_update_if_name_already_exists() throws Exception {
OrganizationDto defaultOrg = defaultOrganizationProvider.getDto();
GroupDto groupToBeRenamed = db.users().insertGroup(defaultOrg, "a name");
String newName = "new-name";
db.users().insertGroup(defaultOrg, newName);
loginAsAdmin();

expectedException.expect(ServerException.class);
expectedException.expectMessage("already taken");
expectedException.expectMessage("Group 'new-name' already exists");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("name", groupName)
.execute().assertStatus(HttpURLConnection.HTTP_CONFLICT);
.setParam("id", groupToBeRenamed.getId().toString())
.setParam("name", newName)
.execute();
}

@Test
public void description_too_long() throws Exception {
GroupDto existingGroup = groupDao.insert(dbSession, new GroupDto().setName("old-name").setDescription("Old Description"));
dbSession.commit();
public void fail_if_description_is_too_long() throws Exception {
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a name");
loginAsAdmin();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Description cannot be longer than 200 characters");

loginAsAdmin();
newRequest()
.setParam("id", existingGroup.getId().toString())
.setParam("id", group.getId().toString())
.setParam("name", "long-group-description-is-looooooooooooong")
.setParam("description", StringUtils.repeat("a", 200 + 1))
.setParam("description", StringUtils.repeat("a", 201))
.execute();
}

@Test
public void unknown_group() throws Exception {
public void fail_if_unknown_group() throws Exception {
loginAsAdmin();

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Could not find a user group with id '42'.");

loginAsAdmin();
newRequest()
.setParam("id", "42")
.execute();
@@ -263,6 +274,4 @@ public class UpdateActionTest {
private void loginAsAdmin() {
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
}


}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsModuleTest.java View File

@@ -29,6 +29,6 @@ public class UserGroupsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new UserGroupsModule().configure(container);
assertThat(container.size()).isEqualTo(12);
assertThat(container.size()).isEqualTo(11);
}
}

+ 5
- 4
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java View File

@@ -40,9 +40,10 @@ public class UserGroupsWsTest {

@Before
public void setUp() {
GroupWsSupport wsSupport = mock(GroupWsSupport.class);
WsTester tester = new WsTester(new UserGroupsWs(
new SearchAction(mock(DbClient.class), mock(UserSession.class)),
new CreateAction(mock(DbClient.class), mock(UserSession.class), mock(UserGroupUpdater.class))));
new SearchAction(mock(DbClient.class), mock(UserSession.class), wsSupport),
new CreateAction(mock(DbClient.class), mock(UserSession.class), wsSupport)));
controller = tester.controller("api/user_groups");
}

@@ -59,7 +60,7 @@ public class UserGroupsWsTest {
WebService.Action action = controller.action("search");
assertThat(action).isNotNull();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.params()).hasSize(4);
assertThat(action.params()).hasSize(5);
}

@Test
@@ -68,6 +69,6 @@ public class UserGroupsWsTest {
assertThat(action).isNotNull();
assertThat(action.isPost()).isTrue();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.params()).hasSize(2);
assertThat(action.params()).hasSize(3);
}
}

+ 37
- 62
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java View File

@@ -26,21 +26,19 @@ import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProviderRule;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsTester;
import org.sonar.server.ws.WsTester.TestRequest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.usergroups.ws.UserGroupsWsParameters.PARAM_GROUP_NAME;
import static org.sonar.db.user.UserTesting.newUserDto;
import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_GROUP_NAME;

public class UsersActionTest {

@@ -48,34 +46,30 @@ public class UsersActionTest {
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();

WsTester wsTester;
DbClient dbClient;
DbSession dbSession;
private DefaultOrganizationProviderRule defaultOrganizationProvider = DefaultOrganizationProviderRule.create(db);
private WsTester wsTester;

@Before
public void setUp() {
dbClient = db.getDbClient();
dbSession = db.getSession();

GroupWsSupport groupSupport = new GroupWsSupport(db.getDbClient(), defaultOrganizationProvider);
wsTester = new WsTester(new UserGroupsWs(
new UsersAction(
dbClient,
new UserGroupFinder(dbClient),
userSession)));
db.getDbClient(),
userSession,
groupSupport)));
userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);

}

@Test(expected = NotFoundException.class)
public void fail_on_unknown_user() throws Exception {
public void fail_if_unknown_user() throws Exception {
newUsersRequest()
.setParam("id", "42")
.setParam("login", "john").execute();
}

@Test(expected = ForbiddenException.class)
public void fail_on_missing_permission() throws Exception {
public void fail_if_missing_permission() throws Exception {
userSession.login("not-admin");
newUsersRequest()
.setParam("id", "42")
@@ -84,8 +78,7 @@ public class UsersActionTest {

@Test
public void empty_users() throws Exception {
GroupDto group = insertGroup();
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");

newUsersRequest()
.setParam("login", "john")
@@ -96,11 +89,10 @@ public class UsersActionTest {

@Test
public void all_users() throws Exception {
GroupDto group = insertGroup();
UserDto groupUser = insertUser("ada", "Ada Lovelace");
insertUser("grace", "Grace Hopper");
addUserToGroup(groupUser, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto user1 = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
db.users().insertMember(group, user1);
db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));

newUsersRequest()
.setParam("id", group.getId().toString())
@@ -111,12 +103,11 @@ public class UsersActionTest {

@Test
public void all_users_by_group_name() throws Exception {
GroupDto group = insertGroup();
UserDto adaLovelace = insertUser("ada", "Ada Lovelace");
UserDto graceHopper = insertUser("grace", "Grace Hopper");
addUserToGroup(adaLovelace, group);
addUserToGroup(graceHopper, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto adaLovelace = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
UserDto graceHopper = db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));
db.users().insertMember(group, adaLovelace);
db.users().insertMember(group, graceHopper);

String response = newUsersRequest()
.setParam(PARAM_GROUP_NAME, group.getName())
@@ -127,11 +118,10 @@ public class UsersActionTest {

@Test
public void selected_users() throws Exception {
GroupDto group = insertGroup();
UserDto groupUser = insertUser("ada", "Ada Lovelace");
insertUser("grace", "Grace Hopper");
addUserToGroup(groupUser, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto user1 = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));
db.users().insertMember(group, user1);

newUsersRequest()
.setParam("id", group.getId().toString())
@@ -147,11 +137,10 @@ public class UsersActionTest {

@Test
public void deselected_users() throws Exception {
GroupDto group = insertGroup();
UserDto groupUser = insertUser("ada", "Ada Lovelace");
insertUser("grace", "Grace Hopper");
addUserToGroup(groupUser, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto user1 = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));
db.users().insertMember(group, user1);

newUsersRequest()
.setParam("id", group.getId().toString())
@@ -162,11 +151,10 @@ public class UsersActionTest {

@Test
public void paging() throws Exception {
GroupDto group = insertGroup();
UserDto groupUser = insertUser("ada", "Ada Lovelace");
insertUser("grace", "Grace Hopper");
addUserToGroup(groupUser, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto user1 = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));
db.users().insertMember(group, user1);

newUsersRequest()
.setParam("id", group.getId().toString())
@@ -186,11 +174,10 @@ public class UsersActionTest {

@Test
public void filtering() throws Exception {
GroupDto group = insertGroup();
UserDto groupUser = insertUser("ada", "Ada Lovelace");
insertUser("grace", "Grace Hopper");
addUserToGroup(groupUser, group);
dbSession.commit();
GroupDto group = db.users().insertGroup(defaultOrganizationProvider.getDto(), "a group");
UserDto user1 = db.users().insertUser(newUserDto().setLogin("ada").setName("Ada Lovelace"));
db.users().insertUser(newUserDto().setLogin("grace").setName("Grace Hopper"));
db.users().insertMember(group, user1);

newUsersRequest()
.setParam("id", group.getId().toString())
@@ -210,16 +197,4 @@ public class UsersActionTest {
return wsTester.newGetRequest("api/user_groups", "users");
}

private GroupDto insertGroup() {
return dbClient.groupDao().insert(dbSession, new GroupDto()
.setName("sonar-users"));
}

private UserDto insertUser(String login, String name) {
return dbClient.userDao().insert(dbSession, new UserDto().setLogin(login).setName(name));
}

private void addUserToGroup(UserDto user, GroupDto usersGroup) {
dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(usersGroup.getId()));
}
}

+ 2
- 1
server/sonar-server/src/test/resources/org/sonar/server/user/UserUpdaterTest/associate_default_groups_when_reactivating_user.xml View File

@@ -18,7 +18,8 @@
name="sonar-devs"
description="Sonar Devs"
created_at="2014-09-08"
updated_at="2014-09-08"/>
updated_at="2014-09-08"
organization_uuid="org1"/>

<groups_users user_id="101"
group_id="1"/>

+ 2
- 1
server/sonar-server/src/test/resources/org/sonar/server/user/UserUpdaterTest/not_associate_default_group_when_updating_user_if_already_existing.xml View File

@@ -18,7 +18,8 @@
name="sonar-users"
description="Sonar Users"
created_at="2014-09-08"
updated_at="2014-09-08"/>
updated_at="2014-09-08"
organization_uuid="org1"/>

<groups_users user_id="101"
group_id="1"/>

server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1403_add_root_column_on_table_users.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1404_add_root_column_on_table_users.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1404_populate_root_column_on_table_users.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1405_populate_root_column_on_table_users.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1405_make_root_column_not_null_on_table_users.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1406_make_root_column_not_null_on_table_users.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1406_populate_organization_uuid_of_groups.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1407_populate_organization_uuid_of_groups.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1407_make_organization_uuid_not_null_on_groups.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1408_make_organization_uuid_not_null_on_groups.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1408_add_organization_uuid_to_user_roles.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1409_add_organization_uuid_to_user_roles.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1409_populate_organization_uuid_of_user_roles.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1410_populate_organization_uuid_of_user_roles.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1410_make_organization_uuid_not_null_on_user_roles.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1411_make_organization_uuid_not_null_on_user_roles.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1411_add_organization_uuid_to_permission_templates.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1412_add_organization_uuid_to_permission_templates.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1412_populate_organization_uuid_of_permission_templates.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1413_populate_organization_uuid_of_permission_templates.rb View File


server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1413_make_organization_uuid_not_null_on_permission_templates.rb → server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1414_make_organization_uuid_not_null_on_permission_templates.rb View File


+ 1
- 1
sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java View File

@@ -30,7 +30,7 @@ import org.sonar.db.MyBatis;

public class DatabaseVersion {

public static final int LAST_VERSION = 1_413;
public static final int LAST_VERSION = 1_414;

/**
* The minimum supported version which can be upgraded. Lower

+ 1
- 0
sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql View File

@@ -502,6 +502,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1410');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1411');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1412');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1413');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1414');

INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, IS_ROOT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', true, '1418215735482', '1418215735482');
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;

+ 4
- 2
sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java View File

@@ -39,6 +39,7 @@ import org.sonar.db.issue.IssueFilterDto;
import org.sonar.db.issue.IssueFilterFavouriteDto;
import org.sonar.db.measure.MeasureFilterDto;
import org.sonar.db.measure.MeasureFilterFavouriteDto;
import org.sonar.db.permission.UserPermissionDto;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.property.PropertyQuery;

@@ -50,6 +51,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.user.GroupMembershipQuery.IN;
import static org.sonar.db.user.GroupMembershipQuery.builder;
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;

public class UserDaoTest {
@@ -722,13 +724,13 @@ public class UserDaoTest {

private org.sonar.db.permission.UserPermissionDto insertUserPermission(UserDto user) {
String permission = randomAlphanumeric(64);
org.sonar.db.permission.UserPermissionDto dto = new org.sonar.db.permission.UserPermissionDto(permission, user.getId(), null);
UserPermissionDto dto = new UserPermissionDto(db.getDefaultOrganization().getUuid(), permission, user.getId(), null);
dbClient.userPermissionDao().insert(session, dto);
return dto;
}

private UserGroupDto insertUserGroup(UserDto user) {
GroupDto group = new GroupDto().setName(randomAlphanumeric(30));
GroupDto group = newGroupDto().setName(randomAlphanumeric(30));
dbClient.groupDao().insert(session, group);

UserGroupDto dto = new UserGroupDto().setUserId(user.getId()).setGroupId(group.getId());

+ 1
- 1
sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java View File

@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
public void verify_count_of_added_MigrationStep_types() {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
assertThat(container.size()).isEqualTo(153);
assertThat(container.size()).isEqualTo(156);
}
}

+ 2
- 1
sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_global_permissions_for_group_anyone.xml View File

@@ -7,7 +7,8 @@
<user_roles id="1"
user_id="10"
resource_id="[null]"
role="user"/>
role="user"
organization_uuid="org1"/>

<groups_users user_id="10"
group_id="[null]"/>

+ 4
- 2
sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_group_global_permissions.xml View File

@@ -12,11 +12,13 @@
<user_roles id="1"
user_id="999"
resource_id="[null]"
role="user"/>
role="user"
organization_uuid="org1"/>
<user_roles id="2"
user_id="999"
resource_id="[null]"
role="user"/>
role="user"
organization_uuid="org1"/>

<groups_users user_id="10"
group_id="200"/>

+ 6
- 3
sonar-db/src/test/resources/org/sonar/db/permission/PermissionDaoTest/should_return_user_global_permissions.xml View File

@@ -12,15 +12,18 @@
<user_roles id="1"
user_id="10"
resource_id="[null]"
role="user"/>
role="user"
organization_uuid="org1"/>
<user_roles id="2"
user_id="10"
resource_id="[null]"
role="admin"/>
role="admin"
organization_uuid="org1"/>
<user_roles id="3"
user_id="11"
resource_id="[null]"
role="user"/>
role="user"
organization_uuid="org1"/>

<groups_users user_id="999"
group_id="200"/>

+ 14
- 7
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/apply_default_permission_template-result.xml View File

@@ -1,9 +1,11 @@
<dataset>

<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>

<users id="200"
login="marius"
@@ -30,7 +32,8 @@
<user_roles id="1"
user_id="200"
resource_id="1"
role="admin"/>
role="admin"
organization_uuid="org1"/>

<!-- new groups permissions : sonar-administrators (admin), sonar-users (user & codeviewer), Anyone (user & codeviewer) -->
<group_roles id="3"
@@ -62,20 +65,24 @@
<user_roles id="2"
user_id="200"
resource_id="123"
role="admin"/>
role="admin"
organization_uuid="org1"/>
<user_roles id="3"
user_id="201"
resource_id="123"
role="admin"/>
role="admin"
organization_uuid="org1"/>
<user_roles id="4"
user_id="201"
resource_id="123"
role="user"/>
role="user"
organization_uuid="org1"/>

<!-- default permission template for all qualifiers -->
<permission_templates id="1"
name="default"
kee="default_20130101_010203"/>
kee="default_20130101_010203"
organization_uuid="org1"/>

<perm_templates_groups id="1"
template_id="1"

+ 10
- 5
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/apply_default_permission_template_by_component_id-result.xml View File

@@ -1,9 +1,11 @@
<dataset>

<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>

<users id="200"
login="marius"
@@ -30,7 +32,8 @@
<user_roles id="1"
user_id="200"
resource_id="1"
role="admin"/>
role="admin"
organization_uuid="org1"/>

<!-- new groups permissions : sonar-administrators (admin), sonar-users (user & codeviewer), Anyone (user & codeviewer) -->
<group_roles id="3"
@@ -62,12 +65,14 @@
<user_roles id="2"
user_id="200"
resource_id="123"
role="admin"/>
role="admin"
organization_uuid="org1"/>

<!-- default permission template for all qualifiers -->
<permission_templates id="1"
name="default"
kee="default_20130101_010203"/>
kee="default_20130101_010203"
organization_uuid="org1"/>

<perm_templates_groups id="1"
template_id="1"

+ 10
- 5
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_apply_permission_template-result.xml View File

@@ -1,9 +1,11 @@
<dataset>

<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>

<users id="200"
login="marius"
@@ -24,7 +26,8 @@
<user_roles id="1"
user_id="200"
resource_id="1"
role="admin"/>
role="admin"
organization_uuid="org1"/>

<!-- new groups permissions : sonar-administrators (admin), sonar-users (user & codeviewer), Anyone (user & codeviewer) -->
<group_roles id="3"
@@ -56,12 +59,14 @@
<user_roles id="2"
user_id="200"
resource_id="123"
role="admin"/>
role="admin"
organization_uuid="org1"/>

<!-- default permission template for all qualifiers -->
<permission_templates id="1"
name="default"
kee="default_20130101_010203"/>
kee="default_20130101_010203"
organization_uuid="org1"/>

<perm_templates_groups id="1"
template_id="1"

+ 4
- 2
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_count_component_permissions.xml View File

@@ -8,12 +8,14 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles id="1"
user_id="200"
resource_id="123"
role="user"/>
role="user"
organization_uuid="org1"/>

<group_roles id="1"
group_id="100"

+ 2
- 1
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_remove_all_permissions-result.xml View File

@@ -8,7 +8,8 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles/>


+ 4
- 2
sonar-db/src/test/resources/org/sonar/db/permission/PermissionRepositoryTest/should_remove_all_permissions.xml View File

@@ -8,12 +8,14 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles id="1"
user_id="200"
resource_id="123"
role="user"/>
role="user"
organization_uuid="org1"/>

<group_roles id="1"
group_id="100"

+ 2
- 1
sonar-db/src/test/resources/org/sonar/db/permission/template/PermissionTemplateDaoTest/selectEmptyPermissionTemplate.xml View File

@@ -4,7 +4,8 @@
kee="my_template_20130102_030405"
description="my description"
created_at="[null]"
updated_at="[null]"/>
updated_at="[null]"
organization_uuid="org1"/>

<users id="1"
login="user1"

+ 0
- 2
sonar-db/src/test/resources/org/sonar/db/permission/template/PermissionTemplateDaoTest/selectPermissionTemplate.xml View File

@@ -4,7 +4,6 @@
kee="my_template_20130102_030405"
description="my description"
created_at="[null]"
updated_at="[null]"/>
updated_at="[null]"
organization_uuid="org1"/>

@@ -51,7 +50,6 @@
permission_reference="group_permission2"/>

<groups id="1"
name="group1"/>
name="group1"
organization_uuid="org1"/>
<groups id="2"

+ 2
- 1
sonar-db/src/test/resources/org/sonar/db/user/GroupDaoTest/find_by_user_login.xml View File

@@ -30,6 +30,7 @@
email="jo@hn.com"
created_at="1418215735482"
updated_at="1418215735482"
active="[true]"/>
active="[true]"
is_root="[false]"/>

</dataset>

+ 6
- 3
sonar-db/src/test/resources/org/sonar/db/user/GroupMembershipDaoTest/shared.xml View File

@@ -2,13 +2,16 @@

<groups id="100"
name="sonar-administrators"
description="System administrators"/>
description="System administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"
description="Any new users created will automatically join this group"/>
description="Any new users created will automatically join this group"
organization_uuid="org1"/>
<groups id="102"
name="sonar-reviewers"
description="Reviewers"/>
description="Reviewers"
organization_uuid="org1"/>

<!-- user 200 is in all groups -->
<groups_users user_id="200"

+ 8
- 4
sonar-db/src/test/resources/org/sonar/db/user/GroupMembershipDaoTest/shared_plus_empty_group.xml View File

@@ -2,16 +2,20 @@

<groups id="100"
name="sonar-administrators"
description="System administrators"/>
description="System administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"
description="Any new users created will automatically join this group"/>
description="Any new users created will automatically join this group"
organization_uuid="org1"/>
<groups id="102"
name="sonar-reviewers"
description="Reviewers"/>
description="Reviewers"
organization_uuid="org1"/>
<groups id="103"
name="sonar-nobody"
description="Nobody in this group"/>
description="Nobody in this group"
organization_uuid="org1"/>

<!-- user 200 is in all groups -->
<groups_users user_id="200"

+ 4
- 2
sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_count_component_permissions.xml View File

@@ -8,12 +8,14 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles id="1"
user_id="200"
resource_id="123"
role="user"/>
role="user"
organization_uuid="org1"/>

<group_roles id="1"
group_id="100"

+ 2
- 1
sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_remove_all_permissions-result.xml View File

@@ -8,7 +8,8 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles/>


+ 4
- 2
sonar-db/src/test/resources/org/sonar/db/user/RoleDaoTest/should_remove_all_permissions.xml View File

@@ -8,12 +8,14 @@
is_root="[false]"/>

<groups id="100"
name="devs"/>
name="devs"
organization_uuid="org1"/>

<user_roles id="1"
user_id="200"
resource_id="123"
role="user"/>
role="user"
organization_uuid="org1"/>

<group_roles id="1"
group_id="100"

+ 8
- 4
sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/countRoles.xml View File

@@ -1,8 +1,10 @@
<dataset>
<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>
<users id="200"
login="marius"
name="Marius"
@@ -21,7 +23,8 @@
<user_roles id="1"
user_id="200"
resource_id="123"
role="codeviewer"/>
role="codeviewer"
organization_uuid="org1"/>

<!-- other resource -->
<group_roles id="3"
@@ -31,6 +34,7 @@
<user_roles id="2"
user_id="200"
resource_id="999"
role="codeviewer"/>
role="codeviewer"
organization_uuid="org1"/>

</dataset>

+ 6
- 3
sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/deleteRolesByResourceId-result.xml View File

@@ -1,8 +1,10 @@
<dataset>
<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>
<users id="200"
login="marius"
name="Marius"
@@ -22,6 +24,7 @@
<user_roles id="2"
user_id="200"
resource_id="999"
role="codeviewer"/>
role="codeviewer"
organization_uuid="org1"/>

</dataset>

+ 8
- 4
sonar-db/src/test/resources/org/sonar/db/user/RoleMapperTest/deleteRolesByResourceId.xml View File

@@ -1,8 +1,10 @@
<dataset>
<groups id="100"
name="sonar-administrators"/>
name="sonar-administrators"
organization_uuid="org1"/>
<groups id="101"
name="sonar-users"/>
name="sonar-users"
organization_uuid="org1"/>
<users id="200"
login="marius"
name="Marius"
@@ -21,7 +23,8 @@
<user_roles id="1"
user_id="200"
resource_id="123"
role="codeviewer"/>
role="codeviewer"
organization_uuid="org1"/>

<!-- other resource -->
<group_roles id="3"
@@ -31,6 +34,7 @@
<user_roles id="2"
user_id="200"
resource_id="999"
role="codeviewer"/>
role="codeviewer"
organization_uuid="org1"/>

</dataset>

+ 43
- 0
sonar-ws/src/main/protobuf/ws-user_groups.proto View File

@@ -0,0 +1,43 @@
// SonarQube, open source software quality management tool.
// Copyright (C) 2008-2015 SonarSource
// mailto:contact AT sonarsource DOT com
//
// SonarQube 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.
//
// SonarQube 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 this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

syntax = "proto2";

package sonarqube.ws.usergroup;

option java_package = "org.sonarqube.ws";
option java_outer_classname = "WsUserGroups";
option optimize_for = SPEED;

// WS api/user_groups/create
message CreateResponse {
optional Group group = 1;
}

// WS api/user_groups/update
message UpdateResponse {
optional Group group = 1;
}

message Group {
optional int64 id = 1;
optional string organization = 2;
optional string name = 3;
optional string description = 4;
optional int32 membersCount = 5;
}

Loading…
Cancel
Save