diff options
48 files changed, 729 insertions, 1039 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java index d6ded94d712..cfe3b7fc4ad 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactory.java @@ -42,6 +42,7 @@ public class ProjectConfigurationFactory { Settings projectSettings = new ChildSettings(globalSettings); addSettings(projectSettings, projectUuid); if (!projectUuid.equals(branchUuid)) { + // TODO not supported? addSettings(projectSettings, branchUuid); } return new ConfigurationBridge(projectSettings); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java index 2f6df7a0bdd..c56459bc94f 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/analysis/ProjectConfigurationFactoryTest.java @@ -25,6 +25,7 @@ import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.MapSettings; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; +import org.sonar.db.project.ProjectDto; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto; @@ -46,13 +47,13 @@ public class ProjectConfigurationFactoryTest { @Test public void return_project_settings() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("1").setValue("val1"), newComponentPropertyDto(project).setKey("2").setValue("val2"), newComponentPropertyDto(project).setKey("3").setValue("val3")); - Configuration config = underTest.newProjectConfiguration(project.uuid(), project.uuid()); + Configuration config = underTest.newProjectConfiguration(project.getUuid(), project.getUuid()); assertThat(config.get("1")).hasValue("val1"); assertThat(config.get("2")).hasValue("val2"); @@ -62,11 +63,11 @@ public class ProjectConfigurationFactoryTest { @Test public void project_settings_override_global_settings() { settings.setProperty("key", "value"); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("key").setValue("value2")); - Configuration projectConfig = underTest.newProjectConfiguration(project.uuid(), project.uuid()); + Configuration projectConfig = underTest.newProjectConfiguration(project.getUuid(), project.getUuid()); assertThat(projectConfig.get("key")).hasValue("value2"); } diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java index 94fa0a6a606..d8562e7d72f 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java @@ -44,8 +44,10 @@ import org.sonar.db.audit.NoOpAuditPersister; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectData; +import org.sonar.db.entity.EntityDto; import org.sonar.db.measure.LiveMeasureDto; import org.sonar.db.metric.MetricDto; +import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.qualityprofile.QProfileDto; import static org.apache.commons.lang.math.RandomUtils.nextInt; @@ -327,6 +329,60 @@ public class ProjectDaoIT { assertThat(projectUuids).containsExactlyInAnyOrder(project.projectUuid(), project2.projectUuid()); } + @Test + public void selectEntitiesByKeys_shouldReturnAllEntities() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + assertThat(projectDao.selectEntitiesByKeys(db.getSession(), List.of(application.projectKey(), project.projectKey(), portfolio.getKey(), "unknown"))) + .extracting(EntityDto::getUuid) + .containsOnly(application.projectUuid(), project.projectUuid(), portfolio.getUuid()); + } + + @Test + public void selectEntitiesByUuids_shouldReturnAllEntities() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + assertThat(projectDao.selectEntitiesByUuids(db.getSession(), List.of(application.projectUuid(), project.projectUuid(), portfolio.getUuid(), "unknown"))) + .extracting(EntityDto::getKey) + .containsOnly(application.projectKey(), project.projectKey(), portfolio.getKey()); + } + + @Test + public void selectEntityByUuid_shouldReturnAllEntities() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + assertThat(projectDao.selectEntityByUuid(db.getSession(), application.projectUuid()).get().getKey()).isEqualTo(application.projectKey()); + assertThat(projectDao.selectEntityByUuid(db.getSession(), project.projectUuid()).get().getKey()).isEqualTo(project.projectKey()); + assertThat(projectDao.selectEntityByUuid(db.getSession(), portfolio.getUuid()).get().getKey()).isEqualTo(portfolio.getKey()); + } + + @Test + public void selectEntityByUuid_whenNoMatch_shouldReturnEmpty() { + assertThat(projectDao.selectEntityByUuid(db.getSession(), "unknown")).isEmpty(); + } + + @Test + public void selectEntityByKey_shouldReturnAllEntities() { + ProjectData application = db.components().insertPrivateApplication(); + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + assertThat(projectDao.selectEntityByKey(db.getSession(), application.projectKey()).get().getUuid()).isEqualTo(application.projectUuid()); + assertThat(projectDao.selectEntityByKey(db.getSession(), project.projectKey()).get().getUuid()).isEqualTo(project.projectUuid()); + assertThat(projectDao.selectEntityByKey(db.getSession(), portfolio.getKey()).get().getUuid()).isEqualTo(portfolio.getUuid()); + } + + @Test + public void selectEntityByKey_whenNoMatch_shouldReturnEmpty() { + assertThat(projectDao.selectEntityByKey(db.getSession(), "unknown")).isEmpty(); + } + private void insertDefaultQualityProfile(String language) { QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language)); db.qualityProfiles().setAsDefault(profile); diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/property/PropertiesDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/property/PropertiesDaoIT.java index 789f708f66f..9c9d8799598 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/property/PropertiesDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/property/PropertiesDaoIT.java @@ -45,6 +45,7 @@ import org.sonar.db.EmailSubscriberDto; import org.sonar.db.audit.AuditPersister; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import static com.google.common.collect.ImmutableSet.of; @@ -89,52 +90,6 @@ public class PropertiesDaoIT { } @Test - public void shouldFindUsersForNotification() { - ComponentDto project1 = insertPrivateProject("uuid_45"); - ComponentDto project2 = insertPrivateProject("uuid_56"); - UserDto user1 = db.users().insertUser(u -> u.setLogin("user1")); - UserDto user2 = db.users().insertUser(u -> u.setLogin("user2")); - UserDto user3 = db.users().insertUser(u -> u.setLogin("user3")); - insertProperty("notification.NewViolations.Email", "true", project1.uuid(), user2.getUuid(), user2.getLogin(), - project1.getKey(), project1.name()); - insertProperty("notification.NewViolations.Twitter", "true", null, user3.getUuid(), user3.getLogin(), - null, null); - insertProperty("notification.NewViolations.Twitter", "true", project2.uuid(), user1.getUuid(), user1.getLogin(), - project2.getKey(), project2.name()); - insertProperty("notification.NewViolations.Twitter", "true", project1.uuid(), user2.getUuid(), user2.getLogin(), - project1.getKey(), project1.name()); - insertProperty("notification.NewViolations.Twitter", "true", project2.uuid(), user3.getUuid(), user3.getLogin(), - project2.getKey(), project2.name()); - db.users().insertProjectPermissionOnUser(user2, UserRole.USER, project1); - db.users().insertProjectPermissionOnUser(user3, UserRole.USER, project2); - db.users().insertProjectPermissionOnUser(user1, UserRole.USER, project2); - - assertThat(underTest.findUsersForNotification("NewViolations", "Email", null)) - .isEmpty(); - - assertThat(underTest.findUsersForNotification("NewViolations", "Email", "uuid_78")) - .isEmpty(); - - assertThat(underTest.findUsersForNotification("NewViolations", "Email", project1.getKey())) - .containsOnly(new Subscriber("user2", false)); - - assertThat(underTest.findUsersForNotification("NewViolations", "Email", project2.getKey())) - .isEmpty(); - - assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", null)) - .containsOnly(new Subscriber("user3", true)); - - assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", "uuid_78")) - .containsOnly(new Subscriber("user3", true)); - - assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", project1.getKey())) - .containsOnly(new Subscriber("user2", false), new Subscriber("user3", true)); - - assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", project2.getKey())) - .containsOnly(new Subscriber("user1", false), new Subscriber("user3", true), new Subscriber("user3", false)); - } - - @Test public void hasNotificationSubscribers() { UserDto user1 = db.users().insertUser(u -> u.setLogin("user1")); UserDto user2 = db.users().insertUser(u -> u.setLogin("user2")); @@ -615,31 +570,31 @@ public class PropertiesDaoIT { @Test public void select_properties_by_keys_and_component_ids() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); UserDto user = db.users().insertUser(); String key = "key"; String anotherKey = "anotherKey"; insertProperties(null, null, null, newGlobalPropertyDto().setKey(key)); - insertProperties(null, project.getKey(), project.name(), newComponentPropertyDto(project).setKey(key)); - insertProperties(null, project2.getKey(), project2.name(), newComponentPropertyDto(project2).setKey(key), + insertProperties(null, project.getKey(), project.getName(), newComponentPropertyDto(project).setKey(key)); + insertProperties(null, project2.getKey(), project2.getName(), newComponentPropertyDto(project2).setKey(key), newComponentPropertyDto(project2).setKey(anotherKey)); insertProperties(user.getLogin(), null, null, newUserPropertyDto(user).setKey(key)); - assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key), newHashSet(project.uuid()))) - .extracting("key", "componentUuid").containsOnly(tuple(key, project.uuid())); - assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key), newHashSet(project.uuid(), project2.uuid()))) + assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key), newHashSet(project.getUuid()))) + .extracting("key", "componentUuid").containsOnly(tuple(key, project.getUuid())); + assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key), newHashSet(project.getUuid(), project2.getUuid()))) .extracting("key", "componentUuid").containsOnly( - tuple(key, project.uuid()), - tuple(key, project2.uuid())); - assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key, anotherKey), newHashSet(project.uuid(), project2.uuid()))) + tuple(key, project.getUuid()), + tuple(key, project2.getUuid())); + assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet(key, anotherKey), newHashSet(project.getUuid(), project2.getUuid()))) .extracting("key", "componentUuid").containsOnly( - tuple(key, project.uuid()), - tuple(key, project2.uuid()), - tuple(anotherKey, project2.uuid())); + tuple(key, project.getUuid()), + tuple(key, project2.getUuid()), + tuple(anotherKey, project2.getUuid())); - assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet("unknown"), newHashSet(project.uuid()))).isEmpty(); + assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet("unknown"), newHashSet(project.getUuid()))).isEmpty(); assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet("key"), newHashSet("uuid123456789"))).isEmpty(); assertThat(underTest.selectPropertiesByKeysAndComponentUuids(session, newHashSet("unknown"), newHashSet("uuid123456789"))).isEmpty(); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index c87a74221e7..a36feeb394e 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -64,6 +64,7 @@ import org.sonar.db.component.UuidWithBranchUuidDto; import org.sonar.db.component.ViewsSnapshotDto; import org.sonar.db.duplication.DuplicationMapper; import org.sonar.db.duplication.DuplicationUnitDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.es.EsQueueMapper; import org.sonar.db.event.EventComponentChangeMapper; import org.sonar.db.event.EventDto; @@ -195,6 +196,7 @@ public class MyBatis { confBuilder.loadAlias("CeTaskCharacteristic", CeTaskCharacteristicDto.class); confBuilder.loadAlias("Component", ComponentDto.class); confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class); + confBuilder.loadAlias("Entity", EntityDto.class); confBuilder.loadAlias("Event", EventDto.class); confBuilder.loadAlias("ExternalGroup", ExternalGroupDto.class); confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java new file mode 100644 index 00000000000..11aa6ef3d37 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info 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.db.entity; + +import java.util.Objects; + +/** + * Represents a project, an application, a portfolio or a sub-portfolio. + * Entities are stored either in the projects or portfolios tables. + */ +public class EntityDto { + protected String kee; + protected String uuid; + protected String name; + protected String qualifier; + protected boolean isPrivate; + + public String getKey() { + return kee; + } + + public String getKee() { + return kee; + } + + public String getUuid() { + return uuid; + } + + /** + * Can be TRK, APP, VW or SVW + */ + public String getQualifier() { + return qualifier; + } + + public String getName() { + return name; + } + + public boolean isPrivate() { + return isPrivate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof EntityDto entityDto)) { + return false; + } + return Objects.equals(uuid, entityDto.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java index c4fd120a1a8..fe6c28f84ed 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java @@ -19,20 +19,17 @@ */ package org.sonar.db.portfolio; -import java.util.Objects; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.sonar.api.resources.Qualifiers; +import org.sonar.db.entity.EntityDto; -public class PortfolioDto { +public class PortfolioDto extends EntityDto { public enum SelectionMode { NONE, MANUAL, REGEXP, REST, TAGS } - private String uuid; - private String kee; - private String name; private String description; - private boolean isPrivate = false; private String branchKey; private String rootUuid; @@ -79,6 +76,14 @@ public class PortfolioDto { this.branchKey = branchKey; } + @Override + public String getQualifier() { + if (isRoot()) { + return Qualifiers.VIEW; + } + return Qualifiers.SUBVIEW; + } + public String getSelectionMode() { return selectionMode; } @@ -121,27 +126,12 @@ public class PortfolioDto { return this; } - public String getUuid() { - return uuid; - } - public PortfolioDto setUuid(String uuid) { this.uuid = uuid; return this; } /** - * This is the getter used by MyBatis mapper. - */ - public String getKee() { - return kee; - } - - public String getKey() { - return getKee(); - } - - /** * This is the setter used by MyBatis mapper. */ public PortfolioDto setKee(String kee) { @@ -153,19 +143,11 @@ public class PortfolioDto { return setKee(key); } - public boolean isPrivate() { - return isPrivate; - } - public PortfolioDto setPrivate(boolean aPrivate) { isPrivate = aPrivate; return this; } - public String getName() { - return name; - } - public PortfolioDto setName(String name) { this.name = name; return this; @@ -180,22 +162,4 @@ public class PortfolioDto { this.description = description; return this; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PortfolioDto that = (PortfolioDto) o; - return Objects.equals(uuid, that.uuid); - } - - @Override - public int hashCode() { - return uuid != null ? uuid.hashCode() : 0; - } - } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java index fb03394e5b1..27ab59c83d3 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java @@ -19,6 +19,7 @@ */ package org.sonar.db.project; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -29,7 +30,9 @@ import org.sonar.db.Dao; import org.sonar.db.DbSession; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.model.ComponentNewValue; +import org.sonar.db.entity.EntityDto; +import static java.util.Collections.emptyList; import static org.sonar.db.DatabaseUtils.executeLargeInputs; public class ProjectDao implements Dao { @@ -70,14 +73,14 @@ public class ProjectDao implements Dao { public List<ProjectDto> selectProjectsByKeys(DbSession session, Set<String> keys) { if (keys.isEmpty()) { - return Collections.emptyList(); + return emptyList(); } return mapper(session).selectProjectsByKeys(keys); } public List<ProjectDto> selectApplicationsByKeys(DbSession session, Set<String> keys) { if (keys.isEmpty()) { - return Collections.emptyList(); + return emptyList(); } return executeLargeInputs(keys, partition -> mapper(session).selectApplicationsByKeys(partition)); @@ -101,7 +104,7 @@ public class ProjectDao implements Dao { public List<ProjectDto> selectByUuids(DbSession session, Set<String> uuids) { if (uuids.isEmpty()) { - return Collections.emptyList(); + return emptyList(); } return executeLargeInputs(uuids, partition -> mapper(session).selectByUuids(partition)); } @@ -143,4 +146,28 @@ public class ProjectDao implements Dao { public long getNclocSum(DbSession dbSession, @Nullable String projectUuidToExclude) { return Optional.ofNullable(mapper(dbSession).getNclocSum(projectUuidToExclude)).orElse(0L); } + + public Optional<EntityDto> selectEntityByUuid(DbSession dbSession, String uuid) { + return Optional.ofNullable(mapper(dbSession).selectEntityByUuid(uuid)); + } + + public List<EntityDto> selectEntitiesByUuids(DbSession dbSession, Collection<String> uuids) { + if (uuids.isEmpty()) { + return emptyList(); + } + return mapper(dbSession).selectEntitiesByUuids(uuids); + } + + public Optional<EntityDto> selectEntityByKey(DbSession dbSession, String key) { + return Optional.ofNullable(mapper(dbSession).selectEntityByKey(key)); + } + + public List<EntityDto> selectEntitiesByKeys(DbSession dbSession, Collection<String> keys) { + if (keys.isEmpty()) { + return emptyList(); + } + return mapper(dbSession).selectEntitiesByKeys(keys); + } + + } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java index 840e16a2715..738be9d67d9 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java @@ -24,18 +24,14 @@ import java.util.Objects; import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.sonar.db.entity.EntityDto; import static org.apache.commons.lang.StringUtils.trimToNull; import static org.sonar.db.component.DbTagsReader.readDbTags; -public class ProjectDto { +public class ProjectDto extends EntityDto { private static final String TAGS_SEPARATOR = ","; - private String uuid; - private String kee; - private String qualifier; - private String name; private String description; - private boolean isPrivate = false; private String tags; private long createdAt; private long updatedAt; @@ -62,27 +58,12 @@ public class ProjectDto { return this; } - public String getUuid() { - return uuid; - } - public ProjectDto setUuid(String uuid) { this.uuid = uuid; return this; } /** - * This is the getter used by MyBatis mapper. - */ - public String getKee() { - return kee; - } - - public String getKey() { - return getKee(); - } - - /** * This is the setter used by MyBatis mapper. */ public ProjectDto setKee(String kee) { @@ -94,10 +75,6 @@ public class ProjectDto { return setKee(key); } - public boolean isPrivate() { - return isPrivate; - } - public ProjectDto setPrivate(boolean aPrivate) { isPrivate = aPrivate; return this; @@ -127,10 +104,6 @@ public class ProjectDto { return this; } - public String getName() { - return name; - } - public ProjectDto setName(String name) { this.name = name; return this; @@ -146,30 +119,8 @@ public class ProjectDto { return this; } - public String getQualifier() { - return qualifier; - } - public ProjectDto setQualifier(String qualifier) { this.qualifier = qualifier; return this; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ProjectDto that = (ProjectDto) o; - return Objects.equals(uuid, that.uuid); - } - - @Override - public int hashCode() { - return uuid != null ? uuid.hashCode() : 0; - } - } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java index 928c98ec899..e5f54671e70 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java @@ -21,10 +21,13 @@ package org.sonar.db.project; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.ibatis.annotations.Param; +import org.sonar.db.DbSession; +import org.sonar.db.entity.EntityDto; public interface ProjectMapper { @@ -72,4 +75,13 @@ public interface ProjectMapper { @CheckForNull Long getNclocSum(@Nullable @Param("projectUuidToExclude") String projectUuidToExclude); + @CheckForNull + EntityDto selectEntityByUuid(String uuid); + + List<EntityDto> selectEntitiesByUuids(@Param("uuids") Collection<String> uuids); + + @CheckForNull + EntityDto selectEntityByKey(String key); + + List<EntityDto> selectEntitiesByKeys(@Param("keys") Collection<String> keys); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java index 41c1b7d438a..8043b74cb8b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java @@ -65,20 +65,6 @@ public class PropertiesDao implements Dao { this.auditPersister = auditPersister; } - /** - * Returns the logins of users who have subscribed to the given notification dispatcher with the given notification channel. - * If a resource ID is passed, the search is made on users who have specifically subscribed for the given resource. - * Note that {@link UserRole#USER} permission is not checked here, filter the results with - * {@link org.sonar.db.permission.AuthorizationDao#keepAuthorizedLoginsOnProject} - * - * @return the list of Subscriber (maybe be empty - obviously) - */ - public Set<Subscriber> findUsersForNotification(String notificationDispatcherKey, String notificationChannelKey, @Nullable String projectKey) { - try (DbSession session = mybatis.openSession(false)) { - return getMapper(session).findUsersForNotification(NOTIFICATION_PREFIX + notificationDispatcherKey + "." + notificationChannelKey, projectKey); - } - } - public Set<EmailSubscriberDto> findEmailSubscribersForNotification(DbSession dbSession, String notificationDispatcherKey, String notificationChannelKey, @Nullable String projectKey) { return getMapper(dbSession).findEmailRecipientsForNotification(NOTIFICATION_PREFIX + notificationDispatcherKey + "." + notificationChannelKey, projectKey, null); @@ -171,6 +157,7 @@ public class PropertiesDao implements Dao { return getMapper(session).selectByKeyAndMatchingValue(key, value); } + //TODO public List<PropertyDto> selectByKeyAndUserUuidAndComponentQualifier(DbSession session, String key, String userUuid, String qualifier) { return getMapper(session).selectByKeyAndUserUuidAndComponentQualifier(key, userUuid, qualifier); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java index 17ae9dab86a..3ba2665e206 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java @@ -27,8 +27,6 @@ import org.sonar.db.EmailSubscriberDto; public interface PropertiesMapper { - Set<Subscriber> findUsersForNotification(@Param("notifKey") String notificationKey, @Nullable @Param("projectKey") String projectKey); - Set<EmailSubscriberDto> findEmailRecipientsForNotification(@Param("notifKey") String notificationKey, @Nullable @Param("projectKey") String projectKey, @Nullable @Param("logins") List<String> logins); @@ -48,10 +46,6 @@ public interface PropertiesMapper { List<PropertyDto> selectByKeyAndMatchingValue(@Param("key") String key, @Param("value") String value); - List<String> selectUuidsByUser(@Param("userUuid") String userUuid); - - List<String> selectIdsByMatchingLogin(@Param("login") String login, @Param("propertyKeys") List<String> propertyKeys); - void insertAsEmpty(@Param("uuid") String uuid, @Param("key") String key, @Nullable @Param("userUuid") String userUuid, @Nullable @Param("componentUuid") String componentUuid, @Param("now") long now); @@ -65,8 +59,6 @@ public interface PropertiesMapper { int deleteProjectProperty(@Param("key") String key, @Param("componentUuid") String componentUuid); - int deleteProjectProperties(@Param("key") String key, @Param("value") String value); - int deleteGlobalProperty(@Param("key") String key); int deleteByQuery(@Param("query") PropertyQuery query); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml index 64679854e77..1ed2db7d48a 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml @@ -202,4 +202,64 @@ </if> </select> + <sql id="entityProjectColumns"> + p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, p.qualifier as qualifier + </sql> + + <sql id="entityPortfolioColumns"> + p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, + case when p.parent_uuid is null then 'VW' else 'SVW' end as qualifier + </sql> + + <select id="selectEntityByUuid" parameterType="string" resultType="Entity"> + (select <include refid="entityProjectColumns"/> + from projects p + where p.uuid = #{uuid,jdbcType=VARCHAR}) + UNION + (select <include refid="entityPortfolioColumns"/> + from portfolios p + where p.uuid = #{uuid,jdbcType=VARCHAR}) + </select> + + <select id="selectEntitiesByUuids" resultType="Entity"> + (select <include refid="entityProjectColumns"/> + from projects p + where p.uuid in + <foreach collection="uuids" open="(" close=")" item="uuid" separator=","> + #{uuid,jdbcType=VARCHAR} + </foreach>) + UNION + (select <include refid="entityPortfolioColumns"/> + from portfolios p + where p.uuid in + <foreach collection="uuids" open="(" close=")" item="uuid" separator=","> + #{uuid,jdbcType=VARCHAR} + </foreach>) + </select> + + <select id="selectEntityByKey" parameterType="string" resultType="Entity"> + (select <include refid="entityProjectColumns"/> + from projects p + where p.kee = #{key,jdbcType=VARCHAR}) + UNION + (select <include refid="entityPortfolioColumns"/> + from portfolios p + where p.kee = #{key,jdbcType=VARCHAR}) + </select> + + <select id="selectEntitiesByKeys" parameterType="string" resultType="Entity"> + (select <include refid="entityProjectColumns"/> + from projects p + where p.kee in + <foreach collection="keys" open="(" close=")" item="kee" separator=","> + #{kee,jdbcType=VARCHAR} + </foreach>) + UNION + (select <include refid="entityPortfolioColumns"/> + from portfolios p + where p.kee in + <foreach collection="keys" open="(" close=")" item="kee" separator=","> + #{kee,jdbcType=VARCHAR} + </foreach>) </select> + </mapper> diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml index f1f3f77500a..72b92e78ae2 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml @@ -3,35 +3,6 @@ <mapper namespace="org.sonar.db.property.PropertiesMapper"> - <select id="findUsersForNotification" parameterType="map" resultType="org.sonar.db.property.Subscriber"> - SELECT - u.login as "login", - ${_true} as "global" - FROM - users u - INNER JOIN properties p ON p.user_uuid = u.uuid - WHERE - p.prop_key = #{notifKey,jdbcType=VARCHAR} - AND p.text_value = 'true' - AND p.component_uuid IS NULL - - <if test="projectKey != null"> - UNION - - SELECT - u.login as "login", - ${_false} as "global" - FROM - users u - INNER JOIN components c on c.kee = #{projectKey,jdbcType=VARCHAR} - INNER JOIN properties p ON p.user_uuid = u.uuid - WHERE - p.prop_key = #{notifKey,jdbcType=VARCHAR} - AND p.text_value = 'true' - AND p.component_uuid = c.uuid - </if> - </select> - <select id="findEmailRecipientsForNotification" parameterType="map" resultType="org.sonar.db.EmailSubscriberDto"> SELECT u.login as "login", @@ -59,13 +30,13 @@ u.email as "email" FROM users u - INNER JOIN components c on - c.kee = #{projectKey,jdbcType=VARCHAR} + INNER JOIN projects proj on + proj.kee = #{projectKey,jdbcType=VARCHAR} INNER JOIN properties p ON p.user_uuid = u.uuid and p.prop_key = #{notifKey,jdbcType=VARCHAR} and p.text_value = 'true' - and p.component_uuid = c.uuid + and p.component_uuid = proj.uuid WHERE u.email is not null <if test="logins != null"> @@ -189,24 +160,6 @@ </where> </select> - <select id="selectUuidsByUser" parameterType="map" resultType="String"> - select py.uuid - from properties py - where - py.user_uuid=#{userUuid,jdbcType=VARCHAR} - </select> - - <select id="selectIdsByMatchingLogin" parameterType="String" resultType="String"> - select py.uuid - from properties py - where - py.text_value like #{login,jdbcType=VARCHAR} - and py.prop_key in - <foreach item="property" index="index" collection="propertyKeys" open="(" separator="," close=")"> - #{property,jdbcType=VARCHAR} - </foreach> - </select> - <select id="selectByKeyAndMatchingValue" parameterType="map" resultType="ScrapProperty"> select <include refid="columnsToScrapPropertyDto"/> @@ -313,15 +266,6 @@ and user_uuid is null </delete> - <delete id="deleteProjectProperties" parameterType="map"> - delete from properties - where - prop_key=#{key} - and text_value = #{value} - and component_uuid is not null - and user_uuid is null - </delete> - <delete id="deleteGlobalProperty" parameterType="string"> delete from properties where diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/favorite/FavoriteDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/favorite/FavoriteDbTester.java index df77f0e2b08..0d9de5a22ad 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/favorite/FavoriteDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/favorite/FavoriteDbTester.java @@ -24,6 +24,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.entity.EntityDto; import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; @@ -38,29 +39,29 @@ public class FavoriteDbTester { this.dbSession = db.getSession(); } - public void add(ComponentDto componentDto, String userUuid, String userLogin) { + public void add(EntityDto entity, String userUuid, String userLogin) { dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto() .setKey(PROP_FAVORITE_KEY) .setUserUuid(userUuid) - .setComponentUuid(componentDto.uuid()), - userLogin, componentDto.getKey(), componentDto.name(), componentDto.qualifier()); + .setComponentUuid(entity.getUuid()), + userLogin, entity.getKey(), entity.getName(), entity.getQualifier()); dbSession.commit(); } - public boolean hasFavorite(ComponentDto componentDto, String userUuid) { + public boolean hasFavorite(EntityDto entity, String userUuid) { List<PropertyDto> result = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setKey(PROP_FAVORITE_KEY) - .setComponentUuid(componentDto.uuid()) + .setComponentUuid(entity.getUuid()) .setUserUuid(userUuid) .build(), dbSession); return !result.isEmpty(); } - public boolean hasNoFavorite(ComponentDto componentDto) { + public boolean hasNoFavorite(EntityDto entity) { List<PropertyDto> result = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setKey(PROP_FAVORITE_KEY) - .setComponentUuid(componentDto.uuid()) + .setComponentUuid(entity.getUuid()) .build(), dbSession); return result.isEmpty(); } diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyDbTester.java index 94e4c778f3b..c1a46ecb119 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyDbTester.java @@ -28,7 +28,7 @@ import javax.annotation.Nullable; 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.entity.EntityDto; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -75,15 +75,15 @@ public class PropertyDbTester { null, null, null, null); } - public void insertPropertySet(String settingBaseKey, @Nullable ComponentDto componentDto, Map<String, String>... fieldValues) { + public void insertPropertySet(String settingBaseKey, @Nullable EntityDto entity, Map<String, String>... fieldValues) { int index = 1; List<PropertyDto> propertyDtos = new ArrayList<>(); List<String> ids = new ArrayList<>(); for (Map<String, String> fieldValue : fieldValues) { for (Map.Entry<String, String> entry : fieldValue.entrySet()) { String key = settingBaseKey + "." + index + "." + entry.getKey(); - if (componentDto != null) { - propertyDtos.add(newComponentPropertyDto(componentDto).setKey(key).setValue(entry.getValue())); + if (entity != null) { + propertyDtos.add(newComponentPropertyDto(entity).setKey(key).setValue(entry.getValue())); } else { propertyDtos.add(newGlobalPropertyDto().setKey(key).setValue(entry.getValue())); } @@ -92,14 +92,14 @@ public class PropertyDbTester { index++; } String idsValue = Joiner.on(",").join(ids); - if (componentDto != null) { - propertyDtos.add(newComponentPropertyDto(componentDto).setKey(settingBaseKey).setValue(idsValue)); + if (entity != null) { + propertyDtos.add(newComponentPropertyDto(entity).setKey(settingBaseKey).setValue(idsValue)); } else { propertyDtos.add(newGlobalPropertyDto().setKey(settingBaseKey).setValue(idsValue)); } - String componentKey = componentDto == null ? null : componentDto.getKey(); - String componentName = componentDto == null ? null : componentDto.name(); - String qualififer = componentDto == null ? null : componentDto.qualifier(); + String componentKey = entity == null ? null : entity.getKey(); + String componentName = entity == null ? null : entity.getName(); + String qualififer = entity == null ? null : entity.getQualifier(); insertProperties(propertyDtos, null, componentKey, componentName, qualififer); } diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java index b520e05a4b3..6542ac1fbee 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/property/PropertyTesting.java @@ -22,6 +22,7 @@ package org.sonar.db.property; import javax.annotation.Nullable; import org.apache.commons.lang.math.RandomUtils; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.user.UserDto; import static com.google.common.base.Preconditions.checkNotNull; @@ -47,9 +48,9 @@ public class PropertyTesting { return newPropertyDto(key, value, component.uuid(), null); } - public static PropertyDto newComponentPropertyDto(ComponentDto component) { - checkNotNull(component.uuid()); - return newPropertyDto(component.uuid(), null); + public static PropertyDto newComponentPropertyDto(EntityDto entity) { + checkNotNull(entity.getUuid()); + return newPropertyDto(entity.getUuid(), null); } public static PropertyDto newUserPropertyDto(String key, String value, UserDto user) { diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/favorite/FavoriteUpdaterIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/favorite/FavoriteUpdaterIT.java index 82a496a830c..2a69e111bf7 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/favorite/FavoriteUpdaterIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/favorite/FavoriteUpdaterIT.java @@ -26,6 +26,8 @@ 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.entity.EntityDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.property.PropertyQuery; import org.sonar.db.user.UserDto; @@ -44,7 +46,7 @@ public class FavoriteUpdaterIT { @Test public void put_favorite() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); UserDto user = db.users().insertUser(); assertNoFavorite(project, user); @@ -55,23 +57,23 @@ public class FavoriteUpdaterIT { @Test public void do_nothing_when_no_user() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); underTest.add(dbSession, project, null, null,true); assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() - .setComponentUuid(project.uuid()) + .setComponentUuid(project.getUuid()) .build(), dbSession)).isEmpty(); } @Test public void do_not_add_favorite_when_already_100_favorite_projects() { UserDto user = db.users().insertUser(); - IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), user.getUuid(), user.getName())); + IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getName())); assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setUserUuid(user.getUuid()) .build(), dbSession)).hasSize(100); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); underTest.add(dbSession, project, user.getUuid(), user.getLogin(), false); @@ -83,12 +85,12 @@ public class FavoriteUpdaterIT { @Test public void do_not_add_favorite_when_already_100_favorite_portfolios() { UserDto user = db.users().insertUser(); - IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), + IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin())); assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setUserUuid(user.getUuid()) .build(), dbSession)).hasSize(100); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); underTest.add(dbSession, project, user.getUuid(), user.getLogin(), false); @@ -100,9 +102,9 @@ public class FavoriteUpdaterIT { @Test public void fail_when_more_than_100_projects_favorites() { UserDto user = db.users().insertUser(); - IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), + IntStream.rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin())); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); assertThatThrownBy(() -> underTest.add(dbSession, project, user.getUuid(), user.getLogin(), true)) .isInstanceOf(IllegalArgumentException.class) @@ -111,27 +113,27 @@ public class FavoriteUpdaterIT { @Test public void fail_when_adding_existing_favorite() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); UserDto user = db.users().insertUser(); underTest.add(dbSession, project, user.getUuid(), user.getLogin(), true); assertFavorite(project, user); assertThatThrownBy(() -> underTest.add(dbSession, project, user.getUuid(), user.getLogin(), true)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage(String.format("Component '%s' (uuid: %s) is already a favorite", project.getKey(), project.uuid())); + .hasMessage(String.format("Component '%s' (uuid: %s) is already a favorite", project.getKey(), project.getUuid())); } - private void assertFavorite(ComponentDto project, UserDto user) { + private void assertFavorite(EntityDto entity, UserDto user) { assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setUserUuid(user.getUuid()) - .setComponentUuid(project.uuid()) + .setComponentUuid(entity.getUuid()) .build(), dbSession)).hasSize(1); } - private void assertNoFavorite(ComponentDto project, UserDto user) { + private void assertNoFavorite(EntityDto entity, UserDto user) { assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setUserUuid(user.getUuid()) - .setComponentUuid(project.uuid()) + .setComponentUuid(entity.getUuid()) .build(), dbSession)).isEmpty(); } } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/favorite/FavoriteUpdater.java b/server/sonar-server-common/src/main/java/org/sonar/server/favorite/FavoriteUpdater.java index 2fd5671d931..54940fc75a1 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/favorite/FavoriteUpdater.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/favorite/FavoriteUpdater.java @@ -24,6 +24,7 @@ import javax.annotation.Nullable; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; @@ -41,7 +42,7 @@ public class FavoriteUpdater { /** * Set favorite to the logged in user. If no user, no action is done */ - public void add(DbSession dbSession, ComponentDto componentDto, @Nullable String userUuid, @Nullable String userLogin, boolean failIfTooManyFavorites) { + public void add(DbSession dbSession, EntityDto entity, @Nullable String userUuid, @Nullable String userLogin, boolean failIfTooManyFavorites) { if (userUuid == null) { return; } @@ -49,21 +50,21 @@ public class FavoriteUpdater { List<PropertyDto> existingFavoriteOnComponent = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder() .setKey(PROP_FAVORITE_KEY) .setUserUuid(userUuid) - .setComponentUuid(componentDto.uuid()) + .setComponentUuid(entity.getUuid()) .build(), dbSession); - checkArgument(existingFavoriteOnComponent.isEmpty(), "Component '%s' (uuid: %s) is already a favorite", componentDto.getKey(), componentDto.uuid()); + checkArgument(existingFavoriteOnComponent.isEmpty(), "Component '%s' (uuid: %s) is already a favorite", entity.getKey(), entity.getUuid()); - List<PropertyDto> existingFavorites = dbClient.propertiesDao().selectByKeyAndUserUuidAndComponentQualifier(dbSession, PROP_FAVORITE_KEY, userUuid, componentDto.qualifier()); + List<PropertyDto> existingFavorites = dbClient.propertiesDao().selectByKeyAndUserUuidAndComponentQualifier(dbSession, PROP_FAVORITE_KEY, userUuid, entity.getQualifier()); if (existingFavorites.size() >= 100) { - checkArgument(!failIfTooManyFavorites, "You cannot have more than 100 favorites on components with qualifier '%s'", componentDto.qualifier()); + checkArgument(!failIfTooManyFavorites, "You cannot have more than 100 favorites on components with qualifier '%s'", entity.getQualifier()); return; } dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto() .setKey(PROP_FAVORITE_KEY) - .setComponentUuid(componentDto.uuid()) + .setComponentUuid(entity.getUuid()) .setUserUuid(userUuid), userLogin, - componentDto.getKey(), componentDto.name(), componentDto.qualifier()); + entity.getKey(), entity.getName(), entity.getQualifier()); } /** diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java b/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java index 8b6800ae195..eed10f265f2 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java @@ -113,69 +113,10 @@ public class DefaultNotificationManager implements NotificationManager { return dbClient.notificationQueueDao().count(); } - /** - * {@inheritDoc} - */ - @Override - public Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, - String projectKey, SubscriberPermissionsOnProject subscriberPermissionsOnProject) { - verifyProjectKey(projectKey); - String dispatcherKey = dispatcher.getKey(); - - Set<SubscriberAndChannel> subscriberAndChannels = Arrays.stream(notificationChannels) - .flatMap(notificationChannel -> toSubscriberAndChannels(dispatcherKey, projectKey, notificationChannel)) - .collect(Collectors.toSet()); - - if (subscriberAndChannels.isEmpty()) { - return ImmutableMultimap.of(); - } - - ImmutableSetMultimap.Builder<String, NotificationChannel> builder = ImmutableSetMultimap.builder(); - try (DbSession dbSession = dbClient.openSession(false)) { - Set<String> authorizedLogins = keepAuthorizedLogins(dbSession, projectKey, subscriberAndChannels, subscriberPermissionsOnProject); - subscriberAndChannels.stream() - .filter(subscriberAndChannel -> authorizedLogins.contains(subscriberAndChannel.subscriber().getLogin())) - .forEach(subscriberAndChannel -> builder.put(subscriberAndChannel.subscriber().getLogin(), subscriberAndChannel.channel())); - } - return builder.build(); - } - private static void verifyProjectKey(String projectKey) { requireNonNull(projectKey, "projectKey is mandatory"); } - private Stream<SubscriberAndChannel> toSubscriberAndChannels(String dispatcherKey, String projectKey, NotificationChannel notificationChannel) { - Set<Subscriber> usersForNotification = dbClient.propertiesDao().findUsersForNotification(dispatcherKey, notificationChannel.getKey(), projectKey); - return usersForNotification - .stream() - .map(login -> new SubscriberAndChannel(login, notificationChannel)); - } - - private Set<String> keepAuthorizedLogins(DbSession dbSession, String projectKey, Set<SubscriberAndChannel> subscriberAndChannels, - SubscriberPermissionsOnProject requiredPermissions) { - if (requiredPermissions.getGlobalSubscribers().equals(requiredPermissions.getProjectSubscribers())) { - return keepAuthorizedLogins(dbSession, projectKey, subscriberAndChannels, null, requiredPermissions.getGlobalSubscribers()); - } else { - return Stream - .concat( - keepAuthorizedLogins(dbSession, projectKey, subscriberAndChannels, true, requiredPermissions.getGlobalSubscribers()).stream(), - keepAuthorizedLogins(dbSession, projectKey, subscriberAndChannels, false, requiredPermissions.getProjectSubscribers()).stream()) - .collect(Collectors.toSet()); - } - } - - private Set<String> keepAuthorizedLogins(DbSession dbSession, String projectKey, Set<SubscriberAndChannel> subscriberAndChannels, - @Nullable Boolean global, String permission) { - Set<String> logins = subscriberAndChannels.stream() - .filter(s -> global == null || s.subscriber().isGlobal() == global) - .map(s -> s.subscriber().getLogin()) - .collect(Collectors.toSet()); - if (logins.isEmpty()) { - return Collections.emptySet(); - } - return dbClient.authorizationDao().keepAuthorizedLoginsOnProject(dbSession, logins, projectKey, permission); - } - @Override public Set<EmailRecipient> findSubscribedEmailRecipients(String dispatcherKey, String projectKey, SubscriberPermissionsOnProject subscriberPermissionsOnProject) { verifyProjectKey(projectKey); @@ -244,23 +185,6 @@ public class DefaultNotificationManager implements NotificationManager { .filter(s -> authorizedLogins.contains(s.getLogin())); } - private record SubscriberAndChannel(Subscriber subscriber, NotificationChannel channel) { - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SubscriberAndChannel that = (SubscriberAndChannel) o; - return Objects.equals(subscriber, that.subscriber) && - Objects.equals(channel, that.channel); - } - - } - @VisibleForTesting protected List<NotificationChannel> getChannels() { return Arrays.asList(notificationChannels); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java b/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java index 6517c4ee9a1..be336191a8f 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java @@ -44,23 +44,6 @@ public interface NotificationManager { */ <T extends Notification> void scheduleForSending(T notification); - /** - * <p> - * Returns the list of users who subscribed to the given dispatcher, along with the notification channels (email, twitter, ...) that they choose - * for this dispatcher. - * </p> - * <p> - * The resource ID can be null in case of notifications that have nothing to do with a specific project (like system notifications). - * </p> - * - * @param dispatcher the dispatcher for which this list of users is requested - * @param projectKey key of the project - * @param subscriberPermissionsOnProject the required permission for global and project subscribers - * @return the list of user login along with the subscribed channels - */ - Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectKey, - SubscriberPermissionsOnProject subscriberPermissionsOnProject); - record EmailRecipient(String login, String email) { public EmailRecipient(String login, String email) { this.login = requireNonNull(login, "login can't be null"); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java index d07f5d1567a..310615af703 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java @@ -143,125 +143,6 @@ public class DefaultNotificationManagerTest { } @Test - public void shouldFindNoRecipient() { - assertThat(underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45", new SubscriberPermissionsOnProject(UserRole.USER)).asMap().entrySet()) - .isEmpty(); - } - - @Test - public void shouldFindSubscribedRecipientForGivenResource() { - String projectKey = randomAlphabetic(6); - String otherProjectKey = randomAlphabetic(7); - when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectKey)) - .thenReturn(newHashSet(new Subscriber("user1", false), new Subscriber("user3", false), new Subscriber("user3", true))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", otherProjectKey)) - .thenReturn(newHashSet(new Subscriber("user2", false))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", true))); - when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user4", false))); - - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectKey, "user")) - .thenReturn(newHashSet("user1", "user3")); - - Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectKey, - ALL_MUST_HAVE_ROLE_USER); - assertThat(multiMap.entries()).hasSize(3); - - Map<String, Collection<NotificationChannel>> map = multiMap.asMap(); - assertThat(map.get("user1")).containsOnly(emailChannel); - assertThat(map.get("user2")).isNull(); - assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel); - assertThat(map.get("user4")).isNull(); - - // code is optimized to perform only 1 SQL requests for all channels - verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), anyString()); - } - - @Test - public void should_apply_distinct_permission_filtering_global_or_project_subscribers() { - String globalPermission = randomAlphanumeric(4); - String projectPermission = randomAlphanumeric(5); - String projectKey = randomAlphabetic(6); - String otherProjectKey = randomAlphabetic(7); - when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectKey)) - .thenReturn(newHashSet(new Subscriber("user1", false), new Subscriber("user3", false), new Subscriber("user3", true))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", otherProjectKey)) - .thenReturn(newHashSet(new Subscriber("user2", false))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", true))); - when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user4", false))); - - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3", "user4"), projectKey, globalPermission)) - .thenReturn(newHashSet("user3")); - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectKey, projectPermission)) - .thenReturn(newHashSet("user1", "user3")); - - Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectKey, - new SubscriberPermissionsOnProject(globalPermission, projectPermission)); - assertThat(multiMap.entries()).hasSize(3); - - Map<String, Collection<NotificationChannel>> map = multiMap.asMap(); - assertThat(map.get("user1")).containsOnly(emailChannel); - assertThat(map.get("user2")).isNull(); - assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel); - assertThat(map.get("user4")).isNull(); - - // code is optimized to perform only 2 SQL requests for all channels - verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); - verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); - } - - @Test - public void do_not_call_db_for_project_permission_filtering_if_there_is_no_project_subscriber() { - String globalPermission = randomAlphanumeric(4); - String projectPermission = randomAlphanumeric(5); - String projectKey = randomAlphabetic(6); - when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", true))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", true))); - - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3"), projectKey, globalPermission)) - .thenReturn(newHashSet("user3")); - - Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectKey, - new SubscriberPermissionsOnProject(globalPermission, projectPermission)); - assertThat(multiMap.entries()).hasSize(2); - - Map<String, Collection<NotificationChannel>> map = multiMap.asMap(); - assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel); - - verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); - verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); - } - - @Test - public void do_not_call_db_for_project_permission_filtering_if_there_is_no_global_subscriber() { - String globalPermission = randomAlphanumeric(4); - String projectPermission = randomAlphanumeric(5); - String projectKey = randomAlphabetic(6); - when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", false))); - when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectKey)) - .thenReturn(newHashSet(new Subscriber("user3", false))); - - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3"), projectKey, projectPermission)) - .thenReturn(newHashSet("user3")); - - Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectKey, - new SubscriberPermissionsOnProject(globalPermission, projectPermission)); - assertThat(multiMap.entries()).hasSize(2); - - Map<String, Collection<NotificationChannel>> map = multiMap.asMap(); - assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel); - - verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); - verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); - } - - @Test public void findSubscribedEmailRecipients_fails_with_NPE_if_projectKey_is_null() { String dispatcherKey = randomAlphabetic(12); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java index 818e5de16f1..44ee9a5e252 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/AbstractUserSession.java @@ -28,6 +28,7 @@ import javax.annotation.Nullable; import org.sonar.api.web.UserRole; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; @@ -88,7 +89,6 @@ public abstract class AbstractUserSession implements UserSession { @Override public boolean hasComponentPermission(String permission, ComponentDto component) { - Optional<String> projectUuid1 = componentUuidToProjectUuid(component.uuid()); return projectUuid1 @@ -102,6 +102,11 @@ public abstract class AbstractUserSession implements UserSession { } @Override + public final boolean hasEntityPermission(String permission, EntityDto entity) { + return hasProjectUuidPermission(permission, entity.getUuid()); + } + + @Override public final boolean hasProjectPermission(String permission, String projectUuid) { return hasProjectUuidPermission(permission, projectUuid); } @@ -148,6 +153,21 @@ public abstract class AbstractUserSession implements UserSession { return doKeepAuthorizedProjects(permission, projects); } + @Override + public <T extends EntityDto> List<T> keepAuthorizedEntities(String permission, Collection<T> projects) { + return doKeepAuthorizedEntities(permission, projects); + } + + /** + * Naive implementation, to be overridden if needed + */ + protected <T extends EntityDto> List<T> doKeepAuthorizedEntities(String permission, Collection<T> entities) { + boolean allowPublicComponent = PUBLIC_PERMISSIONS.contains(permission); + return entities.stream() + .filter(c -> (allowPublicComponent && !c.isPrivate()) || hasProjectPermission(permission, c.getUuid())) + .toList(); + } + /** * Naive implementation, to be overridden if needed */ @@ -202,6 +222,15 @@ public abstract class AbstractUserSession implements UserSession { } @Override + public UserSession checkEntityPermission(String projectPermission, EntityDto entity) { + if (hasEntityPermission(projectPermission, entity)) { + return this; + } + + throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); + } + + @Override public UserSession checkChildProjectsPermission(String projectPermission, ComponentDto component) { if (!APP.equals(component.qualifier()) || hasChildProjectsPermission(projectPermission, component)) { return this; diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java index 020c9e08acb..518b710e5f4 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java @@ -41,6 +41,7 @@ import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTreeQuery; import org.sonar.db.component.ComponentTreeQuery.Strategy; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; @@ -195,6 +196,17 @@ public class ServerUserSession extends AbstractUserSession { .toList(); } + @Override + public <T extends EntityDto> List<T> keepAuthorizedEntities(String permission, Collection<T> projects) { + Set<String> projectsUuids = projects.stream().map(EntityDto::getUuid).collect(Collectors.toSet()); + // TODO + Set<String> authorizedProjectsUuids = keepProjectsUuidsByPermission(permission, projectsUuids); + + return projects.stream() + .filter(project -> authorizedProjectsUuids.contains(project.getUuid())) + .toList(); + } + private Set<String> keepProjectsUuidsByPermission(String permission, Collection<String> projectsUuids) { try (DbSession dbSession = dbClient.openSession(false)) { String userUuid = userDto == null ? null : userDto.getUuid(); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java index 192cb000789..66b3e060fe5 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Optional; import javax.annotation.CheckForNull; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; @@ -129,6 +130,12 @@ public class ThreadLocalUserSession implements UserSession { } @Override + public UserSession checkEntityPermission(String projectPermission, EntityDto entity) { + get().checkEntityPermission(projectPermission, entity); + return this; + } + + @Override public UserSession checkProjectPermission(String projectPermission, ProjectDto project) { get().checkProjectPermission(projectPermission, project); return this; @@ -174,6 +181,11 @@ public class ThreadLocalUserSession implements UserSession { } @Override + public boolean hasEntityPermission(String permission, EntityDto entity) { + return get().hasEntityPermission(permission, entity); + } + + @Override public boolean hasProjectPermission(String permission, ProjectDto project) { return get().hasProjectPermission(permission, project); } @@ -209,8 +221,12 @@ public class ThreadLocalUserSession implements UserSession { } @Override + public <T extends EntityDto> List<T> keepAuthorizedEntities(String permission, Collection<T> entities) { + return get().keepAuthorizedEntities(permission, entities); + } + + @Override public List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects) { return get().keepAuthorizedProjects(permission, projects); } - } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java index 7f46dc68dea..a49bf480760 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserSession.java @@ -25,7 +25,9 @@ import java.util.List; import java.util.Optional; import javax.annotation.CheckForNull; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.user.GroupDto; @@ -149,6 +151,8 @@ public interface UserSession { boolean hasProjectPermission(String permission, ProjectDto project); + boolean hasEntityPermission(String permission, EntityDto entity); + boolean hasProjectPermission(String permission, String projectUuid); boolean hasChildProjectsPermission(String permission, ComponentDto component); @@ -176,6 +180,8 @@ public interface UserSession { */ List<ComponentDto> keepAuthorizedComponents(String permission, Collection<ComponentDto> components); + <T extends EntityDto> List<T> keepAuthorizedEntities(String permission, Collection<T> components); + List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects); /** @@ -190,6 +196,8 @@ public interface UserSession { */ UserSession checkProjectPermission(String projectPermission, ProjectDto project); + UserSession checkEntityPermission(String projectPermission, EntityDto entity); + /** * Ensures that {@link #hasChildProjectsPermission(String, ComponentDto)} is {@code true} * otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException}. diff --git a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java index 862eb29455e..9623adc300c 100644 --- a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java +++ b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/tester/UserSessionRule.java @@ -30,6 +30,7 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; @@ -204,7 +205,7 @@ public class UserSessionRule implements TestRule, UserSession { return this; } - public UserSession registerBranches(BranchDto ...branchDtos){ + public UserSession registerBranches(BranchDto... branchDtos) { ensureAbstractMockUserSession().registerBranches(branchDtos); return this; } @@ -263,6 +264,11 @@ public class UserSessionRule implements TestRule, UserSession { } @Override + public boolean hasEntityPermission(String permission, EntityDto entity) { + return currentUserSession.hasProjectPermission(permission, entity.getUuid()); + } + + @Override public boolean hasProjectPermission(String permission, String projectUuid) { return currentUserSession.hasProjectPermission(permission, projectUuid); } @@ -293,6 +299,11 @@ public class UserSessionRule implements TestRule, UserSession { } @Override + public <T extends EntityDto> List<T> keepAuthorizedEntities(String permission, Collection<T> entities) { + return currentUserSession.keepAuthorizedEntities(permission, entities); + } + + @Override public List<ProjectDto> keepAuthorizedProjects(String permission, Collection<ProjectDto> projects) { return currentUserSession.keepAuthorizedProjects(permission, projects); } @@ -370,6 +381,12 @@ public class UserSessionRule implements TestRule, UserSession { } @Override + public UserSession checkEntityPermission(String projectPermission, EntityDto entity) { + currentUserSession.checkEntityPermission(projectPermission, entity); + return this; + } + + @Override public UserSession checkProjectPermission(String projectPermission, ProjectDto project) { currentUserSession.checkProjectPermission(projectPermission, project); return this; diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java index 6ef8214e45b..3a10efa34ff 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java @@ -40,6 +40,7 @@ import org.sonar.db.DbTester; import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.es.TestProjectIndexers; @@ -91,11 +92,8 @@ public class ReportSubmitterIT { private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - private final Configuration config = mock(Configuration.class); - private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService, - new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, true - ); + new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, true); private final BranchSupport ossEditionBranchSupport = new BranchSupport(null); private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport, @@ -146,7 +144,7 @@ public class ReportSubmitterIT { userSession.logIn(user).addProjectPermission(SCAN.getKey(), project); mockSuccessfulPrepareSubmitCall(); - underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8)); + underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); verifyReportIsPersisted(TASK_UUID); verifyNoInteractions(permissionTemplateService); @@ -165,7 +163,7 @@ public class ReportSubmitterIT { when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); verifyReportIsPersisted(TASK_UUID); @@ -185,9 +183,9 @@ public class ReportSubmitterIT { when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); + ProjectDto createdProject = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), PROJECT_KEY).get(); assertThat(db.favorites().hasFavorite(createdProject, user.getUuid())).isTrue(); } @@ -203,14 +201,14 @@ public class ReportSubmitterIT { underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); + ProjectDto createdProject = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), PROJECT_KEY).get(); assertThat(db.favorites().hasNoFavorite(createdProject)).isTrue(); } @Test public void do_no_add_favorite_when_already_100_favorite_projects_and_no_project_creator_permission_on_permission_template() { UserDto user = db.users().insertUser(); - rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), user.getUuid(), user.getLogin())); + rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin())); userSession .logIn(user) .addPermission(GlobalPermission.SCAN) @@ -219,9 +217,9 @@ public class ReportSubmitterIT { when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); - ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get(); + ProjectDto createdProject = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), PROJECT_KEY).get(); assertThat(db.favorites().hasNoFavorite(createdProject)).isTrue(); } @@ -234,7 +232,7 @@ public class ReportSubmitterIT { when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))) .thenReturn(true); - underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); verify(queue).submit(any(CeTaskSubmit.class)); } @@ -245,7 +243,7 @@ public class ReportSubmitterIT { userSession.addPermission(SCAN); mockSuccessfulPrepareSubmitCall(); - underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); verify(queue).submit(any(CeTaskSubmit.class)); } @@ -256,7 +254,7 @@ public class ReportSubmitterIT { userSession.addProjectPermission(SCAN.getKey(), project); mockSuccessfulPrepareSubmitCall(); - underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); + underTest.submit(project.getKey(), project.name(), emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); verify(queue).submit(any(CeTaskSubmit.class)); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java index 953c2164f31..504e25af0e3 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentUpdaterIT.java @@ -33,6 +33,7 @@ import org.sonar.db.DbTester; import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.es.ProjectIndexer; import org.sonar.server.es.TestProjectIndexers; @@ -234,7 +235,7 @@ public class ComponentUpdaterIT { when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))) .thenReturn(true); - ComponentDto dto = underTest.create(db.getSession(), project, userDto.getUuid(), userDto.getLogin()).mainBranchComponent(); + ProjectDto dto = underTest.create(db.getSession(), project, userDto.getUuid(), userDto.getLogin()).projectDto(); assertThat(db.favorites().hasFavorite(dto, userDto.getUuid())).isTrue(); } @@ -242,7 +243,7 @@ public class ComponentUpdaterIT { @Test public void do_not_add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template_and_already_100_favorites() { UserDto user = db.users().insertUser(); - rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), user.getUuid(), user.getLogin())); + rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin())); NewComponent project = NewComponent.newComponentBuilder() .setKey(DEFAULT_PROJECT_KEY) .setName(DEFAULT_PROJECT_NAME) @@ -250,34 +251,34 @@ public class ComponentUpdaterIT { when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(eq(db.getSession()), any(ComponentDto.class))) .thenReturn(true); - ComponentDto dto = underTest.create(db.getSession(), + ProjectDto dto = underTest.create(db.getSession(), project, user.getUuid(), - user.getLogin()).mainBranchComponent(); + user.getLogin()).projectDto(); assertThat(db.favorites().hasFavorite(dto, user.getUuid())).isFalse(); } @Test public void does_not_add_project_to_favorite_when_anonymously_created() { - ComponentDto project = underTest.create(db.getSession(), + ProjectDto project = underTest.create(db.getSession(), NewComponent.newComponentBuilder() .setKey(DEFAULT_PROJECT_KEY) .setName(DEFAULT_PROJECT_NAME) .build(), - null, null).mainBranchComponent(); + null, null).projectDto(); assertThat(db.favorites().hasNoFavorite(project)).isTrue(); } @Test public void does_not_add_project_to_favorite_when_project_has_no_permission_on_template() { - ComponentDto project = underTest.create(db.getSession(), + ProjectDto project = underTest.create(db.getSession(), NewComponent.newComponentBuilder() .setKey(DEFAULT_PROJECT_KEY) .setName(DEFAULT_PROJECT_NAME) .build(), - null, null).mainBranchComponent(); + null, null).projectDto(); assertThat(db.favorites().hasNoFavorite(project)).isTrue(); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/AppActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/AppActionIT.java index 0e90200040a..e112df8b1b8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/AppActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/AppActionIT.java @@ -26,6 +26,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.metric.MetricDto; +import org.sonar.db.project.ProjectDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -219,7 +220,7 @@ public class AppActionIT { @Test public void component_is_favorite() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); userSession.logIn("john").addProjectPermission(USER, project); db.favorites().add(project, userSession.getUuid(), userSession.getLogin()); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java index 939a3fb9b8c..fe99952fbe3 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ws/SuggestionsActionIT.java @@ -34,7 +34,9 @@ import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; +import org.sonar.db.component.ProjectData; import org.sonar.db.component.ResourceTypesRule; +import org.sonar.db.project.ProjectDto; import org.sonar.server.component.index.ComponentIndex; import org.sonar.server.component.index.ComponentIndexer; import org.sonar.server.es.EsTester; @@ -68,8 +70,6 @@ import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE; import static org.sonar.api.resources.Qualifiers.VIEW; import static org.sonar.api.web.UserRole.USER; import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.db.component.ComponentTesting.newPublicProjectDto; import static org.sonar.server.component.ws.SuggestionsAction.PARAM_MORE; import static org.sonar.server.component.ws.SuggestionsAction.PARAM_QUERY; import static org.sonar.server.component.ws.SuggestionsAction.PARAM_RECENTLY_BROWSED; @@ -132,8 +132,8 @@ public class SuggestionsActionIT { @Test public void test_example_json_response() { - ComponentDto project1 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarqube").setName("SonarSource :: SonarQube")).getMainBranchComponent(); - ComponentDto project2 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarlint").setName("SonarSource :: SonarLint")).getMainBranchComponent(); + ProjectDto project1 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarqube").setName("SonarSource :: SonarQube")).getProjectDto(); + ProjectDto project2 = db.components().insertPublicProject(p -> p.setKey("org.sonarsource:sonarlint").setName("SonarSource :: SonarLint")).getProjectDto(); componentIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project1); authorizationIndexerTester.allowOnlyAnyone(project2); @@ -150,7 +150,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_contain_recently_browsed() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); componentIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); @@ -175,7 +175,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_contain_recently_browsed_public_project() { - ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPublicProject().getProjectDto(); componentIndexer.indexAll(); @@ -199,7 +199,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_not_contain_recently_browsed_without_permission() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); componentIndexer.indexAll(); @@ -215,7 +215,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_contain_favorites() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); componentIndexer.indexAll(); @@ -240,7 +240,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_not_contain_favorites_without_permission() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); componentIndexer.indexAll(); @@ -256,7 +256,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_contain_recently_browsed_favorites() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); doReturn(singletonList(project)).when(favoriteFinder).list(); componentIndexer.indexAll(); @@ -282,7 +282,7 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_not_contain_matches_that_are_neither_favorites_nor_recently_browsed() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); componentIndexer.indexAll(); userSessionRule.addProjectPermission(USER, project); @@ -300,10 +300,10 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_order_results() { - ComponentDto project1 = db.components().insertPrivateProject(p -> p.setName("Alpha")).getMainBranchComponent(); - ComponentDto project2 = db.components().insertPrivateProject(p -> p.setName("Bravo")).getMainBranchComponent(); - ComponentDto project3 = db.components().insertPrivateProject(p -> p.setName("Charlie")).getMainBranchComponent(); - ComponentDto project4 = db.components().insertPrivateProject(p -> p.setName("Delta")).getMainBranchComponent(); + ProjectDto project1 = db.components().insertPrivateProject(p -> p.setName("Alpha")).getProjectDto(); + ProjectDto project2 = db.components().insertPrivateProject(p -> p.setName("Bravo")).getProjectDto(); + ProjectDto project3 = db.components().insertPrivateProject(p -> p.setName("Charlie")).getProjectDto(); + ProjectDto project4 = db.components().insertPrivateProject(p -> p.setName("Delta")).getProjectDto(); doReturn(asList(project4, project2)).when(favoriteFinder).list(); componentIndexer.indexAll(); @@ -314,7 +314,7 @@ public class SuggestionsActionIT { SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") - .setParam(PARAM_RECENTLY_BROWSED, Stream.of(project3, project1).map(ComponentDto::getKey).collect(joining(","))) + .setParam(PARAM_RECENTLY_BROWSED, Stream.of(project3, project1).map(ProjectDto::getKey).collect(joining(","))) .executeProtobuf(SuggestionsWsResponse.class); // assert order of keys @@ -330,13 +330,13 @@ public class SuggestionsActionIT { @Test public void suggestions_without_query_should_return_empty_qualifiers() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - componentIndexer.indexOnAnalysis(project.branchUuid()); - userSessionRule.addProjectPermission(USER, project); + ProjectData project = db.components().insertPrivateProject(); + componentIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); + userSessionRule.addProjectPermission(USER, project.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") - .setParam(PARAM_RECENTLY_BROWSED, project.getKey()) + .setParam(PARAM_RECENTLY_BROWSED, project.getProjectDto().getKey()) .executeProtobuf(SuggestionsWsResponse.class); assertThat(response.getResultsList()) @@ -348,13 +348,13 @@ public class SuggestionsActionIT { @Test public void suggestions_should_filter_allowed_qualifiers() { resourceTypes.setAllQualifiers(PROJECT, FILE, UNIT_TEST_FILE); - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - componentIndexer.indexOnAnalysis(project.branchUuid()); - userSessionRule.addProjectPermission(USER, project); + ProjectData project = db.components().insertPrivateProject(); + componentIndexer.indexOnAnalysis(project.getMainBranchDto().getUuid()); + userSessionRule.addProjectPermission(USER, project.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") - .setParam(PARAM_RECENTLY_BROWSED, project.getKey()) + .setParam(PARAM_RECENTLY_BROWSED, project.getProjectDto().getKey()) .executeProtobuf(SuggestionsWsResponse.class); assertThat(response.getResultsList()) @@ -364,7 +364,7 @@ public class SuggestionsActionIT { @Test public void exact_match_in_one_qualifier() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); componentIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); @@ -389,12 +389,12 @@ public class SuggestionsActionIT { @Test public void should_not_return_suggestion_on_non_existing_project() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); componentIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); - db.getDbClient().purgeDao().deleteProject(db.getSession(), project.uuid(), PROJECT, project.name(), project.getKey()); + db.getDbClient().purgeDao().deleteProject(db.getSession(), project.getUuid(), PROJECT, project.getName(), project.getKey()); db.commit(); SuggestionsWsResponse response = ws.newRequest() @@ -410,7 +410,7 @@ public class SuggestionsActionIT { @Test public void must_not_search_if_no_valid_tokens_are_provided() { - ComponentDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getProjectDto(); componentIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); @@ -436,7 +436,7 @@ public class SuggestionsActionIT { @Test public void should_warn_about_short_inputs_but_return_results_based_on_other_terms() { - ComponentDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getProjectDto(); componentIndexer.indexAll(); authorizationIndexerTester.allowOnlyAnyone(project); @@ -455,9 +455,9 @@ public class SuggestionsActionIT { @Test public void should_contain_component_names() { - ComponentDto project1 = db.components().insertPrivateProject(p -> p.setName("Project1")).getMainBranchComponent(); - componentIndexer.indexOnAnalysis(project1.branchUuid()); - authorizationIndexerTester.allowOnlyAnyone(project1); + ProjectData project1 = db.components().insertPrivateProject(p -> p.setName("Project1")); + componentIndexer.indexOnAnalysis(project1.getMainBranchDto().getUuid()); + authorizationIndexerTester.allowOnlyAnyone(project1.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") @@ -467,7 +467,7 @@ public class SuggestionsActionIT { assertThat(response.getResultsList()) .flatExtracting(Category::getItemsList) .extracting(Suggestion::getKey, Suggestion::getName) - .containsExactlyInAnyOrder(tuple(project1.getKey(), project1.name())); + .containsExactlyInAnyOrder(tuple(project1.getProjectDto().getKey(), project1.getProjectDto().getName())); } @Test @@ -492,13 +492,13 @@ public class SuggestionsActionIT { @Test public void should_mark_favorite_items() { - ComponentDto favouriteProject = db.components().insertPrivateProject(p -> p.setName("Project1")).getMainBranchComponent(); - ComponentDto nonFavouriteProject = db.components().insertPublicProject(p -> p.setName("Project2")).getMainBranchComponent(); + ProjectData favouriteProject = db.components().insertPrivateProject(p -> p.setName("Project1")); + ProjectData nonFavouriteProject = db.components().insertPublicProject(p -> p.setName("Project2")); - doReturn(singletonList(favouriteProject)).when(favoriteFinder).list(); - componentIndexer.indexOnAnalysis(favouriteProject.branchUuid()); - componentIndexer.indexOnAnalysis(nonFavouriteProject.branchUuid()); - authorizationIndexerTester.allowOnlyAnyone(favouriteProject, nonFavouriteProject); + doReturn(singletonList(favouriteProject.getProjectDto())).when(favoriteFinder).list(); + componentIndexer.indexOnAnalysis(favouriteProject.getMainBranchDto().getUuid()); + componentIndexer.indexOnAnalysis(nonFavouriteProject.getMainBranchDto().getUuid()); + authorizationIndexerTester.allowOnlyAnyone(favouriteProject.getProjectDto(), nonFavouriteProject.getProjectDto()); SuggestionsWsResponse response = ws.newRequest() .setMethod("POST") @@ -508,7 +508,7 @@ public class SuggestionsActionIT { assertThat(response.getResultsList()) .flatExtracting(Category::getItemsList) .extracting(Suggestion::getKey, Suggestion::getIsFavorite) - .containsExactly(tuple(favouriteProject.getKey(), true), tuple(nonFavouriteProject.getKey(), false)); + .containsExactly(tuple(favouriteProject.getProjectDto().getKey(), true), tuple(nonFavouriteProject.getProjectDto().getKey(), false)); } @Test @@ -553,7 +553,6 @@ public class SuggestionsActionIT { .containsExactlyInAnyOrder( tuple(SuggestionCategory.APP.getName(), false), tuple(SuggestionCategory.VIEW.getName(), false), - tuple(SuggestionCategory.SUBVIEW.getName(), false), tuple(SuggestionCategory.PROJECT.getName(), false)); } @@ -677,8 +676,8 @@ public class SuggestionsActionIT { boolean useQuery) { String namePrefix = "MyProject"; - List<ComponentDto> projects = range(0, numberOfProjects) - .mapToObj(i -> db.components().insertPublicProject(p -> p.setName(namePrefix + i)).getMainBranchComponent()) + List<ProjectDto> projects = range(0, numberOfProjects) + .mapToObj(i -> db.components().insertPublicProject(p -> p.setName(namePrefix + i)).getProjectDto()) .collect(Collectors.toList()); componentIndexer.indexAll(); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java index d7fbca4589f..9feaba8aaf4 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/AddActionIT.java @@ -29,6 +29,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.project.ProjectDto; import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; import org.sonar.db.user.UserDto; @@ -67,7 +68,7 @@ public class AddActionIT { @Test public void add_a_project() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); UserDto user = db.users().insertUser(); userSession.logIn(user).addProjectPermission(USER, project); @@ -82,7 +83,7 @@ public class AddActionIT { PropertyDto favorite = favorites.get(0); assertThat(favorite) .extracting(PropertyDto::getComponentUuid, PropertyDto::getUserUuid, PropertyDto::getKey) - .containsOnly(project.uuid(), user.getUuid(), "favourite"); + .containsOnly(project.getUuid(), user.getUuid(), "favourite"); } @Test @@ -104,25 +105,13 @@ public class AddActionIT { @Test public void fail_when_user_is_not_authenticated() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); assertThatThrownBy(() -> call(project.getKey())) .isInstanceOf(UnauthorizedException.class); } @Test - public void fail_on_directory() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto directory = db.components().insertComponent(newDirectory(project, "dir")); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(USER, project); - - assertThatThrownBy(() -> call(directory.getKey())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Only components with qualifiers TRK, VW, SVW, APP are supported"); - } - - @Test public void fail_on_file() { ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); ComponentDto file = db.components().insertComponent(newFileDto(project)); @@ -130,20 +119,8 @@ public class AddActionIT { userSession.logIn(user).addProjectPermission(USER, project); assertThatThrownBy(() -> call(file.getKey())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Only components with qualifiers TRK, VW, SVW, APP are supported"); - } - - @Test - public void fail_on_unit_test_file() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto unitTestFile = db.components().insertComponent(newFileDto(project).setQualifier(UNIT_TEST_FILE)); - UserDto user = db.users().insertUser(); - userSession.logIn(user).addProjectPermission(USER, project); - - assertThatThrownBy(() -> call(unitTestFile.getKey())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Only components with qualifiers TRK, VW, SVW, APP are supported"); + .isInstanceOf(NotFoundException.class) + .hasMessage("Entity with key '" + file.getKey() + "' not found"); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java index 40f5a3f5513..f2636b299b3 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/RemoveActionIT.java @@ -26,7 +26,7 @@ import org.junit.Test; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.NotFoundException; @@ -37,13 +37,10 @@ import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; -import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.util.Optional.ofNullable; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.sonar.db.component.ComponentTesting.newFileDto; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.server.favorite.ws.FavoritesWsParameters.PARAM_COMPONENT; public class RemoveActionIT { @@ -67,25 +64,22 @@ public class RemoveActionIT { @Test public void remove_a_favorite_project() { - ComponentDto project = insertProjectAndPermissions(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); + ProjectDto project = insertProjectAndPermissions(); db.favorites().add(project, user.getUuid(), user.getLogin()); - db.favorites().add(file, user.getUuid(), user.getLogin()); TestResponse result = call(PROJECT_KEY); assertThat(result.getStatus()).isEqualTo(HTTP_NO_CONTENT); assertThat(db.favorites().hasFavorite(project, user.getUuid())).isFalse(); - assertThat(db.favorites().hasFavorite(file, user.getUuid())).isTrue(); } @Test public void fail_if_not_already_a_favorite() { - ComponentDto componentDto = insertProjectAndPermissions(); + ProjectDto componentDto = insertProjectAndPermissions(); assertThatThrownBy(() -> call(PROJECT_KEY)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Component '" + PROJECT_KEY + "' (uuid: "+componentDto.uuid()+") is not a favorite"); + .hasMessage("Component '" + PROJECT_KEY + "' (uuid: " + componentDto.getUuid() + ") is not a favorite"); } @Test @@ -115,11 +109,11 @@ public class RemoveActionIT { assertThat(param.isRequired()).isTrue(); } - private ComponentDto insertProject() { - return db.components().insertPrivateProject(PROJECT_UUID, c -> c.setKey(PROJECT_KEY)).getMainBranchComponent(); + private ProjectDto insertProject() { + return db.components().insertPrivateProject(PROJECT_UUID, c -> c.setKey(PROJECT_KEY)).getProjectDto(); } - private ComponentDto insertProjectAndPermissions() { + private ProjectDto insertProjectAndPermissions() { userSession.logIn(user); return insertProject(); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/SearchActionIT.java index a510185d1fa..8fdd858415e 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/favorite/ws/SearchActionIT.java @@ -31,6 +31,7 @@ import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteFinder; @@ -76,21 +77,18 @@ public class SearchActionIT { @Test public void return_favorites() { - ComponentDto project = newPrivateProjectDto("P1").setKey("K1").setName("N1"); - addComponent(project); - addComponent(newFileDto(project).setKey("K11").setName("N11")); - addComponent(newPrivateProjectDto("P2").setKey("K2").setName("N2")); + addPermissionAndFavorite(db.components().insertPrivateProject("P1", c -> c.setKey("K1").setName("N1")).getProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject("P2", c -> c.setKey("K2").setName("N2")).getProjectDto()); SearchResponse result = call(); assertThat(result.getPaging()) .extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal) - .containsExactly(1, 100, 3); + .containsExactly(1, 100, 2); assertThat(result.getFavoritesList()) .extracting(Favorite::getKey, Favorite::getName, Favorite::getQualifier) .containsOnly( tuple("K1", "N1", PROJECT), - tuple("K11", "N11", FILE), tuple("K2", "N2", PROJECT)); } @@ -104,8 +102,8 @@ public class SearchActionIT { @Test public void filter_authorized_components() { - addComponent(ComponentTesting.newPrivateProjectDto().setKey("K1")); - ComponentDto unauthorizedProject = db.components().insertComponent(ComponentTesting.newPrivateProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K1")).getProjectDto()); + ProjectDto unauthorizedProject = db.components().insertPrivateProject().getProjectDto(); db.favorites().add(unauthorizedProject, userUuid, userLogin); SearchResponse result = call(); @@ -117,8 +115,8 @@ public class SearchActionIT { @Test public void paginate_results() { IntStream.rangeClosed(1, 9) - .forEach(i -> addComponent(ComponentTesting.newPrivateProjectDto().setKey("K" + i).setName("N" + i))); - ComponentDto unauthorizedProject = db.components().insertComponent(ComponentTesting.newPrivateProjectDto()); + .forEach(i -> addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K" + i).setName("N" + i)).getProjectDto())); + ProjectDto unauthorizedProject = db.components().insertPrivateProject().getProjectDto(); db.favorites().add(unauthorizedProject, userUuid, userLogin); SearchResponse result = call(2, 3); @@ -127,14 +125,12 @@ public class SearchActionIT { assertThat(result.getFavoritesList()) .extracting(Favorite::getKey) .containsExactly("K4", "K5", "K6"); - } @Test public void return_only_users_favorite() { - addComponent(ComponentTesting.newPrivateProjectDto().setKey("K1")); - ComponentDto otherUserFavorite = ComponentTesting.newPrivateProjectDto().setKey("K42"); - db.components().insertComponent(otherUserFavorite); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K1")).getProjectDto()); + ProjectDto otherUserFavorite = db.components().insertPrivateProject(c -> c.setKey("K42")).getProjectDto(); db.favorites().add(otherUserFavorite, "42", userLogin); db.commit(); @@ -145,9 +141,9 @@ public class SearchActionIT { @Test public void favorites_ordered_by_name() { - addComponent(ComponentTesting.newPrivateProjectDto().setName("N2")); - addComponent(ComponentTesting.newPrivateProjectDto().setName("N3")); - addComponent(ComponentTesting.newPrivateProjectDto().setName("N1")); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setName("N2")).getProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setName("N3")).getProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setName("N1")).getProjectDto()); SearchResponse result = call(); @@ -157,9 +153,9 @@ public class SearchActionIT { @Test public void json_example() { - addComponent(ComponentTesting.newPrivateProjectDto().setKey("K1").setName("Samba")); - addComponent(ComponentTesting.newPrivateProjectDto().setKey("K2").setName("Apache HBase")); - addComponent(ComponentTesting.newPrivateProjectDto().setKey("K3").setName("JDK9")); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K1").setName("Samba")).getProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K2").setName("Apache HBase")).getProjectDto()); + addPermissionAndFavorite(db.components().insertPrivateProject(c -> c.setKey("K3").setName("JDK9")).getProjectDto()); String result = ws.newRequest().execute().getInput(); @@ -183,8 +179,7 @@ public class SearchActionIT { .isInstanceOf(UnauthorizedException.class); } - private void addComponent(ComponentDto component) { - db.components().insertComponent(component); + private void addPermissionAndFavorite(ProjectDto component) { db.favorites().add(component, userUuid, userLogin); db.commit(); userSession.addProjectPermission(UserRole.USER, component); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java index f4f24403383..cfc0f3d3d1d 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/CreateActionIT.java @@ -31,6 +31,7 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.es.TestProjectIndexers; @@ -199,7 +200,7 @@ public class CreateActionIT { .setParam("name", DEFAULT_PROJECT_NAME) .executeProtobuf(CreateWsResponse.class); - ComponentDto project = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get(); + ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get(); assertThat(db.favorites().hasFavorite(project, user.getUuid())).isTrue(); } @@ -207,7 +208,7 @@ public class CreateActionIT { public void do_not_add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template_and_already_100_favorites() { UserDto user = db.users().insertUser(); when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true); - rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getMainBranchComponent(), user.getUuid(), user.getLogin())); + rangeClosed(1, 100).forEach(i -> db.favorites().add(db.components().insertPrivateProject().getProjectDto(), user.getUuid(), user.getLogin())); userSession.logIn(user).addPermission(PROVISION_PROJECTS); ws.newRequest() @@ -215,7 +216,7 @@ public class CreateActionIT { .setParam("name", DEFAULT_PROJECT_NAME) .executeProtobuf(CreateWsResponse.class); - ComponentDto project = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get(); + ProjectDto project = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get(); assertThat(db.favorites().hasNoFavorite(project)).isTrue(); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java index 869697b83fa..569dabcee25 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ResetActionIT.java @@ -21,6 +21,7 @@ package org.sonar.server.setting.ws; import java.util.Random; import javax.annotation.Nullable; +import javax.sound.sampled.Port; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -34,6 +35,9 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; +import org.sonar.db.entity.EntityDto; +import org.sonar.db.portfolio.PortfolioDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.property.PropertyDbTester; import org.sonar.db.property.PropertyQuery; import org.sonar.db.user.UserDto; @@ -79,13 +83,13 @@ public class ResetActionIT { private final PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private final SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions); private final SettingValidations settingValidations = new SettingValidations(definitions, dbClient, i18n); - private ComponentDto project; + private ProjectDto project; private final ResetAction underTest = new ResetAction(dbClient, componentFinder, settingsUpdater, userSession, definitions, settingValidations); private final WsActionTester ws = new WsActionTester(underTest); @Before public void setUp() { - project = db.components().insertPrivateProject().getMainBranchComponent(); + project = db.components().insertPrivateProject().getProjectDto(); } @Test @@ -141,7 +145,7 @@ public class ResetActionIT { logInAsSystemAdministrator(); propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("foo").setValue("one")); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("value")); executeRequestOnGlobalSetting("foo"); @@ -154,7 +158,7 @@ public class ResetActionIT { public void ignore_global_setting_when_removing_project_setting() { logInAsProjectAdmin(); propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("foo").setValue("one")); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("value")); executeRequestOnProjectSetting("foo"); @@ -201,26 +205,6 @@ public class ResetActionIT { } @Test - public void remove_setting_on_branch() { - ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); - String branchName = randomAlphanumeric(248); - ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey(branchName)); - definitions.addComponent(PropertyDefinition.builder("foo").onQualifiers(PROJECT).build()); - propertyDb.insertProperties(null, branch.name(), null, null, newComponentPropertyDto(branch).setKey("foo").setValue("value")); - userSession.logIn().addProjectPermission(ADMIN, project); - userSession.addProjectBranchMapping(project.uuid(), branch); - - ws.newRequest() - .setMediaType(MediaTypes.PROTOBUF) - .setParam("keys", "foo") - .setParam("component", branch.getKey()) - .setParam("branch", branchName) - .execute(); - - assertProjectPropertyDoesNotExist(branch, "foo"); - } - - @Test public void empty_204_response() { logInAsSystemAdministrator(); TestResponse result = ws.newRequest() @@ -256,9 +240,7 @@ public class ResetActionIT { userSession.logIn().addProjectPermission(USER, project); definitions.addComponent(PropertyDefinition.builder("foo").build()); - assertThatThrownBy(() -> { - executeRequestOnComponentSetting("foo", project); - }) + assertThatThrownBy(() -> executeRequestOnComponentSetting("foo", project)) .isInstanceOf(ForbiddenException.class) .hasMessage("Insufficient privileges"); } @@ -268,9 +250,7 @@ public class ResetActionIT { logInAsSystemAdministrator(); definitions.addComponent(PropertyDefinition.builder("foo").build()); - assertThatThrownBy(() -> { - executeRequestOnComponentSetting("foo", project); - }) + assertThatThrownBy(() -> executeRequestOnComponentSetting("foo", project)) .isInstanceOf(ForbiddenException.class) .hasMessage("Insufficient privileges"); } @@ -282,9 +262,7 @@ public class ResetActionIT { .onlyOnQualifiers(VIEW) .build()); - assertThatThrownBy(() -> { - executeRequestOnGlobalSetting("foo"); - }) + assertThatThrownBy(() -> executeRequestOnGlobalSetting("foo")) .isInstanceOf(BadRequestException.class) .hasMessage("Setting 'foo' cannot be global"); } @@ -297,9 +275,7 @@ public class ResetActionIT { .build()); i18n.put("qualifier." + PROJECT, "project"); - assertThatThrownBy(() -> { - executeRequestOnComponentSetting("foo", project); - }) + assertThatThrownBy(() -> executeRequestOnComponentSetting("foo", project)) .isInstanceOf(BadRequestException.class) .hasMessage("Setting 'foo' cannot be set on a project"); } @@ -311,115 +287,55 @@ public class ResetActionIT { definitions.addComponent(PropertyDefinition.builder("foo").build()); i18n.put("qualifier." + PROJECT, "project"); - assertThatThrownBy(() -> { - executeRequestOnComponentSetting("foo", project); - }) + assertThatThrownBy(() -> executeRequestOnComponentSetting("foo", project)) .isInstanceOf(BadRequestException.class) .hasMessage("Setting 'foo' cannot be set on a project"); } @Test public void succeed_for_property_without_definition_when_set_on_project_component() { - ComponentDto project = randomPublicOrPrivateProject(); - succeedForPropertyWithoutDefinitionAndValidComponent(project, project); - } - - @Test - public void fail_for_property_without_definition_when_set_on_directory_component() { - ComponentDto project = randomPublicOrPrivateProject(); - ComponentDto directory = db.components().insertComponent(ComponentTesting.newDirectory(project, "A/B")); - failForPropertyWithoutDefinitionOnUnsupportedComponent(project, directory); - } - - @Test - public void fail_for_property_without_definition_when_set_on_file_component() { - ComponentDto project = randomPublicOrPrivateProject(); - ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); - failForPropertyWithoutDefinitionOnUnsupportedComponent(project, file); + ProjectDto project = randomPublicOrPrivateProject(); + succeedForPropertyWithoutDefinitionAndValidComponent(project); } @Test public void succeed_for_property_without_definition_when_set_on_view_component() { - ComponentDto view = db.components().insertPublicPortfolio(); - succeedForPropertyWithoutDefinitionAndValidComponent(view, view); - } - - @Test - public void succeed_for_property_without_definition_when_set_on_subview_component() { - ComponentDto view = db.components().insertPublicPortfolio(); - ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubPortfolio(view)); - succeedForPropertyWithoutDefinitionAndValidComponent(view, subview); - } - - @Test - public void fail_for_property_without_definition_when_set_on_projectCopy_component() { - ComponentDto view = db.components().insertPublicPortfolio(); - ComponentDto projectCopy = db.components().insertComponent(ComponentTesting.newProjectCopy("a", db.components().insertPrivateProject().getMainBranchComponent(), view)); - - failForPropertyWithoutDefinitionOnUnsupportedComponent(view, projectCopy); + PortfolioDto view = db.components().insertPublicPortfolioDto(); + succeedForPropertyWithoutDefinitionAndValidComponent(view); } @Test public void fail_when_component_not_found() { - assertThatThrownBy(() -> { - ws.newRequest() + assertThatThrownBy(() -> ws.newRequest() .setParam("keys", "foo") .setParam("component", "unknown") - .execute(); - }) + .execute()) .isInstanceOf(NotFoundException.class) .hasMessage("Component key 'unknown' not found"); } @Test - public void fail_when_branch_not_found() { - ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); - logInAsProjectAdmin(project); - ComponentDto branch = db.components().insertProjectBranch(project); - String settingKey = "not_allowed_on_branch"; - - assertThatThrownBy(() -> { - ws.newRequest() - .setParam("keys", settingKey) - .setParam("component", branch.getKey()) - .setParam("branch", "unknown") - .execute(); - }) - .isInstanceOf(NotFoundException.class) - .hasMessage(format("Component '%s' on branch 'unknown' not found", branch.getKey())); - } - - @Test public void fail_when_setting_key_is_defined_in_sonar_properties() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); logInAsProjectAdmin(project); String settingKey = ProcessProperties.Property.JDBC_URL.getKey(); - assertThatThrownBy(() -> { - ws.newRequest() + assertThatThrownBy(() -> ws.newRequest() .setParam("keys", settingKey) .setParam("component", project.getKey()) - .execute(); - }) + .execute()) .isInstanceOf(IllegalArgumentException.class) .hasMessage(format("Setting '%s' can only be used in sonar.properties", settingKey)); } - private void succeedForPropertyWithoutDefinitionAndValidComponent(ComponentDto root, ComponentDto module) { - logInAsProjectAdmin(root); - - executeRequestOnComponentSetting("foo", module); + private void succeedForPropertyWithoutDefinitionAndValidComponent(ProjectDto project) { + logInAsProjectAdmin(project); + executeRequestOnComponentSetting("foo", project); } - private void failForPropertyWithoutDefinitionOnUnsupportedComponent(ComponentDto root, ComponentDto component) { - i18n.put("qualifier." + component.qualifier(), "QualifierLabel"); - logInAsProjectAdmin(root); - - assertThatThrownBy(() -> { - executeRequestOnComponentSetting("foo", component); - }) - .isInstanceOf(BadRequestException.class) - .hasMessage("Setting 'foo' cannot be set on a QualifierLabel"); + private void succeedForPropertyWithoutDefinitionAndValidComponent(PortfolioDto project) { + logInAsProjectAdmin(project); + executeRequestOnComponentSetting("foo", project); } private void executeRequestOnGlobalSetting(String key) { @@ -430,8 +346,8 @@ public class ResetActionIT { executeRequest(key, project.getKey()); } - private void executeRequestOnComponentSetting(String key, ComponentDto componentDto) { - executeRequest(key, componentDto.getKey()); + private void executeRequestOnComponentSetting(String key, EntityDto entity) { + executeRequest(key, entity.getKey()); } private void executeRequest(String key, @Nullable String componentKey) { @@ -452,10 +368,14 @@ public class ResetActionIT { userSession.logIn().addProjectPermission(ADMIN, project); } - private void logInAsProjectAdmin(ComponentDto root) { + private void logInAsProjectAdmin(ProjectDto root) { userSession.logIn().addProjectPermission(ADMIN, root); } + private void logInAsProjectAdmin(PortfolioDto root) { + userSession.logIn().addPortfolioPermission(ADMIN, root); + } + private void assertGlobalPropertyDoesNotExist(String key) { assertThat(dbClient.propertiesDao().selectGlobalProperty(dbSession, key)).isNull(); } @@ -464,8 +384,8 @@ public class ResetActionIT { assertThat(dbClient.propertiesDao().selectGlobalProperty(dbSession, key)).isNotNull(); } - private void assertProjectPropertyDoesNotExist(ComponentDto component, String key) { - assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(component.uuid()).setKey(key).build(), dbSession)).isEmpty(); + private void assertProjectPropertyDoesNotExist(EntityDto entity, String key) { + assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(entity.getUuid()).setKey(key).build(), dbSession)).isEmpty(); } private void assertProjectPropertyDoesNotExist(String key) { @@ -473,7 +393,7 @@ public class ResetActionIT { } private void assertProjectPropertyExists(String key) { - assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.uuid()).setKey(key).build(), dbSession)).isNotEmpty(); + assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.getUuid()).setKey(key).build(), dbSession)).isNotEmpty(); } private void assertUserPropertyExists(String key, UserDto user) { @@ -484,8 +404,8 @@ public class ResetActionIT { dbSession)).isNotEmpty(); } - private ComponentDto randomPublicOrPrivateProject() { - return new Random().nextBoolean() ? db.components().insertPrivateProject().getMainBranchComponent() : db.components().insertPublicProject().getMainBranchComponent(); + private ProjectDto randomPublicOrPrivateProject() { + return new Random().nextBoolean() ? db.components().insertPrivateProject().getProjectDto() : db.components().insertPublicProject().getProjectDto(); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java index 0079db0022b..efbebc379e8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SetActionIT.java @@ -836,7 +836,7 @@ public class SetActionIT { @Test public void succeed_for_property_without_definition_when_set_on_project_component() { ComponentDto project = randomPublicOrPrivateProject(); - succeedForPropertyWithoutDefinitionAndValidComponent(project, project); + succeedForPropertyWithoutDefinitionAndValidComponent(project); } @Test @@ -856,14 +856,14 @@ public class SetActionIT { @Test public void succeed_for_property_without_definition_when_set_on_view_component() { ComponentDto view = db.components().insertPrivatePortfolio(); - succeedForPropertyWithoutDefinitionAndValidComponent(view, view); + succeedForPropertyWithoutDefinitionAndValidComponent(view); } @Test public void succeed_for_property_without_definition_when_set_on_subview_component() { ComponentDto view = db.components().insertPrivatePortfolio(); ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubPortfolio(view)); - succeedForPropertyWithoutDefinitionAndValidComponent(view, subview); + failForPropertyWithoutDefinitionOnUnsupportedComponent(view, subview); } @Test @@ -874,12 +874,12 @@ public class SetActionIT { failForPropertyWithoutDefinitionOnUnsupportedComponent(view, projectCopy); } - private void succeedForPropertyWithoutDefinitionAndValidComponent(ComponentDto project, ComponentDto module) { + private void succeedForPropertyWithoutDefinitionAndValidComponent(ComponentDto project) { logInAsProjectAdministrator(project); - callForProjectSettingByKey("my.key", "My Value", module.getKey()); + callForProjectSettingByKey("my.key", "My Value", project.getKey()); - assertComponentSetting("my.key", "My Value", module.uuid()); + assertComponentSetting("my.key", "My Value", project.uuid()); } private void failForPropertyWithoutDefinitionOnUnsupportedComponent(ComponentDto root, ComponentDto component) { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SettingsUpdaterIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SettingsUpdaterIT.java index 7784a3aa7b9..c522fc52b11 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SettingsUpdaterIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/SettingsUpdaterIT.java @@ -33,6 +33,7 @@ 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.project.ProjectDto; import org.sonar.db.property.PropertyDbTester; import org.sonar.db.property.PropertyQuery; import org.sonar.db.user.UserDto; @@ -58,19 +59,19 @@ public class SettingsUpdaterIT { ComponentDbTester componentDb = new ComponentDbTester(db); PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); - ComponentDto project; + ProjectDto project; SettingsUpdater underTest = new SettingsUpdater(dbClient, definitions); @Before public void setUp() { - project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto()); + project = componentDb.insertPrivateProject().getProjectDto(); } @Test public void delete_global_settings() { definitions.addComponent(PropertyDefinition.builder("foo").build()); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("value")); propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("foo").setValue("one")); propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("bar").setValue("two")); @@ -86,9 +87,9 @@ public class SettingsUpdaterIT { public void delete_component_settings() { definitions.addComponent(PropertyDefinition.builder("foo").build()); propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("foo").setValue("value")); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("one")); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("bar").setValue("two")); underTest.deleteComponentSettings(dbSession, project, "foo", "bar"); @@ -150,7 +151,7 @@ public class SettingsUpdaterIT { PropertyFieldDefinition.build("key").name("Key").build(), PropertyFieldDefinition.build("size").name("Size").build())) .build()); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("1,2"), newComponentPropertyDto(project).setKey("foo.1.key").setValue("key1"), newComponentPropertyDto(project).setKey("foo.1.size").setValue("size1"), @@ -173,7 +174,7 @@ public class SettingsUpdaterIT { PropertyFieldDefinition.build("key").name("Key").build(), PropertyFieldDefinition.build("size").name("Size").build())) .build()); - propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(), + propertyDb.insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("other").setValue("1,2"), newComponentPropertyDto(project).setKey("other.1.key").setValue("key1")); @@ -209,11 +210,11 @@ public class SettingsUpdaterIT { } private void assertProjectPropertyDoesNotExist(String key) { - assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.uuid()).setKey(key).build(), dbSession)).isEmpty(); + assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.getUuid()).setKey(key).build(), dbSession)).isEmpty(); } private void assertProjectPropertyExists(String key) { - assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.uuid()).setKey(key).build(), dbSession)).isNotEmpty(); + assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentUuid(project.getUuid()).setKey(key).build(), dbSession)).isNotEmpty(); } private void assertUserPropertyExists(String key, UserDto user) { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java index 1673b634a40..cea85076cc1 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java @@ -38,7 +38,10 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ProjectData; +import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.project.ProjectDto; import org.sonar.process.ProcessProperties; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.ForbiddenException; @@ -80,11 +83,14 @@ public class ValuesActionIT { private final PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE); private final SettingsWsSupport support = new SettingsWsSupport(userSession); private final WsActionTester wsActionTester = new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support)); - private ComponentDto project; + private ProjectDto project; + private ComponentDto rootComponent; @Before public void setUp() { - project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectData projectData = db.components().insertPrivateProject(); + project = projectData.getProjectDto(); + rootComponent = projectData.getMainBranchComponent(); } @Test @@ -240,7 +246,7 @@ public class ValuesActionIT { PropertyDefinition.builder("property").defaultValue("default").onQualifiers(PROJECT).build()); db.properties().insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("property").setValue("one")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), // The property is overriding global value newComponentPropertyDto(project).setKey("property").setValue("two")); @@ -259,7 +265,7 @@ public class ValuesActionIT { PropertyDefinition.builder("project").onQualifiers(PROJECT).build())); db.properties().insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("global").setValue("one")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("project").setValue("two")); ValuesWsResponse result = executeRequestForProjectProperties(); @@ -299,7 +305,7 @@ public class ValuesActionIT { @Test public void return_values_of_component_even_if_no_property_definition() { logInAsProjectUser(); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("property").setValue("foo")); ValuesWsResponse response = executeRequestForComponentProperties(project, "property"); @@ -335,31 +341,6 @@ public class ValuesActionIT { } @Test - public void return_inherited_values_on_component() { - logInAsProjectUser(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - definitions.addComponents(asList( - PropertyDefinition.builder("defaultProperty").defaultValue("default").onQualifiers(PROJECT).build(), - PropertyDefinition.builder("globalProperty").onQualifiers(PROJECT).build(), - PropertyDefinition.builder("projectProperty").onQualifiers(PROJECT).build(), - PropertyDefinition.builder("componentProperty").onQualifiers(PROJECT).build())); - db.properties().insertProperties(null, null, null, null, - newGlobalPropertyDto().setKey("globalProperty").setValue("global")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), - newComponentPropertyDto(project).setKey("projectProperty").setValue("project")); - db.properties().insertProperties(null, file.getKey(), file.name(), file.qualifier(), - newComponentPropertyDto(file).setKey("componentProperty").setValue("component")); - - ValuesWsResponse result = executeRequestForComponentProperties(file, "defaultProperty", "globalProperty", "projectProperty", "componentProperty"); - - assertThat(result.getSettingsList()).hasSize(4); - assertSetting(result.getSettings(0), "defaultProperty", "default", true); - assertSetting(result.getSettings(1), "globalProperty", "global", true); - assertSetting(result.getSettings(2), "projectProperty", "project", true); - assertSetting(result.getSettings(3), "componentProperty", "component", false); - } - - @Test public void return_inherited_values_on_global_setting() { logIn(); definitions.addComponents(asList( @@ -376,83 +357,6 @@ public class ValuesActionIT { } @Test - public void return_parent_value() { - logInAsProjectUser(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - definitions.addComponents(asList( - PropertyDefinition.builder("foo").defaultValue("default").onQualifiers(PROJECT).build())); - db.properties().insertProperties(null, null, null, null, - newGlobalPropertyDto().setKey("foo").setValue("global")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), - newComponentPropertyDto(project).setKey("foo").setValue("project")); - db.properties().insertProperties(null, file.getKey(), file.name(), file.qualifier(), - newComponentPropertyDto(file).setKey("foo").setValue("file")); - - assertParentValue(executeRequestForComponentProperties(file, "foo").getSettings(0), "project"); - assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global"); - assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), "default"); - } - - @Test - public void return_parent_field_values() { - logInAsProjectUser(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - definitions.addComponent(PropertyDefinition - .builder("foo") - .onQualifiers(PROJECT) - .type(PropertyType.PROPERTY_SET) - .fields(asList( - PropertyFieldDefinition.build("key").name("Key").build(), - PropertyFieldDefinition.build("size").name("Size").build())) - .build()); - db.properties().insertPropertySet("foo", null, ImmutableMap.of("key", "keyG1", "size", "sizeG1")); - db.properties().insertPropertySet("foo", project, ImmutableMap.of("key", "keyP1", "size", "sizeP1")); - db.properties().insertPropertySet("foo", file, ImmutableMap.of("key", "keyM1", "size", "sizeM1")); - - assertParentFieldValues(executeRequestForComponentProperties(file, "foo").getSettings(0), ImmutableMap.of("key", "keyP1", "size", "sizeP1")); - assertParentFieldValues(executeRequestForComponentProperties(project, "foo").getSettings(0), ImmutableMap.of("key", "keyG1", "size", "sizeG1")); - assertParentFieldValues(executeRequestForGlobalProperties("foo").getSettings(0)); - } - - @Test - public void return_no_parent_value() { - logInAsProjectUser(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - definitions.addComponents(asList( - PropertyDefinition.builder("simple").onQualifiers(PROJECT).build(), - PropertyDefinition.builder("multi").multiValues(true).onQualifiers(PROJECT).build(), - PropertyDefinition.builder("set") - .type(PropertyType.PROPERTY_SET) - .onQualifiers(PROJECT) - .fields(asList( - PropertyFieldDefinition.build("key").name("Key").build(), - PropertyFieldDefinition.build("size").name("Size").build())) - .build())); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), - newComponentPropertyDto(project).setKey("simple").setValue("module"), - newComponentPropertyDto(project).setKey("multi").setValue("module1,module2")); - db.properties().insertPropertySet("set", project, ImmutableMap.of("key", "keyM1", "size", "sizeM1")); - - assertParentValue(executeRequestForComponentProperties(file, "simple").getSettings(0), null); - assertParentValues(executeRequestForComponentProperties(file, "multi").getSettings(0)); - assertParentFieldValues(executeRequestForComponentProperties(file, "set").getSettings(0)); - } - - @Test - public void return_parent_value_when_no_definition() { - logInAsProjectUser(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - db.properties().insertProperties(null, null, null, null, - newGlobalPropertyDto().setKey("foo").setValue("global")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), - newComponentPropertyDto(project).setKey("foo").setValue("project")); - - assertParentValue(executeRequestForComponentProperties(file, "foo").getSettings(0), "project"); - assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global"); - assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), null); - } - - @Test public void return_value_of_deprecated_key() { logIn(); definitions.addComponent(PropertyDefinition @@ -527,7 +431,7 @@ public class ValuesActionIT { PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build())); db.properties().insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("global.secret.secured").setValue("very secret")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("one"), newComponentPropertyDto(project).setKey("secret.secured").setValue("password")); @@ -542,7 +446,7 @@ public class ValuesActionIT { userSession .addProjectPermission(USER, project) .addProjectPermission(SCAN.getKey(), project); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("not-defined.secured").setValue("123")); ValuesWsResponse result = executeRequestForProjectProperties("not-defined.secured"); @@ -575,7 +479,7 @@ public class ValuesActionIT { PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build())); db.properties().insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("global.secret.secured").setValue("very secret")); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("one"), newComponentPropertyDto(project).setKey("secret.secured").setValue("password")); @@ -590,7 +494,7 @@ public class ValuesActionIT { @Test public void return_secured_settings_even_if_not_defined_when_project_admin() { logInAsProjectAdmin(); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("not-defined.secured").setValue("123")); ValuesWsResponse result = executeRequestForProjectProperties("not-defined.secured"); @@ -676,7 +580,7 @@ public class ValuesActionIT { definitions.addComponents(asList( PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(), PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build())); - db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), + db.properties().insertProperties(null, project.getKey(), project.getName(), project.getQualifier(), newComponentPropertyDto(project).setKey("foo").setValue("one"), newComponentPropertyDto(project).setKey("secret.secured").setValue("password")); @@ -847,8 +751,8 @@ public class ValuesActionIT { assertThat(response.getSetSecuredSettingsList()).contains("my.password.secured"); } - private ValuesWsResponse executeRequestForComponentProperties(ComponentDto componentDto, String... keys) { - return executeRequest(componentDto.getKey(), keys); + private ValuesWsResponse executeRequestForComponentProperties(EntityDto entity, String... keys) { + return executeRequest(entity.getKey(), keys); } private ValuesWsResponse executeRequestForProjectProperties(String... keys) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java index ee21751c4cb..b22aebde003 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java @@ -36,6 +36,7 @@ import org.sonar.db.DbSession; import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.portfolio.PortfolioDto.SelectionMode; import org.sonar.db.project.ProjectDto; @@ -236,14 +237,25 @@ public class ComponentUpdater { return branch; } + // TODO this is wrong, should probably be done for the project and not for the component. Component has the uuid of the branch! private void handlePermissionTemplate(DbSession dbSession, ComponentDto componentDto, @Nullable String userUuid, @Nullable String userLogin) { permissionTemplateService.applyDefaultToNewComponent(dbSession, componentDto, userUuid); if (componentDto.qualifier().equals(PROJECT) && permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, componentDto)) { - favoriteUpdater.add(dbSession, componentDto, userUuid, userLogin, false); + favoriteUpdater.add(dbSession, toProject(componentDto), userUuid, userLogin, false); } } + private static ProjectDto toProject(ComponentDto componentDto) { + return new ProjectDto() + .setUuid(componentDto.uuid()) + .setKey(componentDto.getKey()) + .setQualifier(componentDto.qualifier()) + .setPrivate(componentDto.isPrivate()) + .setName(componentDto.name()) + .setDescription(componentDto.description()); + } + private String getQualifierToDisplay(String qualifier) { return i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project"); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java index 279fddd7f54..82588c6167f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java @@ -26,14 +26,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.ResourceType; @@ -47,6 +46,7 @@ import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.server.component.index.ComponentHit; import org.sonar.server.component.index.ComponentHitsPerQualifier; import org.sonar.server.component.index.ComponentIndex; @@ -170,41 +170,41 @@ public class SuggestionsAction implements ComponentsWsAction { * we are generating suggestions, by using (1) favorites and (2) recently browsed components (without searchin in Elasticsearch) */ private SuggestionsWsResponse loadSuggestionsWithoutSearch(int skip, int limit, Set<String> recentlyBrowsedKeys, List<String> qualifiers) { - List<ComponentDto> favoriteDtos = favoriteFinder.list(); - if (favoriteDtos.isEmpty() && recentlyBrowsedKeys.isEmpty()) { + List<EntityDto> favorites = favoriteFinder.list(); + if (favorites.isEmpty() && recentlyBrowsedKeys.isEmpty()) { return newBuilder().build(); } try (DbSession dbSession = dbClient.openSession(false)) { - Set<ComponentDto> componentDtos = new HashSet<>(favoriteDtos); + Set<EntityDto> entities = new HashSet<>(favorites); if (!recentlyBrowsedKeys.isEmpty()) { - componentDtos.addAll(dbClient.componentDao().selectByKeys(dbSession, recentlyBrowsedKeys)); + entities.addAll(dbClient.projectDao().selectEntitiesByKeys(dbSession, recentlyBrowsedKeys)); } - List<ComponentDto> authorizedComponents = userSession.keepAuthorizedComponents(USER, componentDtos); - ListMultimap<String, ComponentDto> componentsPerQualifier = authorizedComponents.stream() - .collect(MoreCollectors.index(ComponentDto::qualifier)); - if (componentsPerQualifier.isEmpty()) { + List<EntityDto> authorizedEntities = userSession.keepAuthorizedEntities(USER, entities); + ListMultimap<String, EntityDto> entityPerQualifier = authorizedEntities.stream() + .collect(MoreCollectors.index(EntityDto::getQualifier)); + if (entityPerQualifier.isEmpty()) { return newBuilder().build(); } - Set<String> favoriteUuids = favoriteDtos.stream().map(ComponentDto::uuid).collect(MoreCollectors.toSet(favoriteDtos.size())); - Comparator<ComponentDto> favoriteComparator = Comparator.comparing(c -> favoriteUuids.contains(c.uuid()) ? -1 : +1); - Comparator<ComponentDto> comparator = favoriteComparator.thenComparing(ComponentDto::name); + Set<String> favoriteUuids = favorites.stream().map(EntityDto::getUuid).collect(MoreCollectors.toSet(favorites.size())); + Comparator<EntityDto> favoriteComparator = Comparator.comparing(c -> favoriteUuids.contains(c.getUuid()) ? -1 : +1); + Comparator<EntityDto> comparator = favoriteComparator.thenComparing(EntityDto::getName); ComponentIndexResults componentsPerQualifiers = ComponentIndexResults.newBuilder().setQualifiers( qualifiers.stream().map(q -> { - List<ComponentDto> componentsOfThisQualifier = componentsPerQualifier.get(q); + List<EntityDto> componentsOfThisQualifier = entityPerQualifier.get(q); List<ComponentHit> hits = componentsOfThisQualifier .stream() .sorted(comparator) .skip(skip) .limit(limit) - .map(ComponentDto::uuid) + .map(EntityDto::getUuid) .map(ComponentHit::new) .collect(MoreCollectors.toList(limit)); int totalHits = componentsOfThisQualifier.size(); return new ComponentHitsPerQualifier(q, hits, totalHits); })).build(); - return buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, authorizedComponents, skip + limit).build(); + return buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, authorizedEntities, skip + limit).build(); } } @@ -215,8 +215,8 @@ public class SuggestionsAction implements ComponentsWsAction { return queryBuilder.build(); } - List<ComponentDto> favorites = favoriteFinder.list(); - Set<String> favoriteKeys = favorites.stream().map(ComponentDto::getKey).collect(MoreCollectors.toSet(favorites.size())); + List<EntityDto> favorites = favoriteFinder.list(); + Set<String> favoriteKeys = favorites.stream().map(EntityDto::getKey).collect(MoreCollectors.toSet(favorites.size())); SuggestionQuery.Builder queryBuilder = SuggestionQuery.builder() .setQuery(query) .setRecentlyBrowsedKeys(recentlyBrowsedKeys) @@ -229,14 +229,14 @@ public class SuggestionsAction implements ComponentsWsAction { return newBuilder().build(); } try (DbSession dbSession = dbClient.openSession(false)) { - Set<String> componentUuids = componentsPerQualifiers.getQualifiers() + Set<String> entityUuids = componentsPerQualifiers.getQualifiers() .map(ComponentHitsPerQualifier::getHits) .flatMap(Collection::stream) .map(ComponentHit::getUuid) .collect(toSet()); - List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, componentUuids); - Set<String> favoriteUuids = favorites.stream().map(ComponentDto::uuid).collect(MoreCollectors.toSet(favorites.size())); - SuggestionsWsResponse.Builder searchWsResponse = buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, dbSession, componentDtos, skip + limit); + List<EntityDto> entities = dbClient.projectDao().selectEntitiesByUuids(dbSession, entityUuids); + Set<String> favoriteUuids = favorites.stream().map(EntityDto::getUuid).collect(MoreCollectors.toSet(favorites.size())); + SuggestionsWsResponse.Builder searchWsResponse = buildResponse(recentlyBrowsedKeys, favoriteUuids, componentsPerQualifiers, entities, skip + limit); getWarning(query).ifPresent(searchWsResponse::setWarning); return searchWsResponse.build(); } @@ -269,21 +269,11 @@ public class SuggestionsAction implements ComponentsWsAction { } private SuggestionsWsResponse.Builder buildResponse(Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, ComponentIndexResults componentsPerQualifiers, - DbSession dbSession, List<ComponentDto> componentDtos, int coveredItems) { + List<EntityDto> entities, int coveredItems) { - Map<String, ComponentDto> componentsByUuids = componentDtos.stream() - .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid)); - Map<String, ComponentDto> projectsByUuids = loadProjects(dbSession, componentsByUuids.values()); - return toResponse(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, componentsByUuids, projectsByUuids, coveredItems); - } - - private Map<String, ComponentDto> loadProjects(DbSession dbSession, Collection<ComponentDto> components) { - Set<String> projectUuids = components.stream() - .filter(c -> QUALIFIERS_FOR_WHICH_TO_RETURN_PROJECT.contains(c.qualifier())) - .map(ComponentDto::branchUuid) - .collect(MoreCollectors.toSet()); - return dbClient.componentDao().selectByUuids(dbSession, projectUuids).stream() - .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid)); + Map<String, EntityDto> entitiesByUuids = entities.stream() + .collect(MoreCollectors.uniqueIndex(EntityDto::getUuid)); + return toResponse(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, entitiesByUuids, coveredItems); } private ComponentIndexResults searchInIndex(SuggestionQuery suggestionQuery) { @@ -291,22 +281,22 @@ public class SuggestionsAction implements ComponentsWsAction { } private static SuggestionsWsResponse.Builder toResponse(ComponentIndexResults componentsPerQualifiers, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, - Map<String, ComponentDto> componentsByUuids, Map<String, ComponentDto> projectsByUuids, int coveredItems) { + Map<String, EntityDto> entitiesByUuids, int coveredItems) { if (componentsPerQualifiers.isEmpty()) { return newBuilder(); } return newBuilder() - .addAllResults(toCategories(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, componentsByUuids, projectsByUuids, coveredItems)) - .addAllProjects(toProjects(projectsByUuids)); + .addAllResults(toCategories(componentsPerQualifiers, recentlyBrowsedKeys, favoriteUuids, entitiesByUuids, coveredItems)); } private static List<Category> toCategories(ComponentIndexResults componentsPerQualifiers, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, - Map<String, ComponentDto> componentsByUuids, Map<String, ComponentDto> projectsByUuids, int coveredItems) { + Map<String, EntityDto> entitiesByUuids, int coveredItems) { return componentsPerQualifiers.getQualifiers().map(qualifier -> { List<Suggestion> suggestions = qualifier.getHits().stream() - .map(hit -> toSuggestion(hit, recentlyBrowsedKeys, favoriteUuids, componentsByUuids, projectsByUuids)) - .filter(Objects::nonNull) + .map(hit -> toSuggestion(hit, recentlyBrowsedKeys, favoriteUuids, entitiesByUuids)) + .filter(Optional::isPresent) + .map(Optional::get) .collect(toList()); return Category.newBuilder() @@ -321,33 +311,14 @@ public class SuggestionsAction implements ComponentsWsAction { * @return null when the component exists in Elasticsearch but not in database. That * occurs when failed indexing requests are been recovering. */ - @CheckForNull - private static Suggestion toSuggestion(ComponentHit hit, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, Map<String, ComponentDto> componentsByUuids, - Map<String, ComponentDto> projectsByUuids) { - ComponentDto result = componentsByUuids.get(hit.getUuid()); - if (result == null - // SONAR-11419 this has happened in production while code does not really allow it. An inconsistency in DB may be the cause. - || (QUALIFIERS_FOR_WHICH_TO_RETURN_PROJECT.contains(result.qualifier()) && projectsByUuids.get(result.branchUuid()) == null)) { - return null; - } - Suggestion.Builder builder = Suggestion.newBuilder() - .setKey(result.getKey()) - .setName(result.name()) - .setMatch(hit.getHighlightedText().orElse(HtmlEscapers.htmlEscaper().escape(result.name()))) - .setIsRecentlyBrowsed(recentlyBrowsedKeys.contains(result.getKey())) - .setIsFavorite(favoriteUuids.contains(result.uuid())); - if (QUALIFIERS_FOR_WHICH_TO_RETURN_PROJECT.contains(result.qualifier())) { - builder.setProject(projectsByUuids.get(result.branchUuid()).getKey()); - } - return builder.build(); - } - - private static List<Project> toProjects(Map<String, ComponentDto> projectsByUuids) { - return projectsByUuids.values().stream() - .map(p -> Project.newBuilder() - .setKey(p.getKey()) - .setName(p.longName()) - .build()) - .toList(); + private static Optional<Suggestion> toSuggestion(ComponentHit hit, Set<String> recentlyBrowsedKeys, Set<String> favoriteUuids, Map<String, EntityDto> entitiesByUuids) { + return Optional.ofNullable(entitiesByUuids.get(hit.getUuid())) + .map(result -> Suggestion.newBuilder() + .setKey(result.getKey()) + .setName(result.getName()) + .setMatch(hit.getHighlightedText().orElse(HtmlEscapers.htmlEscaper().escape(result.getName()))) + .setIsRecentlyBrowsed(recentlyBrowsedKeys.contains(result.getKey())) + .setIsFavorite(favoriteUuids.contains(result.getUuid())) + .build()); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java index 07a57babfa3..b31f0153500 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/FavoriteFinder.java @@ -25,13 +25,12 @@ import java.util.Set; import java.util.stream.Collectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.property.PropertyDto; import org.sonar.db.property.PropertyQuery; import org.sonar.server.user.UserSession; import static java.util.Collections.emptyList; -import static org.sonar.core.util.stream.MoreCollectors.toList; import static org.sonar.server.favorite.FavoriteUpdater.PROP_FAVORITE_KEY; public class FavoriteFinder { @@ -46,7 +45,7 @@ public class FavoriteFinder { /** * @return the list of favorite components of the authenticated user. Empty list if the user is not authenticated */ - public List<ComponentDto> list() { + public List<EntityDto> list() { if (!userSession.isLoggedIn()) { return emptyList(); } @@ -58,9 +57,11 @@ public class FavoriteFinder { .build(); Set<String> componentUuids = dbClient.propertiesDao().selectByQuery(dbQuery, dbSession).stream().map(PropertyDto::getComponentUuid).collect(Collectors.toSet()); - return dbClient.componentDao().selectByUuids(dbSession, componentUuids).stream() - .sorted(Comparator.comparing(ComponentDto::name)) - .collect(toList()); + List<EntityDto> entities = dbClient.projectDao().selectEntitiesByUuids(dbSession, componentUuids); + + return entities.stream() + .sorted(Comparator.comparing(EntityDto::getName)) + .collect(Collectors.toList()); } } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java index 32f37d48369..a233f317cab 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/AddAction.java @@ -28,7 +28,9 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.favorite.FavoriteUpdater; import org.sonar.server.user.UserSession; import org.sonar.server.ws.KeyExamples; @@ -92,14 +94,16 @@ public class AddAction implements FavoritesWsAction { private Consumer<Request> addFavorite() { return request -> { try (DbSession dbSession = dbClient.openSession(false)) { - ComponentDto componentDto = componentFinder.getByKey(dbSession, request.mandatoryParam(PARAM_COMPONENT)); - checkArgument(SUPPORTED_QUALIFIERS.contains(componentDto.qualifier()), "Only components with qualifiers %s are supported", SUPPORTED_QUALIFIERS_AS_STRING); + EntityDto entity = dbClient.projectDao().selectEntityByKey(dbSession, request.mandatoryParam(PARAM_COMPONENT)) + .orElseThrow(() -> new NotFoundException(format("Entity with key '%s' not found", request.mandatoryParam(PARAM_COMPONENT)))); + + checkArgument(SUPPORTED_QUALIFIERS.contains(entity.getQualifier()), "Only components with qualifiers %s are supported", SUPPORTED_QUALIFIERS_AS_STRING); userSession .checkLoggedIn() - .checkComponentPermission(USER, componentDto); + .checkEntityPermission(USER, entity); String userUuid = userSession.isLoggedIn() ? userSession.getUuid() : null; String userLogin = userSession.isLoggedIn() ? userSession.getLogin() : null; - favoriteUpdater.add(dbSession, componentDto, userUuid, userLogin, true); + favoriteUpdater.add(dbSession, entity, userUuid, userLogin, true); dbSession.commit(); } }; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/SearchAction.java index 43739322f87..11111b13988 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/favorite/ws/SearchAction.java @@ -28,6 +28,7 @@ import org.sonar.api.utils.Paging; import org.sonar.api.web.UserRole; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.server.favorite.FavoriteFinder; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Common; @@ -78,25 +79,25 @@ public class SearchAction implements FavoritesWsAction { private SearchResults toSearchResults(SearchRequest request) { userSession.checkLoggedIn(); - List<ComponentDto> authorizedFavorites = getAuthorizedFavorites(); + List<EntityDto> authorizedFavorites = getAuthorizedFavorites(); Paging paging = Paging.forPageIndex(Integer.parseInt(request.getP())).withPageSize(Integer.parseInt(request.getPs())).andTotal(authorizedFavorites.size()); - List<ComponentDto> displayedFavorites = authorizedFavorites.stream() + List<EntityDto> displayedFavorites = authorizedFavorites.stream() .skip(paging.offset()) .limit(paging.pageSize()) .collect(MoreCollectors.toList()); return new SearchResults(paging, displayedFavorites); } - private List<ComponentDto> getAuthorizedFavorites() { - List<ComponentDto> componentDtos = favoriteFinder.list(); - return userSession.keepAuthorizedComponents(UserRole.USER, componentDtos); + private List<EntityDto> getAuthorizedFavorites() { + List<EntityDto> entities = favoriteFinder.list(); + return userSession.keepAuthorizedEntities(UserRole.USER, entities); } private static class SearchResults { - private final List<ComponentDto> favorites; + private final List<EntityDto> favorites; private final Paging paging; - private SearchResults(Paging paging, List<ComponentDto> favorites) { + private SearchResults(Paging paging, List<EntityDto> favorites) { this.paging = paging; this.favorites = favorites; } @@ -124,12 +125,12 @@ public class SearchAction implements FavoritesWsAction { .forEach(builder::addFavorites); } - private static Favorite toWsFavorite(Favorite.Builder builder, ComponentDto componentDto) { + private static Favorite toWsFavorite(Favorite.Builder builder, EntityDto componentDto) { builder .clear() .setKey(componentDto.getKey()); - ofNullable(componentDto.name()).ifPresent(builder::setName); - ofNullable(componentDto.qualifier()).ifPresent(builder::setQualifier); + ofNullable(componentDto.getName()).ifPresent(builder::setName); + ofNullable(componentDto.getQualifier()).ifPresent(builder::setQualifier); return builder.build(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java index c3c21e18d65..4c2383cbc38 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ResetAction.java @@ -35,10 +35,13 @@ import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.setting.ws.SettingValidations.SettingData; import org.sonar.server.user.UserSession; +import static java.lang.String.format; import static java.util.Collections.emptyList; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_BRANCH; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_COMPONENT; @@ -107,7 +110,7 @@ public class ResetAction implements SettingsWsAction { public void handle(Request request, Response response) throws Exception { try (DbSession dbSession = dbClient.openSession(false)) { ResetRequest resetRequest = toWsRequest(request); - Optional<ComponentDto> component = getComponent(dbSession, resetRequest); + Optional<EntityDto> component = getComponent(dbSession, resetRequest); checkPermissions(component); resetRequest.getKeys().forEach(key -> { SettingsWsSupport.validateKey(key); @@ -144,17 +147,20 @@ public class ResetAction implements SettingsWsAction { .setPullRequest(request.param(PARAM_PULL_REQUEST)); } - private Optional<ComponentDto> getComponent(DbSession dbSession, ResetRequest request) { + private Optional<EntityDto> getComponent(DbSession dbSession, ResetRequest request) { String componentKey = request.getComponent(); if (componentKey == null) { return Optional.empty(); } - return Optional.of(componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, request.getBranch(), request.getPullRequest())); + + // TODO this WS should support branches and PRs? + return Optional.of(dbClient.projectDao().selectEntityByKey(dbSession, componentKey) + .orElseThrow(() -> new NotFoundException(format("Component key '%s' not found", componentKey)))); } - private void checkPermissions(Optional<ComponentDto> component) { + private void checkPermissions(Optional<EntityDto> component) { if (component.isPresent()) { - userSession.checkComponentPermission(UserRole.ADMIN, component.get()); + userSession.checkEntityPermission(UserRole.ADMIN, component.get()); } else { userSession.checkIsSystemAdministrator(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java index 92884434b95..d731fe61dfb 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SetAction.java @@ -48,6 +48,7 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.property.PropertyDto; import org.sonar.scanner.protocol.GsonHelper; import org.sonar.server.component.ComponentFinder; @@ -57,6 +58,7 @@ import org.sonar.server.setting.ws.SettingValidations.SettingData; 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.exceptions.BadRequestException.checkRequest; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_COMPONENT; import static org.sonar.server.setting.ws.SettingsWsParameters.PARAM_FIELD_VALUES; @@ -103,9 +105,9 @@ public class SetAction implements SettingsWsAction { PARAM_VALUE, PARAM_VALUES) .setSince("6.1") .setChangelog( - new Change("10.1", String.format("The use of module keys in parameter '%s' is removed", PARAM_COMPONENT)), + new Change("10.1", format("The use of module keys in parameter '%s' is removed", PARAM_COMPONENT)), new Change("8.8", "Deprecated parameter 'componentKey' has been removed"), - new Change("7.6", String.format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)), + new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)), new Change("7.1", "The settings defined in conf/sonar.properties are read-only and can't be changed")) .setPost(true) .setHandler(this); @@ -144,10 +146,10 @@ public class SetAction implements SettingsWsAction { } private void doHandle(DbSession dbSession, SetRequest request) { - Optional<ComponentDto> component = searchComponent(dbSession, request); - String projectKey = component.isPresent() ? component.get().getKey() : null; - String projectName = component.isPresent() ? component.get().name() : null; - String qualifier = component.isPresent() ? component.get().qualifier() : null; + Optional<EntityDto> component = searchComponent(dbSession, request); + String projectKey = component.map(EntityDto::getKey).orElse(null); + String projectName = component.map(EntityDto::getName).orElse(null); + String qualifier = component.map(EntityDto::getQualifier).orElse(null); checkPermissions(component); PropertyDefinition definition = propertyDefinitions.get(request.getKey()); @@ -172,16 +174,16 @@ public class SetAction implements SettingsWsAction { } } - private String doHandlePropertySet(DbSession dbSession, SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) { + private String doHandlePropertySet(DbSession dbSession, SetRequest request, @Nullable PropertyDefinition definition, Optional<EntityDto> component) { validatePropertySet(request, definition); int[] fieldIds = IntStream.rangeClosed(1, request.getFieldValues().size()).toArray(); String inlinedFieldKeys = IntStream.of(fieldIds).mapToObj(String::valueOf).collect(COMMA_JOINER); String key = persistedKey(request); - String componentUuid = component.isPresent() ? component.get().uuid() : null; + String componentUuid = component.isPresent() ? component.get().getUuid() : null; String componentKey = component.isPresent() ? component.get().getKey() : null; - String componentName = component.isPresent() ? component.get().name() : null; - String qualifier = component.isPresent() ? component.get().qualifier() : null; + String componentName = component.isPresent() ? component.get().getName() : null; + String qualifier = component.isPresent() ? component.get().getQualifier() : null; deleteSettings(dbSession, component, key); dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey(key).setValue(inlinedFieldKeys) @@ -197,7 +199,7 @@ public class SetAction implements SettingsWsAction { return inlinedFieldKeys; } - private void deleteSettings(DbSession dbSession, Optional<ComponentDto> component, String key) { + private void deleteSettings(DbSession dbSession, Optional<EntityDto> component, String key) { if (component.isPresent()) { settingsUpdater.deleteComponentSettings(dbSession, component.get(), key); } else { @@ -205,7 +207,7 @@ public class SetAction implements SettingsWsAction { } } - private void commonChecks(SetRequest request, Optional<ComponentDto> component) { + private void commonChecks(SetRequest request, Optional<EntityDto> component) { checkValueIsSet(request); String settingKey = request.getKey(); SettingData settingData = new SettingData(settingKey, valuesFromRequest(request), component.orElse(null)); @@ -284,9 +286,9 @@ public class SetAction implements SettingsWsAction { : request.getValue(); } - private void checkPermissions(Optional<ComponentDto> component) { + private void checkPermissions(Optional<EntityDto> component) { if (component.isPresent()) { - userSession.checkComponentPermission(UserRole.ADMIN, component.get()); + userSession.checkEntityPermission(UserRole.ADMIN, component.get()); } else { userSession.checkIsSystemAdministrator(); } @@ -311,19 +313,20 @@ public class SetAction implements SettingsWsAction { try { return gson.fromJson(json, type); } catch (JsonSyntaxException e) { - throw BadRequestException.create(String.format("JSON '%s' does not respect expected format for setting '%s'. Ex: {\"field1\":\"value1\", \"field2\":\"value2\"}", json, key)); + throw BadRequestException.create(format("JSON '%s' does not respect expected format for setting '%s'. Ex: {\"field1\":\"value1\", \"field2\":\"value2\"}", json, key)); } } - private Optional<ComponentDto> searchComponent(DbSession dbSession, SetRequest request) { + private Optional<EntityDto> searchComponent(DbSession dbSession, SetRequest request) { String componentKey = request.getComponent(); if (componentKey == null) { return Optional.empty(); } - return Optional.of(componentFinder.getByKey(dbSession, componentKey)); + return Optional.of(dbClient.projectDao().selectEntityByKey(dbSession, componentKey) + .orElseThrow(() -> new IllegalArgumentException(format("Component '%s' not found", componentKey)))); } - private PropertyDto toProperty(SetRequest request, Optional<ComponentDto> component) { + private PropertyDto toProperty(SetRequest request, Optional<EntityDto> entity) { String key = persistedKey(request); String value = persistedValue(request); @@ -331,8 +334,8 @@ public class SetAction implements SettingsWsAction { .setKey(key) .setValue(value); - if (component.isPresent()) { - property.setComponentUuid(component.get().uuid()); + if (entity.isPresent()) { + property.setComponentUuid(entity.get().getUuid()); } return property; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java index 3cf51c4c2cf..dbe09a53427 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingValidations.java @@ -40,11 +40,10 @@ import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; import org.sonar.core.i18n.I18n; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.metric.MetricDto; import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.BadRequestException; @@ -55,7 +54,7 @@ import static java.util.Objects.requireNonNull; import static org.sonar.server.exceptions.BadRequestException.checkRequest; public class SettingValidations { - private static final Collection<String> SECURITY_JSON_PROPERTIES = asList( + private static final Collection<String> SECURITY_JSON_PROPERTIES = List.of( "sonar.security.config.javasecurity", "sonar.security.config.phpsecurity", "sonar.security.config.pythonsecurity", @@ -76,32 +75,29 @@ public class SettingValidations { public Consumer<SettingData> scope() { return data -> { PropertyDefinition definition = definitions.get(data.key); - checkRequest(data.component != null || definition == null || definition.global() || isGlobal(definition), + checkRequest(data.entity != null || definition == null || definition.global() || isGlobal(definition), "Setting '%s' cannot be global", data.key); }; } public Consumer<SettingData> qualifier() { return data -> { - String qualifier = data.component == null ? "" : data.component.qualifier(); + String qualifier = data.entity == null ? "" : data.entity.getQualifier(); PropertyDefinition definition = definitions.get(data.key); - checkRequest(checkComponentScopeAndQualifier(data, definition), + checkRequest(checkComponentQualifier(data, definition), "Setting '%s' cannot be set on a %s", data.key, i18n.message(Locale.ENGLISH, "qualifier." + qualifier, null)); }; } - private static boolean checkComponentScopeAndQualifier(SettingData data, @Nullable PropertyDefinition definition) { - ComponentDto component = data.component; + private static boolean checkComponentQualifier(SettingData data, @Nullable PropertyDefinition definition) { + EntityDto component = data.entity; if (component == null) { return true; } - if (!Scopes.PROJECT.equals(component.scope())) { - return false; - } if (definition == null) { - return SUPPORTED_QUALIFIERS.contains(component.qualifier()); + return SUPPORTED_QUALIFIERS.contains(component.getQualifier()); } - return definition.qualifiers().contains(component.qualifier()); + return definition.qualifiers().contains(component.getQualifier()); } public Consumer<SettingData> valueType() { @@ -116,12 +112,12 @@ public class SettingValidations { private final String key; private final List<String> values; @CheckForNull - private final ComponentDto component; + private final EntityDto entity; - SettingData(String key, List<String> values, @Nullable ComponentDto component) { + SettingData(String key, List<String> values, @Nullable EntityDto entity) { this.key = requireNonNull(key); this.values = requireNonNull(values); - this.component = component; + this.entity = entity; } } @@ -195,7 +191,6 @@ public class SettingValidations { SchemaLoader.load(jsonSchema).validate(jsonSubject); } } - } } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsUpdater.java index 93e3e745061..ae793d4a9f5 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsUpdater.java @@ -22,12 +22,14 @@ package org.sonar.server.setting.ws; import java.util.List; import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.property.PropertyDto; import static com.google.common.base.Preconditions.checkArgument; @@ -50,54 +52,54 @@ public class SettingsUpdater { public void deleteGlobalSettings(DbSession dbSession, List<String> settingKeys) { checkArgument(!settingKeys.isEmpty(), "At least one setting key is required"); - settingKeys.forEach(key -> delete(dbSession, key, Optional.empty())); + settingKeys.forEach(key -> delete(dbSession, key, null)); } - public void deleteComponentSettings(DbSession dbSession, ComponentDto componentDto, String... settingKeys) { - deleteComponentSettings(dbSession, componentDto, asList(settingKeys)); + public void deleteComponentSettings(DbSession dbSession, EntityDto entity, String... settingKeys) { + deleteComponentSettings(dbSession, entity, asList(settingKeys)); } - public void deleteComponentSettings(DbSession dbSession, ComponentDto componentDto, List<String> settingKeys) { + public void deleteComponentSettings(DbSession dbSession, EntityDto entity, List<String> settingKeys) { checkArgument(!settingKeys.isEmpty(), "At least one setting key is required"); for (String propertyKey : settingKeys) { - delete(dbSession, propertyKey, Optional.of(componentDto)); + delete(dbSession, propertyKey, entity); } } - private void delete(DbSession dbSession, String settingKey, Optional<ComponentDto> componentDto) { + private void delete(DbSession dbSession, String settingKey, @Nullable EntityDto entity) { PropertyDefinition definition = definitions.get(settingKey); if (definition == null || !definition.type().equals(PropertyType.PROPERTY_SET)) { - deleteSetting(dbSession, settingKey, componentDto); + deleteSetting(dbSession, settingKey, entity); } else { - deletePropertySet(dbSession, settingKey, definition, componentDto); + deletePropertySet(dbSession, settingKey, definition, entity); } } - private void deleteSetting(DbSession dbSession, String settingKey, Optional<ComponentDto> componentDto) { - if (componentDto.isPresent()) { - dbClient.propertiesDao().deleteProjectProperty(dbSession, settingKey, componentDto.get().uuid(), componentDto.get().getKey(), - componentDto.get().name(), componentDto.get().qualifier()); + private void deleteSetting(DbSession dbSession, String settingKey, @Nullable EntityDto entity) { + if (entity != null) { + dbClient.propertiesDao().deleteProjectProperty(dbSession, settingKey, entity.getUuid(), entity.getKey(), + entity.getName(), entity.getQualifier()); } else { dbClient.propertiesDao().deleteGlobalProperty(settingKey, dbSession); } } - private void deletePropertySet(DbSession dbSession, String settingKey, PropertyDefinition definition, Optional<ComponentDto> componentDto) { - Optional<PropertyDto> propertyDto = selectPropertyDto(dbSession, settingKey, componentDto); + private void deletePropertySet(DbSession dbSession, String settingKey, PropertyDefinition definition, @Nullable EntityDto entity) { + Optional<PropertyDto> propertyDto = selectPropertyDto(dbSession, settingKey, entity); if (!propertyDto.isPresent()) { // Setting doesn't exist, nothing to do return; } Set<String> settingSetKeys = extractPropertySetKeys(propertyDto.get(), definition); for (String key : settingSetKeys) { - deleteSetting(dbSession, key, componentDto); + deleteSetting(dbSession, key, entity); } - deleteSetting(dbSession, settingKey, componentDto); + deleteSetting(dbSession, settingKey, entity); } - private Optional<PropertyDto> selectPropertyDto(DbSession dbSession, String settingKey, Optional<ComponentDto> componentDto) { - if (componentDto.isPresent()) { - return Optional.ofNullable(dbClient.propertiesDao().selectProjectProperty(dbSession, componentDto.get().uuid(), settingKey)); + private Optional<PropertyDto> selectPropertyDto(DbSession dbSession, String settingKey, @Nullable EntityDto entity) { + if (entity != null) { + return Optional.ofNullable(dbClient.propertiesDao().selectProjectProperty(dbSession, entity.getUuid(), settingKey)); } else { return Optional.ofNullable(dbClient.propertiesDao().selectGlobalProperty(dbSession, settingKey)); } |