return getMapper(session).selectByKeyAndMatchingValue(key, value);
}
+ public List<PropertyDto> selectByKeyAndUserIdAndComponentQualifier(DbSession session, String key, int userId, String qualifier) {
+ return getMapper(session).selectByKeyAndUserIdAndComponentQualifier(key, userId, qualifier);
+ }
+
/**
* Saves the specified property and its value.
* <p>
List<PropertyDto> selectByKeysAndComponentIds(@Param("keys") List<String> keys, @Param("componentIds") List<Long> componentIds);
+ List<PropertyDto> selectByKeyAndUserIdAndComponentQualifier(@Param("key") String key, @Param("userId") int userId, @Param("qualifier") String qualifier);
+
List<PropertyDto> selectByComponentIds(@Param("componentIds") List<Long> componentIds);
List<PropertyDto> selectByQuery(@Param("query") PropertyQuery query);
and p.user_id is null
</select>
+ <select id="selectByKeyAndUserIdAndComponentQualifier" parameterType="map" resultType="ScrapProperty">
+ select
+ <include refid="columnsToScrapPropertyDto"/>
+ from
+ properties p
+ inner join projects prj on prj.id=p.resource_id and prj.qualifier = #{qualifier, jdbcType=VARCHAR}
+ where
+ p.prop_key = #{key, jdbcType=VARCHAR}
+ and p.user_id = #{userId, jdbcType=INTEGER}
+ </select>
+
<select id="selectByQuery" parameterType="map" resultType="ScrapProperty">
select
<include refid="columnsToScrapPropertyDto"/>
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.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
import static org.mockito.Mockito.when;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
+import static org.sonar.db.property.PropertyTesting.newPropertyDto;
import static org.sonar.db.property.PropertyTesting.newUserPropertyDto;
@RunWith(DataProviderRunner.class)
newComponentPropertyDto("another key", "value", project1));
assertThat(underTest.selectByKeyAndMatchingValue(db.getSession(), "key", "value"))
- .extracting(PropertyDto::getValue, PropertyDto::getResourceId)
- .containsExactlyInAnyOrder(
- tuple("value", project1.getId()),
- tuple("value", project2.getId()),
- tuple("value", null)
- );
+ .extracting(PropertyDto::getValue, PropertyDto::getResourceId)
+ .containsExactlyInAnyOrder(
+ tuple("value", project1.getId()),
+ tuple("value", project2.getId()),
+ tuple("value", null));
+ }
+
+ @Test
+ public void selectByKeyAndUserIdAndComponentQualifier() {
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(project1));
+ ComponentDto project2 = db.components().insertPrivateProject();
+ db.properties().insertProperties(
+ newPropertyDto("key", "1", project1, user1),
+ newPropertyDto("key", "2", project2, user1),
+ newPropertyDto("key", "3", file1, user1),
+ newPropertyDto("another key", "4", project1, user1),
+ newPropertyDto("key", "5", project1, user2),
+ newGlobalPropertyDto("key", "global"));
+
+ assertThat(underTest.selectByKeyAndUserIdAndComponentQualifier(db.getSession(), "key", user1.getId(), "TRK"))
+ .extracting(PropertyDto::getValue).containsExactlyInAnyOrder("1", "2");
+ assertThat(underTest.selectByKeyAndUserIdAndComponentQualifier(db.getSession(), "key", user1.getId(), "FIL"))
+ .extracting(PropertyDto::getValue).containsExactlyInAnyOrder("3");
+ assertThat(underTest.selectByKeyAndUserIdAndComponentQualifier(db.getSession(), "key", user2.getId(), "FIL")).isEmpty();
}
@Test
.add(2605, "Add SNAPSHOTS.PROJECT_VERSION", AddProjectVersionToSnapshot.class)
.add(2606, "Drop DATA_TYPE column from FILE_SOURCES table", DropDataTypeFromFileSources.class)
.add(2607, "Add MEMBERS_SYNC_ENABLED column to ORGANIZATIONS_ALM_BINDING table", AddMembersSyncFlagToOrgAlmBinding.class)
- .add(2608, "Delete favorites on not supported components", DeleteFavouritesOnNotSupportedComponentQualifiers.class);
+ .add(2608, "Delete favorites on not supported components", DeleteFavouritesOnNotSupportedComponentQualifiers.class)
+ .add(2609, "Delete exceeding favorites when there are more than 100 for a user", DeleteFavoritesExceedingOneHundred.class);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.platform.db.migration.version.v77;
+
+import java.sql.SQLException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.Upsert;
+
+import static java.util.Arrays.asList;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+
+@SupportsBlueGreen
+public class DeleteFavoritesExceedingOneHundred extends DataChange {
+
+ private static final Logger LOG = Loggers.get(DeleteFavoritesExceedingOneHundred.class);
+
+ private static final String FAVOURITE_PROPERTY = "favourite";
+
+ private static final List<String> SORTED_QUALIFIERS = asList("TRK", "VW", "APP", "SVW", "FIL");
+
+ public DeleteFavoritesExceedingOneHundred(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ List<Integer> userIdsHavingMoreThanOneHundredFavourites = context.prepareSelect("SELECT user_id FROM " +
+ "(SELECT DISTINCT user_id, COUNT(id) AS nb FROM properties WHERE prop_key = ? AND user_id IS NOT NULL GROUP BY user_id) sub " +
+ "WHERE sub.nb > 100")
+ .setString(1, FAVOURITE_PROPERTY)
+ .list(row -> row.getInt(1));
+ LOG.info("Deleting favourites exceeding one hundred elements for {} users", userIdsHavingMoreThanOneHundredFavourites.size());
+ for (Integer userId : userIdsHavingMoreThanOneHundredFavourites) {
+ List<Integer> propertyIdsToKeep = context.prepareSelect("SELECT prop.id, p.qualifier, p.enabled FROM properties prop " +
+ "INNER JOIN projects p ON p.id=prop.resource_id " +
+ "WHERE prop.prop_key=? AND prop.user_id = ?")
+ .setString(1, FAVOURITE_PROPERTY)
+ .setInt(2, userId)
+ .list(Property::new)
+ .stream()
+ .sorted()
+ .map(Property::getId)
+ .limit(100)
+ .collect(toList());
+
+ String idsToString = IntStream.range(0, propertyIdsToKeep.size()).mapToObj(i -> "?").collect(Collectors.joining(","));
+ Upsert upsert = context.prepareUpsert("DELETE FROM properties WHERE prop_key=? AND user_id=? AND id NOT in (" + idsToString + ")")
+ .setString(1, FAVOURITE_PROPERTY)
+ .setInt(2, userId);
+ int index = 3;
+ for (Integer id : propertyIdsToKeep) {
+ upsert.setInt(index, id);
+ index++;
+ }
+ upsert.execute().commit();
+ }
+ }
+
+ private static class Property implements Comparable<Property> {
+ private final int id;
+ private final String qualifier;
+ private final boolean enabled;
+
+ Property(Select.Row row) throws SQLException {
+ this.id = row.getInt(1);
+ this.qualifier = row.getString(2);
+ this.enabled = row.getBoolean(3);
+ }
+
+ int getId() {
+ return id;
+ }
+
+ String getQualifier() {
+ return qualifier;
+ }
+
+ boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Property property = (Property) o;
+ return id == property.id;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public int compareTo(Property o) {
+ return Comparator.comparing(Property::isEnabled)
+ .reversed()
+ .thenComparing(property -> SORTED_QUALIFIERS.indexOf(property.getQualifier()))
+ .compare(this, o);
+ }
+ }
+
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 9);
+ verifyMigrationCount(underTest, 10);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.server.platform.db.migration.version.v77;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static java.util.stream.IntStream.rangeClosed;
+import static org.apache.commons.lang.math.RandomUtils.nextInt;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DeleteFavoritesExceedingOneHundredTest {
+
+ private static final String TABLE = "properties";
+ private static final String FAVOURITE_PROPERTY = "favourite";
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(DeleteFavoritesExceedingOneHundredTest.class, "schema.sql");
+
+ private DeleteFavoritesExceedingOneHundred underTest = new DeleteFavoritesExceedingOneHundred(db.database());
+
+ @Test
+ public void delete_favorites_when_user_has_more_than_100() throws SQLException {
+ int user1Id = nextInt();
+ insertProperties(user1Id, "TRK", 110);
+ int user2Id = nextInt();
+ insertProperties(user2Id, "TRK", 130);
+ int user3Id = nextInt();
+ insertProperties(user3Id, "TRK", 90);
+
+ underTest.execute();
+
+ assertFavorites(user1Id, 100);
+ assertFavorites(user2Id, 100);
+ assertFavorites(user3Id, 90);
+ }
+
+ @Test
+ public void keep_in_priority_projects_over_files() throws SQLException {
+ int userId = nextInt();
+ insertProperties(userId, "TRK", 90);
+ insertProperties(userId, "FIL", 20);
+ underTest.execute();
+
+ assertFavorites(userId, "TRK", 90);
+ assertFavorites(userId, "FIL", 10);
+ }
+
+ @Test
+ public void keep_in_priority_views_over_sub_views() throws SQLException {
+ int userId = nextInt();
+ insertProperties(userId, "VW", 90);
+ insertProperties(userId, "SVW", 20);
+ underTest.execute();
+
+ assertFavorites(userId, "VW", 90);
+ assertFavorites(userId, "SVW", 10);
+ }
+
+ @Test
+ public void keep_in_priority_apps_over_sub_views() throws SQLException {
+ int userId = nextInt();
+ insertProperties(userId, "APP", 90);
+ insertProperties(userId, "SVW", 20);
+ underTest.execute();
+
+ assertFavorites(userId, "APP", 90);
+ assertFavorites(userId, "SVW", 10);
+ }
+
+ @Test
+ public void keep_in_priority_enabled_projects() throws SQLException {
+ int userId = nextInt();
+ insertProperties(userId, "TRK", 90);
+ rangeClosed(1, 20).forEach(i -> {
+ int componentId = insertDisabledComponent("TRK");
+ insertProperty(FAVOURITE_PROPERTY, userId, componentId);
+ });
+
+ underTest.execute();
+
+ assertFavorites(userId, "TRK", true, 90);
+ assertFavorites(userId, "TRK", false, 10);
+ }
+
+ @Test
+ public void ignore_non_favorite_properties() throws SQLException {
+ int userId = nextInt();
+ rangeClosed(1, 130).forEach(i -> {
+ int componentId = insertComponent("TRK");
+ insertProperty("other", userId, componentId);
+ });
+
+ underTest.execute();
+
+ assertProperties("other", userId, 130);
+ }
+
+ private void assertFavorites(int userId, int expectedSize) {
+ assertProperties(FAVOURITE_PROPERTY, userId, expectedSize);
+ }
+
+ private void assertFavorites(int userId, String qualifier, int expectedSize) {
+ assertThat(db.countSql("SELECT count(prop.id) FROM properties prop " +
+ "INNER JOIN projects p ON p.id=prop.resource_id AND p.qualifier='" + qualifier + "'" +
+ "WHERE prop.user_id=" + userId + " AND prop.prop_key='" + FAVOURITE_PROPERTY + "'"))
+ .isEqualTo(expectedSize);
+ }
+
+ private void assertFavorites(int userId, String qualifier, boolean enabled, int expectedSize) {
+ assertThat(db.countSql("SELECT count(prop.id) FROM properties prop " +
+ "INNER JOIN projects p ON p.id=prop.resource_id AND p.qualifier='" + qualifier + "' AND p.enabled='" + enabled + "'" +
+ "WHERE prop.user_id=" + userId + " AND prop.prop_key='" + FAVOURITE_PROPERTY + "'"))
+ .isEqualTo(expectedSize);
+ }
+
+ private void assertProperties(String propertyKey, int userId, int expectedSize) {
+ assertThat(db.countSql("SELECT count(ID) FROM properties WHERE user_id=" + userId + " AND prop_key='" + propertyKey + "'")).isEqualTo(expectedSize);
+ }
+
+ private void insertProperties(int userId, String qualifier, int nbProperties) {
+ rangeClosed(1, nbProperties).forEach(i -> {
+ int componentId = insertComponent(qualifier);
+ insertProperty(FAVOURITE_PROPERTY, userId, componentId);
+ });
+ }
+
+ private void insertProperty(String key, int userId, int componentId) {
+ db.executeInsert(
+ TABLE,
+ "PROP_KEY", key,
+ "USER_ID", userId,
+ "RESOURCE_ID", componentId,
+ "IS_EMPTY", true,
+ "CREATED_AT", 123456);
+ }
+
+ private int insertComponent(String qualifier) {
+ return insertCommonComponent(qualifier, true);
+ }
+
+ private int insertDisabledComponent(String qualifier) {
+ return insertCommonComponent(qualifier, false);
+ }
+
+ private int insertCommonComponent(String qualifier, boolean enabled) {
+ int id = nextInt();
+ String uuid = "uuid_" + id;
+ db.executeInsert(
+ "projects",
+ "ID", id,
+ "UUID", uuid,
+ "ORGANIZATION_UUID", "org_" + id,
+ "UUID_PATH", "path_" + id,
+ "ROOT_UUID", "root_" + id,
+ "PROJECT_UUID", "project_" + id,
+ "QUALIFIER", qualifier,
+ "ENABLED", enabled,
+ "PRIVATE", false);
+ return id;
+ }
+
+}
--- /dev/null
+CREATE TABLE "PROPERTIES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "PROP_KEY" VARCHAR(512) NOT NULL,
+ "RESOURCE_ID" INTEGER,
+ "USER_ID" INTEGER,
+ "IS_EMPTY" BOOLEAN NOT NULL,
+ "TEXT_VALUE" VARCHAR(4000),
+ "CLOB_VALUE" CLOB,
+ "CREATED_AT" BIGINT
+);
+CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY");
+
+CREATE TABLE "PROJECTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+ "KEE" VARCHAR(400),
+ "UUID" VARCHAR(50) NOT NULL,
+ "UUID_PATH" VARCHAR(1500) NOT NULL,
+ "ROOT_UUID" VARCHAR(50) NOT NULL,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "MODULE_UUID" VARCHAR(50),
+ "MODULE_UUID_PATH" VARCHAR(1500),
+ "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+ "NAME" VARCHAR(2000),
+ "DESCRIPTION" VARCHAR(2000),
+ "PRIVATE" BOOLEAN NOT NULL,
+ "TAGS" VARCHAR(500),
+ "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+ "SCOPE" VARCHAR(3),
+ "QUALIFIER" VARCHAR(10),
+ "DEPRECATED_KEE" VARCHAR(400),
+ "PATH" VARCHAR(2000),
+ "LANGUAGE" VARCHAR(20),
+ "COPY_COMPONENT_UUID" VARCHAR(50),
+ "LONG_NAME" VARCHAR(2000),
+ "DEVELOPER_UUID" VARCHAR(50),
+ "CREATED_AT" TIMESTAMP,
+ "AUTHORIZATION_UPDATED_AT" BIGINT,
+ "B_CHANGED" BOOLEAN,
+ "B_COPY_COMPONENT_UUID" VARCHAR(50),
+ "B_DESCRIPTION" VARCHAR(2000),
+ "B_ENABLED" BOOLEAN,
+ "B_UUID_PATH" VARCHAR(1500),
+ "B_LANGUAGE" VARCHAR(20),
+ "B_LONG_NAME" VARCHAR(500),
+ "B_MODULE_UUID" VARCHAR(50),
+ "B_MODULE_UUID_PATH" VARCHAR(1500),
+ "B_NAME" VARCHAR(500),
+ "B_PATH" VARCHAR(2000),
+ "B_QUALIFIER" VARCHAR(10)
+);
+
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
/**
* Set favorite to the logged in user. If no user, no action is done
*/
- public void add(DbSession dbSession, ComponentDto componentDto, @Nullable Integer userId) {
+ public void add(DbSession dbSession, ComponentDto componentDto, @Nullable Integer userId, boolean failIfTooManyFavorites) {
if (userId == null) {
return;
}
.setComponentId(componentDto.getId())
.build(), dbSession);
checkArgument(existingFavoriteOnComponent.isEmpty(), "Component '%s' is already a favorite", componentDto.getDbKey());
+
+ List<PropertyDto> existingFavorites = dbClient.propertiesDao().selectByKeyAndUserIdAndComponentQualifier(dbSession, PROP_FAVORITE_KEY, userId, componentDto.qualifier());
+ if (existingFavorites.size() >= 100) {
+ checkArgument(!failIfTooManyFavorites, "You cannot have more than 100 favorites on components with qualifier '%s'", componentDto.qualifier());
+ return;
+ }
dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
.setKey(PROP_FAVORITE_KEY)
.setResourceId(componentDto.getId())
*/
package org.sonar.server.favorite;
+import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
-import org.sonar.db.organization.OrganizationTesting;
import org.sonar.db.property.PropertyQuery;
+import org.sonar.db.user.UserDto;
import static org.assertj.core.api.Assertions.assertThat;
public class FavoriteUpdaterTest {
- private static final long COMPONENT_ID = 23L;
- private static final String COMPONENT_KEY = "K1";
- private static final ComponentDto COMPONENT = ComponentTesting.newPrivateProjectDto(OrganizationTesting.newOrganizationDto())
- .setId(COMPONENT_ID)
- .setDbKey(COMPONENT_KEY);
- private static final int USER_ID = 42;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
+ public DbTester db = DbTester.create();
private DbClient dbClient = db.getDbClient();
private DbSession dbSession = db.getSession();
@Test
public void put_favorite() {
- assertNoFavorite();
+ ComponentDto project = db.components().insertPrivateProject();
+ UserDto user = db.users().insertUser();
+ assertNoFavorite(project, user);
- underTest.add(dbSession, COMPONENT, USER_ID);
+ underTest.add(dbSession, project, user.getId(), true);
- assertFavorite();
+ assertFavorite(project, user);
}
@Test
public void do_nothing_when_no_user() {
- underTest.add(dbSession, COMPONENT, null);
+ ComponentDto project = db.components().insertPrivateProject();
- assertNoFavorite();
+ underTest.add(dbSession, project, null, true);
+
+ assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+ .setComponentId(project.getId())
+ .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(), user.getId()));
+ assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+ .setUserId(user.getId())
+ .build(), dbSession)).hasSize(100);
+ ComponentDto project = db.components().insertPrivateProject();
+
+ underTest.add(dbSession, project, user.getId(), false);
+
+ assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+ .setUserId(user.getId())
+ .build(), dbSession)).hasSize(100);
+ }
+
+ @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(), user.getId()));
+ assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+ .setUserId(user.getId())
+ .build(), dbSession)).hasSize(100);
+ ComponentDto project = db.components().insertPrivateProject();
+
+ underTest.add(dbSession, project, user.getId(), false);
+
+ assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+ .setUserId(user.getId())
+ .build(), dbSession)).hasSize(100);
+ }
+
+ @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(), user.getId()));
+ ComponentDto project = db.components().insertPrivateProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("You cannot have more than 100 favorites on components with qualifier 'TRK'");
+
+ underTest.add(dbSession, project, user.getId(), true);
}
@Test
public void fail_when_adding_existing_favorite() {
- underTest.add(dbSession, COMPONENT, USER_ID);
- assertFavorite();
+ ComponentDto project = db.components().insertPrivateProject();
+ UserDto user = db.users().insertUser();
+ underTest.add(dbSession, project, user.getId(), true);
+ assertFavorite(project, user);
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Component 'K1' is already a favorite");
+ expectedException.expectMessage(String.format("Component '%s' is already a favorite", project.getKey()));
- underTest.add(dbSession, COMPONENT, USER_ID);
+ underTest.add(dbSession, project, user.getId(), true);
}
- private void assertFavorite() {
+ private void assertFavorite(ComponentDto project, UserDto user) {
assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
- .setUserId(USER_ID)
- .setComponentId(COMPONENT_ID)
+ .setUserId(user.getId())
+ .setComponentId(project.getId())
.build(), dbSession)).hasSize(1);
}
- private void assertNoFavorite() {
+ private void assertNoFavorite(ComponentDto project, UserDto user) {
assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
- .setUserId(USER_ID)
- .setComponentId(COMPONENT_ID)
+ .setUserId(user.getId())
+ .setComponentId(project.getId())
.build(), dbSession)).isEmpty();
}
}
* - Create component
* - Apply default permission template
* - Add component to favorite if the component has the 'Project Creators' permission
- * - Index component if es indexes
+ * - Index component in es indexes
*/
public ComponentDto create(DbSession dbSession, NewComponent newComponent, @Nullable Integer userId) {
ComponentDto componentDto = createWithoutCommit(dbSession, newComponent, userId);
&& MAIN_BRANCH_QUALIFIERS.contains(componentDto.qualifier());
}
- private BranchDto createMainBranch(DbSession session, String componentUuid) {
+ private void createMainBranch(DbSession session, String componentUuid) {
BranchDto branch = new BranchDto()
.setBranchType(BranchType.LONG)
.setUuid(componentUuid)
.setKey(BranchDto.DEFAULT_MAIN_BRANCH_NAME)
.setMergeBranchUuid(null)
.setProjectUuid(componentUuid);
-
dbClient.branchDao().upsert(session, branch);
- return branch;
}
/**
permissionTemplateService.applyDefault(dbSession, componentDto, userId);
if (componentDto.qualifier().equals(PROJECT)
&& permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(dbSession, componentDto)) {
- favoriteUpdater.add(dbSession, componentDto, userId);
+ favoriteUpdater.add(dbSession, componentDto, userId, false);
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.server.component;
-
-import org.sonar.api.server.ServerSide;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.server.organization.DefaultOrganizationProvider;
-import org.sonar.server.user.UserSession;
-
-import static org.sonar.server.component.NewComponent.newComponentBuilder;
-
-/**
- * Used in GOV
- */
-@ServerSide
-public class DefaultRubyComponentService {
-
- private final UserSession userSession;
- private final DbClient dbClient;
- private final ComponentUpdater componentUpdater;
- private final DefaultOrganizationProvider defaultOrganizationProvider;
-
- public DefaultRubyComponentService(UserSession userSession, DbClient dbClient, ComponentUpdater componentUpdater,
- DefaultOrganizationProvider defaultOrganizationProvider) {
- this.userSession = userSession;
- this.dbClient = dbClient;
- this.componentUpdater = componentUpdater;
- this.defaultOrganizationProvider = defaultOrganizationProvider;
- }
-
- // Used in GOV
- /**
- * @deprecated Use {@link ComponentUpdater#create(DbSession, NewComponent, Integer)} instead
- */
- @Deprecated
- public Long createComponent(String key, String name, String qualifier) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- NewComponent newComponent = newComponentBuilder()
- .setOrganizationUuid(defaultOrganizationProvider.get().getUuid())
- .setKey(key)
- .setName(name)
- .setQualifier(qualifier)
- .build();
- return componentUpdater.create(
- dbSession,
- newComponent,
- userSession.isLoggedIn() ? userSession.getUserId() : null).getId();
- }
- }
-
-}
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction("add")
.setDescription("Add a component (project, file etc.) as favorite for the authenticated user.<br>" +
+ "Only 100 components by qualifier can be added as favorite.<br>" +
"Requires authentication and the following permission: 'Browse' on the project of the specified component.")
.setSince("6.3")
.setChangelog(
- new Change("7.7", "It's no more possible to set a directory as favorite"),
+ new Change("7.7", "It's no longer possible to have more than 100 favorites by qualifier"),
+ new Change("7.7", "It's no longer possible to set a directory as favorite"),
new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT)))
.setPost(true)
.setHandler(this);
userSession
.checkLoggedIn()
.checkComponentPermission(USER, componentDto);
- favoriteUpdater.add(dbSession, componentDto, userSession.isLoggedIn() ? userSession.getUserId() : null);
+ favoriteUpdater.add(dbSession, componentDto, userSession.isLoggedIn() ? userSession.getUserId() : null, true);
dbSession.commit();
}
};
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.i18n.I18n;
import org.sonar.api.utils.System2;
import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeQueueImpl;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
-import org.sonar.server.component.NewComponent;
+import org.sonar.server.es.TestProjectIndexers;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyMap;
+import static java.util.stream.IntStream.rangeClosed;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
-import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
import static org.sonar.db.permission.OrganizationPermission.SCAN;
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
+ public DbTester db = DbTester.create();
private String defaultOrganizationKey;
private String defaultOrganizationUuid;
+
private CeQueue queue = mock(CeQueueImpl.class);
- private ComponentUpdater componentUpdater = mock(ComponentUpdater.class);
+ private TestProjectIndexers projectIndexers = new TestProjectIndexers();
private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
- private FavoriteUpdater favoriteUpdater = mock(FavoriteUpdater.class);
+ private ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
+ new FavoriteUpdater(db.getDbClient()), projectIndexers);
private BranchSupport ossEditionBranchSupport = new BranchSupport();
private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport);
userSession
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid())
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());
-
- ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY);
mockSuccessfulPrepareSubmitCall();
- when(componentUpdater.create(any(), any(), any())).thenReturn(project);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY)))
.thenReturn(true);
Map<String, String> nonEmptyCharacteristics = IntStream.range(0, 1 + new Random().nextInt(5))
userSession
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid())
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());
-
- ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY);
mockSuccessfulPrepareSubmitCall();
- when(componentUpdater.createWithoutCommit(any(), any(), any())).thenReturn(project);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY)))
.thenReturn(true);
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8));
verifyReportIsPersisted(TASK_UUID);
- verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(project));
}
@Test
verifyReportIsPersisted(TASK_UUID);
verifyZeroInteractions(permissionTemplateService);
- verifyZeroInteractions(favoriteUpdater);
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT)
&& submit.getComponent().filter(cpt -> cpt.getUuid().equals(project.uuid()) && cpt.getMainComponentUuid().equals(project.uuid())).isPresent()
&& submit.getSubmitterUuid().equals(user.getUuid())
userSession
.addPermission(OrganizationPermission.SCAN, organization.getUuid())
.addPermission(PROVISION_PROJECTS, organization);
-
mockSuccessfulPrepareSubmitCall();
- ComponentDto createdProject = newPrivateProjectDto(organization, PROJECT_UUID).setDbKey(PROJECT_KEY);
- when(componentUpdater.createWithoutCommit(any(), any(), isNull())).thenReturn(createdProject);
- when(
- permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY)))
- .thenReturn(true);
+ when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true);
when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true);
underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
+ ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get();
verifyReportIsPersisted(TASK_UUID);
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT)
- && submit.getComponent().filter(cpt -> cpt.getUuid().equals(PROJECT_UUID) && cpt.getMainComponentUuid().equals(PROJECT_UUID)).isPresent()
+ && submit.getComponent().filter(cpt -> cpt.getUuid().equals(createdProject.uuid()) && cpt.getMainComponentUuid().equals(createdProject.uuid())).isPresent()
&& submit.getUuid().equals(TASK_UUID)));
- verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(createdProject));
}
@Test
- public void no_favorite_when_no_project_creator_permission_on_permission_template() {
+ public void add_project_as_favorite_when_project_creator_permission_on_permission_template() {
+ UserDto user = db.users().insertUser();
+ OrganizationDto organization = db.organizations().insert();
+ userSession
+ .logIn(user)
+ .addPermission(OrganizationPermission.SCAN, organization.getUuid())
+ .addPermission(PROVISION_PROJECTS, organization);
+ mockSuccessfulPrepareSubmitCall();
+ when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true);
+ when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true);
+
+ underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
+
+ ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get();
+ assertThat(db.favorites().hasFavorite(createdProject, user.getId())).isTrue();
+ }
+
+ @Test
+ public void do_no_add_favorite_when_no_project_creator_permission_on_permission_template() {
userSession
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid())
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());
-
- ComponentDto createdProject = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY);
- when(componentUpdater.createWithoutCommit(any(), any(), isNull())).thenReturn(createdProject);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY)))
.thenReturn(true);
when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(false);
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
- verifyZeroInteractions(favoriteUpdater);
- verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(createdProject));
+ ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(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(), user.getId()));
+ OrganizationDto organization = db.organizations().insert();
+ userSession
+ .logIn(user)
+ .addPermission(OrganizationPermission.SCAN, organization.getUuid())
+ .addPermission(PROVISION_PROJECTS, organization);
+ mockSuccessfulPrepareSubmitCall();
+ when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(organization.getUuid()), any(), eq(PROJECT_KEY))).thenReturn(true);
+ when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true);
+
+ underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
+
+ ComponentDto createdProject = db.getDbClient().componentDao().selectByKey(db.getSession(), PROJECT_KEY).get();
+ assertThat(db.favorites().hasNoFavorite(createdProject)).isTrue();
}
@Test
userSession
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid())
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization());
-
- ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY);
mockSuccessfulPrepareSubmitCall();
- when(componentUpdater.createWithoutCommit(any(), any(), any())).thenReturn(project);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY)))
.thenReturn(true);
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
verify(queue).submit(any(CeTaskSubmit.class));
- verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(project));
}
@Test
@Test
public void project_branch_must_not_benefit_from_the_scan_permission_on_main_project() {
String branchName = "branchFoo";
-
ComponentDto mainProject = db.components().insertPrivateProject();
userSession.addProjectPermission(GlobalPermissions.SCAN_EXECUTION, mainProject);
-
// user does not have the "scan" permission on the branch, so it can't scan it
ComponentDto branchProject = db.components().insertPrivateProject(p -> p.setDbKey(mainProject.getDbKey() + ":" + branchName));
ComponentDto component = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID);
userSession.addProjectPermission(SCAN_EXECUTION, component);
mockSuccessfulPrepareSubmitCall();
- when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setDbKey(PROJECT_KEY));
expectedException.expect(ForbiddenException.class);
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}"));
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.BranchType;
import org.sonar.server.l18n.I18nRule;
import org.sonar.server.permission.PermissionTemplateService;
+import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@Test
public void add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template() {
UserDto userDto = db.users().insertUser();
+ NewComponent project = NewComponent.newComponentBuilder()
+ .setKey(DEFAULT_PROJECT_KEY)
+ .setName(DEFAULT_PROJECT_NAME)
+ .setOrganizationUuid(db.getDefaultOrganization().getUuid())
+ .build();
+ when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class)))
+ .thenReturn(true);
+
+ ComponentDto dto = underTest.create(db.getSession(), project, userDto.getId());
+
+ assertThat(db.favorites().hasFavorite(dto, userDto.getId())).isTrue();
+ }
+
+ @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(), user.getId()));
NewComponent project = NewComponent.newComponentBuilder()
.setKey(DEFAULT_PROJECT_KEY)
.setName(DEFAULT_PROJECT_NAME)
ComponentDto dto = underTest.create(db.getSession(),
project,
- userDto.getId());
+ user.getId());
- assertThat(db.favorites().hasFavorite(dto, userDto.getId())).isTrue();
+ assertThat(db.favorites().hasFavorite(dto, user.getId())).isFalse();
}
@Test
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.es.TestProjectIndexers;
import org.sonar.server.exceptions.BadRequestException;
import org.sonarqube.ws.Projects.CreateWsResponse.Project;
import static java.util.Optional.ofNullable;
+import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
import static org.sonar.server.project.Visibility.PRIVATE;
import static org.sonar.server.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class);
private TestProjectIndexers projectIndexers = new TestProjectIndexers();
+ private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
private WsActionTester ws = new WsActionTester(
new CreateAction(
new ProjectsWsSupport(db.getDbClient(), defaultOrganizationProvider, billingValidations),
db.getDbClient(), userSession,
- new ComponentUpdater(db.getDbClient(), i18n, system2, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()),
+ new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()),
projectIndexers)));
@Test
.isEqualTo(Strings.repeat("a", 497) + "...");
}
+ @Test
+ public void add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template() {
+ OrganizationDto organization = db.organizations().insert();
+ UserDto user = db.users().insertUser();
+ when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(DbSession.class), any(ComponentDto.class))).thenReturn(true);
+ userSession.logIn(user).addPermission(PROVISION_PROJECTS, organization);
+
+ ws.newRequest()
+ .setParam("key", DEFAULT_PROJECT_KEY)
+ .setParam("name", DEFAULT_PROJECT_NAME)
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(CreateWsResponse.class);
+
+ ComponentDto project = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
+ assertThat(db.favorites().hasFavorite(project, user.getId())).isTrue();
+ }
+
+ @Test
+ public void do_not_add_project_to_user_favorites_if_project_creator_is_defined_in_permission_template_and_already_100_favorites() {
+ OrganizationDto organization = db.organizations().insert();
+ 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(), user.getId()));
+ userSession.logIn(user).addPermission(PROVISION_PROJECTS, organization);
+
+ ws.newRequest()
+ .setParam("key", DEFAULT_PROJECT_KEY)
+ .setParam("name", DEFAULT_PROJECT_NAME)
+ .setParam("organization", organization.getKey())
+ .executeProtobuf(CreateWsResponse.class);
+
+ ComponentDto project = db.getDbClient().componentDao().selectByKey(db.getSession(), DEFAULT_PROJECT_KEY).get();
+ assertThat(db.favorites().hasNoFavorite(project)).isTrue();
+ }
+
@Test
public void fail_to_create_private_projects_when_organization_is_not_allowed_to_use_private_projects() {
OrganizationDto organization = db.organizations().insert();