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;
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;
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;
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());
.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)))
}
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();
}
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;
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();
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);
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);
String result = ws.newRequest().execute().getInput();
- assertJson(ws.getDef().responseExampleAsString()).withStrictArrayOrder().isSimilarTo(result);
+ assertJson(ws.getDef().responseExampleAsString())
+ .withStrictArrayOrder()
+ .isSimilarTo(result);
}
@Test