]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8664 add organization to response of api/notifications/list 1615/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 1 Feb 2017 16:30:43 +0000 (17:30 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 2 Feb 2017 15:15:35 +0000 (16:15 +0100)
server/sonar-server/src/main/java/org/sonar/server/notification/ws/ListAction.java
server/sonar-server/src/main/resources/org/sonar/server/notification/ws/list-example.json
server/sonar-server/src/test/java/org/sonar/server/notification/ws/ListActionTest.java
sonar-ws/src/main/protobuf/ws-notifications.proto

index 409323408b45290d215af3427247d2ae0807ed52..c1eb9061b7e01ba229c8e47a5dbfa542cd3e200b 100644 (file)
@@ -22,8 +22,11 @@ package org.sonar.server.notification.ws;
 
 import com.google.common.base.Splitter;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -38,6 +41,7 @@ import org.sonar.core.util.stream.Collectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.db.property.PropertyQuery;
 import org.sonar.server.notification.NotificationCenter;
@@ -45,11 +49,11 @@ import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.Notifications.ListResponse;
 import org.sonarqube.ws.Notifications.Notification;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Comparator.comparing;
 import static java.util.Comparator.naturalOrder;
 import static java.util.Comparator.nullsFirst;
 import static org.sonar.core.util.Protobuf.setNullable;
-import static org.sonar.core.util.stream.Collectors.toList;
 import static org.sonar.core.util.stream.Collectors.toOneElement;
 import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
 import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
@@ -112,6 +116,7 @@ public class ListAction implements NotificationsWsAction {
     return response -> {
       List<PropertyDto> properties = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setUserId(userSession.getUserId()).build(), dbSession);
       Map<Long, ComponentDto> componentsById = searchProjects(dbSession, properties);
+      Map<String, OrganizationDto> organizationsByUuid = getOrganizations(dbSession, componentsById.values());
 
       Predicate<PropertyDto> isNotification = prop -> prop.getKey().startsWith("notification.");
       Predicate<PropertyDto> isComponentInDb = prop -> prop.getResourceId() == null || componentsById.containsKey(prop.getResourceId());
@@ -122,7 +127,7 @@ public class ListAction implements NotificationsWsAction {
         .filter(isNotification)
         .filter(channelAndDispatcherAuthorized())
         .filter(isComponentInDb)
-        .map(toWsNotification(notification, componentsById))
+        .map(toWsNotification(notification, organizationsByUuid, componentsById))
         .sorted(comparing(Notification::getProject, nullsFirst(naturalOrder()))
           .thenComparing(comparing(Notification::getChannel))
           .thenComparing(comparing(Notification::getType)))
@@ -146,35 +151,52 @@ public class ListAction implements NotificationsWsAction {
   }
 
   private Map<Long, ComponentDto> searchProjects(DbSession dbSession, List<PropertyDto> properties) {
-    Collection<String> authorizedComponentUuids = dbClient.authorizationDao().selectAuthorizedRootProjectsUuids(dbSession, userSession.getUserId(), UserRole.USER);
-    return dbClient.componentDao().selectByIds(dbSession,
-      properties.stream()
-        .filter(prop -> prop.getResourceId() != null)
-        .map(PropertyDto::getResourceId)
-        .distinct()
-        .collect(toList()))
+    Set<String> authorizedComponentUuids = new HashSet<>(dbClient.authorizationDao().selectAuthorizedRootProjectsUuids(dbSession, userSession.getUserId(), UserRole.USER));
+    Set<Long> componentIds = properties.stream()
+      .map(PropertyDto::getResourceId)
+      .filter(Objects::nonNull)
+      .collect(Collectors.toSet(properties.size()));
+    return dbClient.componentDao().selectByIds(dbSession, componentIds)
       .stream()
       .filter(c -> authorizedComponentUuids.contains(c.uuid()))
       .collect(Collectors.uniqueIndex(ComponentDto::getId));
   }
 
-  private static Function<PropertyDto, Notification> toWsNotification(Notification.Builder notification, Map<Long, ComponentDto> projectsById) {
+  private Map<String, OrganizationDto> getOrganizations(DbSession dbSession, Collection<ComponentDto> values) {
+    Set<String> organizationUuids = values.stream()
+      .map(ComponentDto::getOrganizationUuid)
+      .collect(Collectors.toSet());
+    return dbClient.organizationDao().selectByUuids(dbSession, organizationUuids)
+      .stream()
+      .collect(Collectors.uniqueIndex(OrganizationDto::getUuid));
+  }
+
+  private static Function<PropertyDto, Notification> toWsNotification(Notification.Builder notification,
+    Map<String, OrganizationDto> organizationsByUuid, Map<Long, ComponentDto> projectsById) {
     return property -> {
       notification.clear();
       List<String> propertyKey = Splitter.on(".").splitToList(property.getKey());
       notification.setType(propertyKey.get(1));
       notification.setChannel(propertyKey.get(2));
-      setNullable(property.getResourceId(), componentId -> {
-        ComponentDto project = projectsById.get(componentId);
-        notification.setProject(project.getKey());
-        notification.setProjectName(project.name());
-        return notification;
-      });
+      setNullable(property.getResourceId(),
+        componentId -> populateProjectFields(notification, componentId, organizationsByUuid, projectsById));
 
       return notification.build();
     };
   }
 
+  private static Notification.Builder populateProjectFields(Notification.Builder notification, Long componentId,
+    Map<String, OrganizationDto> organizationsByUuid, Map<Long, ComponentDto> projectsById) {
+    ComponentDto project = projectsById.get(componentId);
+    String organizationUuid = project.getOrganizationUuid();
+    OrganizationDto organizationDto = organizationsByUuid.get(organizationUuid);
+    checkArgument(organizationDto != null, "No organization for uuid '%s'", organizationUuid);
+
+    return notification.setOrganization(organizationDto.getKey())
+      .setProject(project.getKey())
+      .setProjectName(project.name());
+  }
+
   private Consumer<Request> checkPermissions() {
     return request -> userSession.checkLoggedIn();
   }
index e794aae16d71ea537ecc3de9040cc920e504dbdd..0ebee0c19637aa08ceb38f4a238f7a9da8703871 100644 (file)
     {
       "channel": "EmailChannel",
       "type": "MyNewIssues",
+      "organization": "my-org-1",
       "project": "my_project",
       "projectName": "My Project"
     },
     {
       "channel": "EmailChannel",
       "type": "NewQualityGateStatus",
+      "organization": "my-org-1",
       "project": "my_project",
       "projectName": "My Project"
     },
     {
       "channel": "TwitterChannel",
       "type": "MyNewIssues",
+      "organization": "my-org-1",
       "project": "my_project",
       "projectName": "My Project"
     }
index a9437914cc1d15a39189266df6ab5c3036d6377c..cde5be0ed7c1e762a523a41b6809f737ae00f574 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.permission.UserPermissionDto;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.notification.NotificationCenter;
@@ -56,12 +57,14 @@ public class ListActionTest {
   private static final String NOTIF_MY_NEW_ISSUES = "MyNewIssues";
   private static final String NOTIF_NEW_ISSUES = "NewIssues";
   private static final String NOTIF_NEW_QUALITY_GATE_STATUS = "NewQualityGateStatus";
+
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone().logIn().setUserId(123);
   @Rule
   public DbTester db = DbTester.create();
+
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
 
@@ -156,12 +159,15 @@ public class ListActionTest {
 
     ListResponse result = call();
 
-    assertThat(result.getNotificationsList()).extracting(Notification::getType).containsOnly(NOTIF_MY_NEW_ISSUES);
+    assertThat(result.getNotificationsList())
+      .extracting(Notification::getType)
+      .containsOnly(NOTIF_MY_NEW_ISSUES);
   }
 
   @Test
   public void order_with_global_then_by_channel_and_dispatcher() {
-    ComponentDto project = addComponent(newProjectDto(db.organizations().insert()).setKey("K1"));
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = addComponent(newProjectDto(organization).setKey("K1"));
     notificationUpdater.add(dbSession, twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_NEW_ISSUES, null);
@@ -172,19 +178,21 @@ public class ListActionTest {
 
     ListResponse result = call();
 
-    assertThat(result.getNotificationsList()).extracting(Notification::getChannel, Notification::getType, Notification::getProject)
+    assertThat(result.getNotificationsList())
+      .extracting(Notification::getChannel, Notification::getOrganization, Notification::getType, Notification::getProject)
       .containsExactly(
-        tuple(emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, ""),
-        tuple(emailChannel.getKey(), NOTIF_NEW_ISSUES, ""),
-        tuple(twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, ""),
-        tuple(emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, "K1"),
-        tuple(emailChannel.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, "K1"),
-        tuple(twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, "K1"));
+        tuple(emailChannel.getKey(), "", NOTIF_MY_NEW_ISSUES, ""),
+        tuple(emailChannel.getKey(), "", NOTIF_NEW_ISSUES, ""),
+        tuple(twitterChannel.getKey(), "", NOTIF_MY_NEW_ISSUES, ""),
+        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, "K1"),
+        tuple(emailChannel.getKey(), organization.getKey(), NOTIF_NEW_QUALITY_GATE_STATUS, "K1"),
+        tuple(twitterChannel.getKey(), organization.getKey(), NOTIF_MY_NEW_ISSUES, "K1"));
   }
 
   @Test
   public void json_example() {
-    ComponentDto project = addComponent(newProjectDto(db.organizations().insert()).setKey(KEY_PROJECT_EXAMPLE_001).setName("My Project"));
+    OrganizationDto organization = db.organizations().insertForKey("my-org-1");
+    ComponentDto project = addComponent(newProjectDto(organization).setKey(KEY_PROJECT_EXAMPLE_001).setName("My Project"));
     notificationUpdater.add(dbSession, twitterChannel.getKey(), NOTIF_MY_NEW_ISSUES, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_MY_NEW_ISSUES, null);
     notificationUpdater.add(dbSession, emailChannel.getKey(), NOTIF_NEW_ISSUES, null);
@@ -195,7 +203,9 @@ public class ListActionTest {
 
     String result = ws.newRequest().execute().getInput();
 
-    assertJson(ws.getDef().responseExampleAsString()).withStrictArrayOrder().isSimilarTo(result);
+    assertJson(ws.getDef().responseExampleAsString())
+      .withStrictArrayOrder()
+      .isSimilarTo(result);
   }
 
   @Test
index 1cf7782806c913dfded1877097368b52485d1238..ac0cb0347485ed67afef3b3a5ff8da44a6046896 100644 (file)
@@ -35,6 +35,7 @@ message ListResponse {
 message Notification {
   optional string channel = 1;
   optional string type = 2;
+  optional string organization = 5;
   optional string project = 3;
   optional string projectName = 4;
 }