]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6473 New WS to update a user group
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 26 May 2015 14:37:31 +0000 (16:37 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Thu, 28 May 2015 10:09:45 +0000 (12:09 +0200)
14 files changed:
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/CreateAction.java
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupUpdater.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/CreateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UpdateActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/user/GroupMapper.java
sonar-core/src/main/resources/org/sonar/core/user/GroupMapper.xml

index eca68f9b1f40c648fdae4176a21641f028bfe606..85c19f942246c141c4d7fb4198b201cd1e30ab0c 100644 (file)
@@ -311,7 +311,7 @@ import org.sonar.server.user.ws.CurrentAction;
 import org.sonar.server.user.ws.FavoritesWs;
 import org.sonar.server.user.ws.UserPropertiesWs;
 import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.usergroups.ws.UserGroupsWs;
+import org.sonar.server.usergroups.ws.UserGroupsModule;
 import org.sonar.server.util.BooleanTypeValidation;
 import org.sonar.server.util.FloatTypeValidation;
 import org.sonar.server.util.IntegerTypeValidation;
@@ -562,10 +562,7 @@ public class PlatformLevel4 extends PlatformLevel {
       // groups
       GroupMembershipService.class,
       GroupMembershipFinder.class,
-      UserGroupsWs.class,
-      org.sonar.server.usergroups.ws.SearchAction.class,
-      org.sonar.server.usergroups.ws.CreateAction.class,
-      org.sonar.server.usergroups.ws.DeleteAction.class,
+      UserGroupsModule.class,
 
       // permissions
       PermissionFacade.class,
index 88229ea14f38ea2149269a65d3f92ee355e73446..55c3a25916b53189a292e01c42ca37012ffa3ba1 100644 (file)
@@ -58,8 +58,16 @@ public class GroupDao implements DaoComponent {
     return mapper(session).selectByKey(key);
   }
 
-  @CheckForNull
   public GroupDto selectById(DbSession dbSession, long groupId) {
+    GroupDto group = selectNullableById(dbSession, groupId);
+    if (group == null) {
+      throw new NotFoundException(String.format("Could not find a group with id '%d'", groupId));
+    }
+    return group;
+  }
+
+  @CheckForNull
+  public GroupDto selectNullableById(DbSession dbSession, long groupId) {
     return mapper(dbSession).selectById(groupId);
   }
 
@@ -83,6 +91,12 @@ public class GroupDao implements DaoComponent {
     return item;
   }
 
+  public GroupDto update(DbSession session, GroupDto item) {
+    item.setUpdatedAt(new Date(system.now()));
+    mapper(session).update(item);
+    return item;
+  }
+
   public List<GroupDto> findByUserLogin(DbSession session, String login){
     return mapper(session).selectByUserLogin(login);
   }
index cdc9ad5fcf0223e02a7e2cd16f8f56b0cf39411d..56e1f7d76b3c0234286a9d7b71d9598c12f24194 100644 (file)
  */
 package org.sonar.server.usergroups.ws;
 
-import com.google.common.base.Preconditions;
-import java.net.HttpURLConnection;
-import javax.annotation.Nullable;
-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;
 import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.user.GroupDto;
 import org.sonar.server.db.DbClient;
-import org.sonar.server.exceptions.ServerException;
 import org.sonar.server.user.UserSession;
 
 import static org.sonar.core.persistence.MyBatis.closeQuietly;
+import static org.sonar.server.usergroups.ws.GroupUpdater.DESCRIPTION_MAX_LENGTH;
+import static org.sonar.server.usergroups.ws.GroupUpdater.NAME_MAX_LENGTH;
+import static org.sonar.server.usergroups.ws.GroupUpdater.PARAM_DESCRIPTION;
+import static org.sonar.server.usergroups.ws.GroupUpdater.PARAM_NAME;
 
 public class CreateAction implements UserGroupsWsAction {
 
-  private static final String PARAM_DESCRIPTION = "description";
-  private 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
-  private static final int NAME_MAX_LENGTH = 255;
-  private static final int DESCRIPTION_MAX_LENGTH = 200;
-
   private final DbClient dbClient;
   private final UserSession userSession;
+  private final GroupUpdater groupUpdater;
 
-  public CreateAction(DbClient dbClient, UserSession userSession) {
+  public CreateAction(DbClient dbClient, UserSession userSession, GroupUpdater groupUpdater) {
     this.dbClient = dbClient;
+    this.groupUpdater = groupUpdater;
     this.userSession = userSession;
   }
 
@@ -65,13 +58,13 @@ public class CreateAction implements UserGroupsWsAction {
       .setSince("5.2");
 
     action.createParam(PARAM_NAME)
-      .setDescription("Name for the new group. A group name cannot be larger than 255 characters and must be unique. " +
-        "The value 'anyone' (whatever the case) is reserved and cannot be used.")
+      .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.", NAME_MAX_LENGTH))
       .setExampleValue("sonar-users")
       .setRequired(true);
 
     action.createParam(PARAM_DESCRIPTION)
-      .setDescription("Description for the new group. A group description cannot be larger than 200 characters.")
+      .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");
   }
 
@@ -82,53 +75,22 @@ public class CreateAction implements UserGroupsWsAction {
     String name = request.mandatoryParam(PARAM_NAME);
     String description = request.param(PARAM_DESCRIPTION);
 
-    validateName(name);
-    validateDescription(description);
+    groupUpdater.validateName(name);
+    if (description != null) {
+      groupUpdater.validateDescription(description);
+    }
 
-    GroupDto newGroup = new GroupDto().setName(name).setDescription(description);
     DbSession session = dbClient.openSession(false);
     try {
-      checkNameIsUnique(name, session);
-      newGroup = dbClient.groupDao().insert(session, new GroupDto().setName(name).setDescription(description));
+      groupUpdater.checkNameIsUnique(name, session);
+      GroupDto newGroup = dbClient.groupDao().insert(session, new GroupDto().setName(name).setDescription(description));
       session.commit();
+
+      JsonWriter json = response.newJsonWriter().beginObject();
+      groupUpdater.writeGroup(json, newGroup, 0);
+      json.endObject().close();
     } finally {
       closeQuietly(session);
     }
-
-    response.newJsonWriter().beginObject().name("group").beginObject()
-      .prop("id", newGroup.getId().toString())
-      .prop(PARAM_NAME, newGroup.getName())
-      .prop(PARAM_DESCRIPTION, newGroup.getDescription())
-      .prop("membersCount", 0)
-      .endObject().endObject().close();
-  }
-
-  private void validateName(String name) {
-    checkNameLength(name);
-    checkNameNotAnyone(name);
-  }
-
-  private void checkNameLength(String name) {
-    Preconditions.checkArgument(!name.isEmpty(), "Name cannot be empty");
-    Preconditions.checkArgument(name.length() <= NAME_MAX_LENGTH, String.format("Name cannot be longer than %d characters", NAME_MAX_LENGTH));
-  }
-
-  private void checkNameNotAnyone(String name) {
-    Preconditions.checkArgument(!DefaultGroups.isAnyone(name), String.format("Name '%s' is reserved (regardless of case)", DefaultGroups.ANYONE));
-  }
-
-  private 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().selectNullableByKey(session, name) != null) {
-      throw new ServerException(HttpURLConnection.HTTP_CONFLICT, String.format("Name '%s' is already taken", name));
-    }
-  }
-
-  private void validateDescription(@Nullable String description) {
-    if (description != null) {
-      Preconditions.checkArgument(description.length() <= DESCRIPTION_MAX_LENGTH, String.format("Description cannot be longer than %d characters", DESCRIPTION_MAX_LENGTH));
-    }
   }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/GroupUpdater.java
new file mode 100644 (file)
index 0000000..31175d5
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+package org.sonar.server.usergroups.ws;
+
+import com.google.common.base.Preconditions;
+import java.net.HttpURLConnection;
+import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.user.GroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ServerException;
+
+@ServerSide
+public class GroupUpdater {
+
+  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 NAME_MAX_LENGTH = 255;
+  static final int DESCRIPTION_MAX_LENGTH = 200;
+
+  private final DbClient dbClient;
+
+  public GroupUpdater(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  protected void validateName(String name) {
+    checkNameLength(name);
+    checkNameNotAnyone(name);
+  }
+
+  private void checkNameLength(String name) {
+    Preconditions.checkArgument(!name.isEmpty(), "Name cannot be empty");
+    Preconditions.checkArgument(name.length() <= NAME_MAX_LENGTH, String.format("Name cannot be longer than %d characters", NAME_MAX_LENGTH));
+  }
+
+  private void checkNameNotAnyone(String name) {
+    Preconditions.checkArgument(!DefaultGroups.isAnyone(name), String.format("Name '%s' is reserved (regardless of case)", DefaultGroups.ANYONE));
+  }
+
+  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().selectNullableByKey(session, name) != null) {
+      throw new ServerException(HttpURLConnection.HTTP_CONFLICT, 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();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UpdateAction.java
new file mode 100644 (file)
index 0000000..3aaae84
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+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;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.user.GroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.user.UserSession;
+
+import static org.sonar.core.persistence.MyBatis.closeQuietly;
+import static org.sonar.server.usergroups.ws.GroupUpdater.DESCRIPTION_MAX_LENGTH;
+import static org.sonar.server.usergroups.ws.GroupUpdater.NAME_MAX_LENGTH;
+import static org.sonar.server.usergroups.ws.GroupUpdater.PARAM_DESCRIPTION;
+import static org.sonar.server.usergroups.ws.GroupUpdater.PARAM_ID;
+import static org.sonar.server.usergroups.ws.GroupUpdater.PARAM_NAME;
+
+public class UpdateAction implements UserGroupsWsAction {
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final GroupUpdater groupUpdater;
+
+  public UpdateAction(DbClient dbClient, UserSession userSession, GroupUpdater groupUpdater) {
+    this.dbClient = dbClient;
+    this.groupUpdater = groupUpdater;
+    this.userSession = userSession;
+  }
+
+  @Override
+  public void define(NewController context) {
+    NewAction action = context.createAction("update")
+      .setDescription("Update a group.")
+      .setHandler(this)
+      .setPost(true)
+      .setResponseExample(getClass().getResource("example-update.json"))
+      .setSince("5.2");
+
+    action.createParam(PARAM_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.", 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))
+      .setExampleValue("Default group for new users");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn().checkGlobalPermission(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 {
+      groupUpdater.checkNameIsUnique(name, dbSession);
+      GroupDto group = dbClient.groupDao().selectById(dbSession, groupId);
+      if (name != null) {
+        groupUpdater.validateName(name);
+        group.setName(name);
+      }
+      if (description != null) {
+        groupUpdater.validateDescription(description);
+        group.setDescription(description);
+      }
+      dbClient.groupDao().update(dbSession, group);
+      dbSession.commit();
+
+      JsonWriter json = response.newJsonWriter().beginObject();
+      groupUpdater.writeGroup(json, group, dbClient.groupMembershipDao().countUsersByGroups(dbSession, Arrays.asList(groupId)).get(group.getName()));
+      json.endObject().close();
+    } finally {
+      closeQuietly(dbSession);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsModule.java
new file mode 100644 (file)
index 0000000..8c2406e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+package org.sonar.server.usergroups.ws;
+
+import org.sonar.core.component.Module;
+
+public class UserGroupsModule extends Module {
+
+  @Override
+  protected void configureModule() {
+    add(
+      GroupUpdater.class,
+      UserGroupsWs.class,
+      SearchAction.class,
+      CreateAction.class,
+      DeleteAction.class,
+      UpdateAction.class);
+  }
+
+}
index c30587992b556221910ebb858e70fc624aed3b8f..70a1f674b533fbd311f786f1744a346075a5d322 100644 (file)
@@ -110,6 +110,23 @@ public class GroupDaoTest {
     dbTester.assertDbUnit(getClass(), "insert-result.xml", "groups");
   }
 
+  @Test
+  public void update() {
+    when(system2.now()).thenReturn(DateUtils.parseDate("2013-07-25").getTime());
+
+    dbTester.prepareDbUnit(getClass(), "update.xml");
+
+    GroupDto dto = new GroupDto()
+      .setId(1L)
+      .setName("new-name")
+      .setDescription("New Description");
+
+    dao.update(session, dto);
+    session.commit();
+
+    dbTester.assertDbUnit(getClass(), "update-result.xml", "groups");
+  }
+
   @Test
   public void select_by_query() {
     dbTester.prepareDbUnit(getClass(), "select_by_query.xml");
index 1967cb1ca0154a1052616db096249d6b6787b34c..44e47770954bf292bbae63179ef79748f223d69c 100644 (file)
@@ -68,7 +68,7 @@ public class CreateActionTest {
 
     DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), groupDao);
 
-    tester = new WsTester(new UserGroupsWs(new CreateAction(dbClient, userSession)));
+    tester = new WsTester(new UserGroupsWs(new CreateAction(dbClient, userSession, new GroupUpdater(dbClient))));
 
     session = dbClient.openSession(false);
   }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UpdateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UpdateActionTest.java
new file mode 100644 (file)
index 0000000..90ad8c4
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+
+package org.sonar.server.usergroups.ws;
+
+import java.net.HttpURLConnection;
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.user.GroupDto;
+import org.sonar.core.user.GroupMembershipDao;
+import org.sonar.core.user.UserGroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.ServerException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.user.db.GroupDao;
+import org.sonar.server.user.db.UserGroupDao;
+import org.sonar.server.ws.WsTester;
+import org.sonar.test.DbTests;
+
+@Category(DbTests.class)
+public class UpdateActionTest {
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private WsTester tester;
+
+  private GroupDao groupDao;
+
+  private DbSession session;
+
+  private UserGroupDao userGroupDao;
+
+  @Before
+  public void setUp() {
+    dbTester.truncateTables();
+
+    groupDao = new GroupDao(System2.INSTANCE);
+
+    userGroupDao = new UserGroupDao();
+
+    DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(),
+      groupDao, new GroupMembershipDao(dbTester.myBatis()), userGroupDao);
+
+    tester = new WsTester(new UserGroupsWs(new UpdateAction(dbClient, userSession, new GroupUpdater(dbClient))));
+
+    session = dbClient.openSession(false);
+  }
+
+  @After
+  public void after() {
+    session.close();
+  }
+
+  @Test
+  public void update_nominal() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    userGroupDao.insert(session, new UserGroupDto().setGroupId(existingGroup.getId()).setUserId(42L));
+
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", "new-name")
+      .setParam("description", "New Description")
+      .execute().assertJson("{" +
+        "  \"group\": {" +
+        "    \"name\": \"new-name\"," +
+        "    \"description\": \"New Description\"," +
+        "    \"membersCount\": 1" +
+        "  }" +
+        "}");
+  }
+
+  @Test
+  public void update_only_name() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", "new-name")
+      .execute().assertJson("{" +
+        "  \"group\": {" +
+        "    \"name\": \"new-name\"," +
+        "    \"description\": \"Old Description\"," +
+        "    \"membersCount\": 0" +
+        "  }" +
+        "}");
+  }
+
+  @Test
+  public void update_only_description() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("description", "New Description")
+      .execute().assertJson("{" +
+        "  \"group\": {" +
+        "    \"name\": \"old-name\"," +
+        "    \"description\": \"New Description\"," +
+        "    \"membersCount\": 0" +
+        "  }" +
+        "}");
+  }
+
+  @Test
+  public void require_admin_permission() throws Exception {
+    expectedException.expect(ForbiddenException.class);
+
+    userSession.login("not-admin");
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", "42")
+      .setParam("name", "some-product-bu")
+      .setParam("description", "Business Unit for Some Awesome Product")
+      .execute();
+  }
+
+  @Test
+  public void name_too_short() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    expectedException.expect(IllegalArgumentException.class);
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", "")
+      .execute();
+  }
+
+  @Test
+  public void name_too_long() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    expectedException.expect(IllegalArgumentException.class);
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", StringUtils.repeat("a", 255 + 1))
+      .execute();
+  }
+
+  @Test
+  public void forbidden_name() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    expectedException.expect(IllegalArgumentException.class);
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", "AnYoNe")
+      .execute();
+  }
+
+  @Test
+  public void non_unique_name() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    String groupName = "conflicting-name";
+    groupDao.insert(session, new GroupDto()
+      .setName(groupName));
+    session.commit();
+
+    expectedException.expect(ServerException.class);
+    expectedException.expectMessage("already taken");
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", groupName)
+      .execute().assertStatus(HttpURLConnection.HTTP_CONFLICT);
+  }
+
+  @Test
+  public void description_too_long() throws Exception {
+    GroupDto existingGroup = groupDao.insert(session, new GroupDto().setName("old-name").setDescription("Old Description"));
+    session.commit();
+
+    expectedException.expect(IllegalArgumentException.class);
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", existingGroup.getId().toString())
+      .setParam("name", "long-group-description-is-looooooooooooong")
+      .setParam("description", StringUtils.repeat("a", 200 + 1))
+      .execute();
+  }
+
+  @Test
+  public void unknown_group() throws Exception {
+    expectedException.expect(NotFoundException.class);
+
+    loginAsAdmin();
+    tester.newPostRequest("api/usergroups", "update")
+      .setParam("id", "42")
+      .execute();
+  }
+
+  private void loginAsAdmin() {
+    userSession.login("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+  }
+}
index e0d9d4e060c64ba22f381ddcdfa50e598281e359..d739480aa9ab6c5420d647aa4e08f793d22e4cd9 100644 (file)
@@ -41,7 +41,7 @@ public class UserGroupsWsTest {
   public void setUp() {
     WsTester tester = new WsTester(new UserGroupsWs(
       new SearchAction(mock(DbClient.class)),
-      new CreateAction(mock(DbClient.class), mock(UserSession.class))));
+      new CreateAction(mock(DbClient.class), mock(UserSession.class), mock(GroupUpdater.class))));
     controller = tester.controller("api/usergroups");
   }
 
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update-result.xml
new file mode 100644 (file)
index 0000000..7fdf00c
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <groups id="1" name="new-name" description="New Description" created_at="2011-04-25" updated_at="2013-07-25"/>
+
+  <groups id="2" name="untouched" description="Untouched" created_at="2003-03-23" updated_at="2006-09-09"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/update.xml
new file mode 100644 (file)
index 0000000..df225b5
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <groups id="1" name="old-name" description="Old Description" created_at="2011-04-25" updated_at="2011-04-25"/>
+
+  <groups id="2" name="untouched" description="Untouched" created_at="2003-03-23" updated_at="2006-09-09"/>
+
+</dataset>
index de36b36af7c5714fb5a68e0e4932feb788820ce2..607b97b4758fb1a064ed8735c8d3a49eea603ce8 100644 (file)
@@ -36,10 +36,11 @@ public interface GroupMapper {
 
   void insert(GroupDto groupDto);
 
+  void update(GroupDto item);
+
   List<GroupDto> selectByQuery(String query, RowBounds rowBounds);
 
   int countByQuery(String query);
 
   void deleteById(long groupId);
-
 }
index 132edb40784b0c8915de21fc164d6e4f2d2a9804..2f7cc2d3f1694e151c407ce08d405b01f3eea9ce 100644 (file)
     VALUES (#{name}, #{description}, #{createdAt}, #{updatedAt})
   </insert>
 
+  <update id="update" parameterType="Group">
+    UPDATE groups SET
+      name=#{name},
+      description=#{description},
+      updated_at=#{updatedAt}
+    WHERE id=#{id}
+  </update>
+
   <select id="selectByQuery" parameterType="map" resultType="Group">
     SELECT <include refid="groupColumns" />
     FROM groups g