aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-dao
diff options
context:
space:
mode:
authorBenoit <benoit.gianinetti@sonarsource.com>2019-07-12 14:06:47 +0200
committerSonarTech <sonartech@sonarsource.com>2019-07-12 20:21:16 +0200
commit7f1afd8ce4723dad04762837efec3b4b2525dff5 (patch)
tree868fce46d90be48623e237c195a64e9aff091696 /server/sonar-db-dao
parentc2d9ced3637a5aa08422427e6435aaecaf659feb (diff)
downloadsonarqube-7f1afd8ce4723dad04762837efec3b4b2525dff5.tar.gz
sonarqube-7f1afd8ce4723dad04762837efec3b4b2525dff5.zip
MMF-769 User can close their account (#1861)
Diffstat (limited to 'server/sonar-db-dao')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDto.java14
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationHelper.java47
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java42
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java11
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java2
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml27
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml20
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java69
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationHelperTest.java141
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationQueryTest.java67
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java49
12 files changed, 251 insertions, 242 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDto.java
index f82bd6588a8..33a703a0be9 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationDto.java
@@ -73,10 +73,6 @@ public class OrganizationDto {
private Subscription subscription;
- /**
- * Flag indicated whether being root is required to be able to delete this organization.
- */
- private boolean guarded = false;
private Integer defaultGroupId;
private String defaultQualityGateUuid;
private long createdAt;
@@ -139,15 +135,6 @@ public class OrganizationDto {
return this;
}
- public boolean isGuarded() {
- return guarded;
- }
-
- public OrganizationDto setGuarded(boolean guarded) {
- this.guarded = guarded;
- return this;
- }
-
@CheckForNull
public Integer getDefaultGroupId() {
return defaultGroupId;
@@ -220,7 +207,6 @@ public class OrganizationDto {
", description='" + description + '\'' +
", url='" + url + '\'' +
", avatarUrl='" + avatarUrl + '\'' +
- ", guarded=" + guarded +
", defaultQualityGateUuid=" + defaultQualityGateUuid +
", subscription=" + subscription +
", createdAt=" + createdAt +
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationHelper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationHelper.java
new file mode 100644
index 00000000000..ef304882a3a
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationHelper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.db.organization;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.permission.OrganizationPermission;
+
+public class OrganizationHelper {
+
+ private static final String ADMIN_PERMISSION = OrganizationPermission.ADMINISTER.getKey();
+
+ private final DbClient dbClient;
+
+ public OrganizationHelper(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ public List<OrganizationDto> selectOrganizationsWithLastAdmin(DbSession dbSession, int userId) {
+ return dbClient.organizationDao().selectByPermission(dbSession, userId, ADMIN_PERMISSION).stream()
+ .filter(org -> isLastAdmin(dbSession, org, userId))
+ .collect(Collectors.toList());
+ }
+
+ private boolean isLastAdmin(DbSession dbSession, OrganizationDto org, int userId) {
+ return dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUser(dbSession, org.getUuid(), ADMIN_PERMISSION, userId) == 0;
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
index da63b59d512..899bcba33cb 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
@@ -32,27 +32,15 @@ public class OrganizationQuery {
private final Set<String> keys;
@Nullable
private final Integer userId;
- private final boolean onlyTeam;
- private final boolean onlyPersonal;
private final boolean withAnalyses;
- private final boolean withoutProjects;
@Nullable
private final Long analyzedAfter;
private OrganizationQuery(Builder builder) {
this.keys = builder.keys;
this.userId = builder.member;
- this.onlyPersonal = builder.onlyPersonal;
- this.onlyTeam = builder.onlyTeam;
- if (this.onlyPersonal && this.onlyTeam) {
- throw new IllegalArgumentException("Only one of onlyPersonal and onlyTeam can be true");
- }
this.withAnalyses = builder.withAnalyses;
this.analyzedAfter = builder.analyzedAfter;
- this.withoutProjects = builder.withoutProjects;
- if ((this.withAnalyses || this.analyzedAfter != null) && this.withoutProjects) {
- throw new IllegalArgumentException("withoutProjects cannot be used together with withAnalyses or analyzedAfter");
- }
}
@CheckForNull
@@ -65,14 +53,6 @@ public class OrganizationQuery {
return userId;
}
- public boolean isOnlyTeam() {
- return onlyTeam;
- }
-
- public boolean isOnlyPersonal() {
- return onlyPersonal;
- }
-
public boolean isWithAnalyses() {
return withAnalyses;
}
@@ -82,10 +62,6 @@ public class OrganizationQuery {
return analyzedAfter;
}
- public boolean isWithoutProjects() {
- return withoutProjects;
- }
-
public static OrganizationQuery returnAll() {
return NO_FILTER;
}
@@ -98,10 +74,7 @@ public class OrganizationQuery {
private Set<String> keys;
@Nullable
private Integer member;
- private boolean onlyTeam = false;
- private boolean onlyPersonal = false;
private boolean withAnalyses = false;
- private boolean withoutProjects = false;
@Nullable
private Long analyzedAfter;
@@ -123,16 +96,6 @@ public class OrganizationQuery {
return this;
}
- public Builder setOnlyTeam() {
- this.onlyTeam = true;
- return this;
- }
-
- public Builder setOnlyPersonal() {
- this.onlyPersonal = true;
- return this;
- }
-
public Builder setWithAnalyses() {
this.withAnalyses = true;
return this;
@@ -143,11 +106,6 @@ public class OrganizationQuery {
return this;
}
- public Builder setWithoutProjects() {
- this.withoutProjects = true;
- return this;
- }
-
public OrganizationQuery build() {
return new OrganizationQuery(this);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
index 7fe0e24e73d..744249a2ce6 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
@@ -135,6 +135,10 @@ public class UserDao implements Dao {
mapper(dbSession).deactivateUser(user.getLogin(), system2.now());
}
+ public void deactivateSonarCloudUser(DbSession dbSession, UserDto user) {
+ mapper(dbSession).deactivateSonarCloudUser(user.getLogin(), system2.now());
+ }
+
public void cleanHomepage(DbSession dbSession, OrganizationDto organization) {
mapper(dbSession).clearHomepages("ORGANIZATION", organization.getUuid(), system2.now());
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java
index 2110735f660..c8a414f934a 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.java
@@ -55,7 +55,6 @@ public class UserDto {
private boolean local = true;
private boolean root = false;
private boolean onboarded = false;
- private String organizationUuid;
/**
* Date of the last time the user has accessed to the server.
@@ -273,16 +272,6 @@ public class UserDto {
}
@CheckForNull
- public String getOrganizationUuid() {
- return organizationUuid;
- }
-
- public UserDto setOrganizationUuid(@Nullable String organizationUuid) {
- this.organizationUuid = organizationUuid;
- return this;
- }
-
- @CheckForNull
public Long getLastConnectionDate() {
return lastConnectionDate;
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java
index 8f1a77c7b86..8c83ba012c3 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java
@@ -82,6 +82,8 @@ public interface UserMapper {
void deactivateUser(@Param("login") String login, @Param("now") long now);
+ void deactivateSonarCloudUser(@Param("login") String login, @Param("now") long now);
+
void clearHomepages(@Param("homepageType") String type, @Param("homepageParameter") String value, @Param("now") long now);
void clearHomepage(@Param("login") String login, @Param("now") long now);
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
index a806a01d78a..b23b1b46960 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
@@ -10,7 +10,6 @@
org.default_quality_gate_uuid as "defaultQualityGateUuid",
org.url as "url",
org.avatar_url as "avatarUrl",
- org.guarded as "guarded",
org.subscription as "subscription",
org.created_at as "createdAt",
org.updated_at as "updatedAt"
@@ -121,22 +120,6 @@
#{key, jdbcType=VARCHAR}
</foreach>
</if>
- <if test="query.onlyTeam">
- and not exists(
- select 1
- from users u
- where u.organization_uuid = org.uuid
- and u.active = ${_true}
- )
- </if>
- <if test="query.onlyPersonal">
- and exists(
- select 1
- from users u
- where u.organization_uuid = org.uuid
- and u.active = ${_true}
- )
- </if>
<if test="query.withAnalyses">
and exists(
select 1
@@ -147,14 +130,6 @@
and s.islast = ${_true}
)
</if>
- <if test="query.withoutProjects">
- and not exists(
- select 1
- from projects p
- where p.organization_uuid = org.uuid
- and p.enabled = ${_true}
- )
- </if>
<if test="query.analyzedAfter != null">
and exists(
select 1
@@ -246,7 +221,6 @@
description,
url,
avatar_url,
- guarded,
new_project_private,
default_quality_gate_uuid,
subscription,
@@ -261,7 +235,6 @@
#{organization.description, jdbcType=VARCHAR},
#{organization.url, jdbcType=VARCHAR},
#{organization.avatarUrl, jdbcType=VARCHAR},
- #{organization.guarded, jdbcType=BOOLEAN},
#{newProjectPrivate, jdbcType=BOOLEAN},
#{organization.defaultQualityGateUuid, jdbcType=VARCHAR},
#{organization.subscription, jdbcType=VARCHAR},
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml
index bf0ee3a5d81..d6c6c9b059f 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml
@@ -22,7 +22,6 @@
u.onboarded as "onboarded",
u.homepage_type as "homepageType",
u.homepage_parameter as "homepageParameter",
- u.organization_uuid as organizationUuid,
u.last_connection_date as "lastConnectionDate",
u.created_at as "createdAt",
u.updated_at as "updatedAt"
@@ -173,8 +172,7 @@
and u.login &lt;&gt; #{login}
</select>
- <update id="deactivateUser" parameterType="map">
- update users set
+ <sql id="deactivateUserUpdatedFields">
active = ${_false},
email = null,
scm_accounts = null,
@@ -182,6 +180,19 @@
crypted_password = null,
last_connection_date = null,
updated_at = #{now, jdbcType=BIGINT}
+ </sql>
+
+ <update id="deactivateUser" parameterType="map">
+ update users set
+ <include refid="deactivateUserUpdatedFields"/>
+ where
+ login = #{login, jdbcType=VARCHAR}
+ </update>
+
+ <update id="deactivateSonarCloudUser" parameterType="map">
+ update users set
+ name = null,
+ <include refid="deactivateUserUpdatedFields"/>
where
login = #{login, jdbcType=VARCHAR}
</update>
@@ -233,7 +244,6 @@
onboarded,
homepage_type,
homepage_parameter,
- organization_uuid,
created_at,
updated_at
) values (
@@ -254,7 +264,6 @@
#{user.onboarded,jdbcType=BOOLEAN},
#{user.homepageType,jdbcType=VARCHAR},
#{user.homepageParameter,jdbcType=VARCHAR},
- #{user.organizationUuid,jdbcType=VARCHAR},
#{user.createdAt,jdbcType=BIGINT},
#{user.updatedAt,jdbcType=BIGINT}
)
@@ -277,7 +286,6 @@
hash_method = #{user.hashMethod, jdbcType=VARCHAR},
homepage_type = #{user.homepageType, jdbcType=VARCHAR},
homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR},
- organization_uuid = #{user.organizationUuid, jdbcType=VARCHAR},
last_connection_date = #{user.lastConnectionDate,jdbcType=BIGINT},
updated_at = #{user.updatedAt,jdbcType=BIGINT}
where
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
index ef389bc5223..debde182ede 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
@@ -50,8 +50,6 @@ import org.sonar.db.Pagination;
import org.sonar.db.alm.ALM;
import org.sonar.db.alm.AlmAppInstallDto;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.dialect.Dialect;
-import org.sonar.db.dialect.Oracle;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.qualitygate.QGateWithOrgDto;
import org.sonar.db.user.GroupDto;
@@ -86,7 +84,6 @@ public class OrganizationDaoTest {
.setDescription("the description 1")
.setUrl("the url 1")
.setAvatarUrl("the avatar url 1")
- .setGuarded(false)
.setSubscription(FREE)
.setDefaultQualityGateUuid("1");
private static final OrganizationDto ORGANIZATION_DTO_2 = new OrganizationDto()
@@ -96,7 +93,6 @@ public class OrganizationDaoTest {
.setDescription("the description 2")
.setUrl("the url 2")
.setAvatarUrl("the avatar url 2")
- .setGuarded(true)
.setSubscription(FREE)
.setDefaultQualityGateUuid("1");
private static final String PERMISSION_1 = "foo";
@@ -148,7 +144,6 @@ public class OrganizationDaoTest {
assertThat(row.get("avatarUrl")).isEqualTo(organization.getAvatarUrl());
assertThat(row.get("createdAt")).isEqualTo(organization.getCreatedAt());
assertThat(row.get("updatedAt")).isEqualTo(organization.getUpdatedAt());
- assertThat(row.get("guarded")).isEqualTo(toBool(organization.isGuarded()));
assertThat(row.get("subscription")).isEqualTo(organization.getSubscription().name());
assertThat(row.get("defaultTemplate")).isNull();
assertThat(row.get("projectDefaultTemplate")).isNull();
@@ -156,14 +151,6 @@ public class OrganizationDaoTest {
}
@Test
- public void insert_persists_boolean_property_guarded_of_OrganizationDto() {
- insertOrganization(ORGANIZATION_DTO_2);
-
- Map<String, Object> row = selectSingleRow();
- assertThat(row.get("guarded")).isEqualTo(toBool(ORGANIZATION_DTO_2.isGuarded()));
- }
-
- @Test
public void description_url_avatarUrl_and_userId_are_optional() {
when(system2.now()).thenReturn(SOME_DATE);
insertOrganization(copyOf(ORGANIZATION_DTO_1).setDescription(null).setUrl(null).setAvatarUrl(null));
@@ -175,7 +162,6 @@ public class OrganizationDaoTest {
assertThat(row.get("description")).isNull();
assertThat(row.get("url")).isNull();
assertThat(row.get("avatarUrl")).isNull();
- assertThat(row.get("guarded")).isEqualTo(toBool(ORGANIZATION_DTO_1.isGuarded()));
assertThat(row.get("userId")).isNull();
assertThat(row.get("createdAt")).isEqualTo(SOME_DATE);
assertThat(row.get("updatedAt")).isEqualTo(SOME_DATE);
@@ -184,14 +170,6 @@ public class OrganizationDaoTest {
assertThat(row.get("viewDefaultTemplate")).isNull();
}
- private Object toBool(boolean guarded) {
- Dialect dialect = db.database().getDialect();
- if (dialect.getId().equals(Oracle.ID)) {
- return guarded ? 1L : 0L;
- }
- return guarded;
- }
-
@Test
public void insert_fails_if_row_with_uuid_already_exists() {
insertOrganization(ORGANIZATION_DTO_1);
@@ -585,20 +563,6 @@ public class OrganizationDaoTest {
}
@Test
- public void selectByQuery_filter_on_type() {
- OrganizationDto personalOrg1 = db.organizations().insert();
- db.users().insertUser(u -> u.setOrganizationUuid(personalOrg1.getUuid()));
- OrganizationDto personalOrg2 = db.organizations().insert();
- db.users().insertUser(u -> u.setOrganizationUuid(personalOrg2.getUuid()));
- OrganizationDto teamOrg1 = db.organizations().insert();
-
- assertThat(selectUuidsByQuery(q -> q.setOnlyPersonal(), forPage(1).andSize(100)))
- .containsExactlyInAnyOrder(personalOrg1.getUuid(), personalOrg2.getUuid());
- assertThat(selectUuidsByQuery(q -> q.setOnlyTeam(), forPage(1).andSize(100)))
- .containsExactlyInAnyOrder(teamOrg1.getUuid());
- }
-
- @Test
public void selectByQuery_filter_on_withAnalyses() {
assertThat(selectUuidsByQuery(q -> q.setWithAnalyses(), forPage(1).andSize(100)))
.isEmpty();
@@ -630,25 +594,6 @@ public class OrganizationDaoTest {
}
@Test
- public void selectByQuery_filter_on_withoutProjects() {
- assertThat(selectUuidsByQuery(q -> q.setWithoutProjects(), forPage(1).andSize(100)))
- .isEmpty();
-
- // has projects
- OrganizationDto orgWithProjects = db.organizations().insert();
- db.components().insertPrivateProject(orgWithProjects);
- db.components().insertPrivateProject(orgWithProjects, p -> p.setEnabled(false));
- // has no projects
- OrganizationDto orgWithoutProjects = db.organizations().insert();
- // has only disabled projects
- OrganizationDto orgWithOnlyDisabledProjects = db.organizations().insert();
- db.components().insertPrivateProject(orgWithOnlyDisabledProjects, p -> p.setEnabled(false));
-
- assertThat(selectUuidsByQuery(q -> q.setWithoutProjects(), forPage(1).andSize(100)))
- .containsExactlyInAnyOrder(orgWithoutProjects.getUuid(), orgWithOnlyDisabledProjects.getUuid());
- }
-
- @Test
public void getDefaultTemplates_returns_empty_when_table_is_empty() {
assertThat(underTest.getDefaultTemplates(dbSession, ORGANIZATION_DTO_1.getUuid())).isEmpty();
}
@@ -1155,7 +1100,6 @@ public class OrganizationDaoTest {
" default_perm_template_app," +
" default_perm_template_port," +
" new_project_private," +
- " guarded," +
" default_quality_gate_uuid," +
" subscription," +
" created_at," +
@@ -1173,7 +1117,6 @@ public class OrganizationDaoTest {
" ?," +
" ?," +
" ?," +
- " ?," +
" ?" +
" )")) {
preparedStatement.setString(1, organizationUuid);
@@ -1183,11 +1126,10 @@ public class OrganizationDaoTest {
preparedStatement.setString(5, view);
preparedStatement.setString(6, view);
preparedStatement.setBoolean(7, false);
- preparedStatement.setBoolean(8, false);
- preparedStatement.setString(9, "1");
- preparedStatement.setString(10, FREE.name());
- preparedStatement.setLong(11, 1000L);
- preparedStatement.setLong(12, 2000L);
+ preparedStatement.setString(8, "1");
+ preparedStatement.setString(9, FREE.name());
+ preparedStatement.setLong(10, 1000L);
+ preparedStatement.setLong(11, 2000L);
preparedStatement.execute();
} catch (SQLException e) {
throw new RuntimeException("dirty insert failed", e);
@@ -1210,7 +1152,6 @@ public class OrganizationDaoTest {
assertThat(dto.getName()).isEqualTo(ORGANIZATION_DTO_1.getName());
assertThat(dto.getDescription()).isEqualTo(ORGANIZATION_DTO_1.getDescription());
assertThat(dto.getUrl()).isEqualTo(ORGANIZATION_DTO_1.getUrl());
- assertThat(dto.isGuarded()).isEqualTo(ORGANIZATION_DTO_1.isGuarded());
assertThat(dto.getAvatarUrl()).isEqualTo(ORGANIZATION_DTO_1.getAvatarUrl());
assertThat(dto.getCreatedAt()).isEqualTo(ORGANIZATION_DTO_1.getCreatedAt());
assertThat(dto.getUpdatedAt()).isEqualTo(ORGANIZATION_DTO_1.getUpdatedAt());
@@ -1222,7 +1163,6 @@ public class OrganizationDaoTest {
assertThat(dto.getName()).isEqualTo(expected.getName());
assertThat(dto.getDescription()).isEqualTo(expected.getDescription());
assertThat(dto.getUrl()).isEqualTo(expected.getUrl());
- assertThat(dto.isGuarded()).isEqualTo(expected.isGuarded());
assertThat(dto.getAvatarUrl()).isEqualTo(expected.getAvatarUrl());
assertThat(dto.getSubscription()).isEqualTo(expected.getSubscription());
assertThat(dto.getCreatedAt()).isEqualTo(expected.getCreatedAt());
@@ -1232,7 +1172,6 @@ public class OrganizationDaoTest {
private Map<String, Object> selectSingleRow() {
List<Map<String, Object>> rows = db.select("select" +
" uuid as \"uuid\", kee as \"key\", name as \"name\", description as \"description\", url as \"url\", avatar_url as \"avatarUrl\"," +
- " guarded as \"guarded\"," +
" subscription as \"subscription\"," +
" created_at as \"createdAt\", updated_at as \"updatedAt\"," +
" default_perm_template_project as \"projectDefaultPermTemplate\"," +
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationHelperTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationHelperTest.java
new file mode 100644
index 00000000000..bc5d738366c
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationHelperTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.db.organization;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.List;
+import java.util.Random;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.UserDto;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
+
+@RunWith(DataProviderRunner.class)
+public class OrganizationHelperTest {
+
+ private static final Random RANDOM = new Random();
+
+ @Rule
+ public DbTester db = DbTester.create(mock(System2.class)).setDisableDefaultOrganization(true);
+ public DbSession dbSession = db.getSession();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private final OrganizationHelper underTest = new OrganizationHelper(db.getDbClient());
+
+ @Test
+ public void returns_empty_list_when_user_is_not_admin_of_any_orgs() {
+ UserDto user1 = db.users().insertUser();
+
+ OrganizationDto org1 = db.organizations().insert();
+ GroupDto group1 = db.users().insertGroup(org1);
+ db.users().insertMember(group1, user1);
+
+ assertThat(underTest.selectOrganizationsWithLastAdmin(dbSession, user1.getId())).isEmpty();
+ }
+
+ @Test
+ public void returns_orgs_where_user_is_last_admin() {
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+
+ OrganizationDto org1 = db.organizations().insert();
+ OrganizationDto org2 = db.organizations().insert();
+
+ setAsDirectOrIndirectAdmin(user1, org1);
+ setAsDirectOrIndirectAdmin(user2, org1);
+ setAsDirectOrIndirectAdmin(user1, org2);
+
+ assertThat(underTest.selectOrganizationsWithLastAdmin(dbSession, user1.getId()))
+ .extracting(OrganizationDto::getKey)
+ .containsExactly(org2.getKey());
+ }
+
+ @Test
+ @UseDataProvider("adminUserCombinationsAndExpectedOrgKeys")
+ public void returns_correct_orgs_for_interesting_combinations_of_last_admin_or_not(
+ boolean user2IsAdminOfOrg1, boolean user1IsAdminOfOrg2, boolean user2IsAdminOfOrg2, List<String> expectedOrgKeys) {
+ UserDto user1 = db.users().insertUser();
+ UserDto user2 = db.users().insertUser();
+
+ OrganizationDto org1 = db.organizations().insert(o -> o.setKey("org1"));
+ OrganizationDto org2 = db.organizations().insert(o -> o.setKey("org2"));
+
+ setAsDirectOrIndirectAdmin(user1, org1);
+ if (user2IsAdminOfOrg1) {
+ setAsDirectOrIndirectAdmin(user2, org1);
+ }
+ if (user1IsAdminOfOrg2) {
+ setAsDirectOrIndirectAdmin(user1, org2);
+ }
+ if (user2IsAdminOfOrg2) {
+ setAsDirectOrIndirectAdmin(user2, org2);
+ }
+
+ assertThat(underTest.selectOrganizationsWithLastAdmin(dbSession, user1.getId()))
+ .extracting(OrganizationDto::getKey)
+ .containsExactlyInAnyOrderElementsOf(expectedOrgKeys);
+ }
+
+ @DataProvider
+ public static Object[][] adminUserCombinationsAndExpectedOrgKeys() {
+ return new Object[][] {
+ // note: user1 is always admin of org1
+ // param 1: user2 is admin of org1
+ // param 2: user1 is admin of org2
+ // param 3: user2 is admin of org2
+ // param 4: list of orgs preventing user1 to delete
+ {true, true, true, emptyList()},
+ {true, true, false, singletonList("org2")},
+ {true, false, true, emptyList()},
+ {true, false, false, emptyList()},
+ {false, true, true, singletonList("org1")},
+ {false, true, false, asList("org1", "org2")},
+ {false, false, true, singletonList("org1")},
+ {false, false, false, singletonList("org1")},
+ };
+ }
+
+ private void setAsDirectOrIndirectAdmin(UserDto user, OrganizationDto organization) {
+ boolean useDirectAdmin = RANDOM.nextBoolean();
+ if (useDirectAdmin) {
+ db.users().insertPermissionOnUser(organization, user, ADMINISTER);
+ } else {
+ GroupDto group = db.users().insertGroup(organization);
+ db.users().insertPermissionOnGroup(group, ADMINISTER);
+ db.users().insertMember(group, user);
+ }
+ }
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationQueryTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationQueryTest.java
deleted file mode 100644
index 74f60141463..00000000000
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationQueryTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.db.organization;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class OrganizationQueryTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void throws_IAE_when_both_onlyPersonal_and_onlyTeam_are_set() {
- expectedException.expect(IllegalArgumentException.class);
- OrganizationQuery.newOrganizationQueryBuilder()
- .setOnlyPersonal()
- .setOnlyTeam()
- .build();
- }
-
- @Test
- public void throws_IAE_when_withoutProjects_is_used_together_with_withAnalyses() {
- expectedException.expect(IllegalArgumentException.class);
- OrganizationQuery.newOrganizationQueryBuilder()
- .setWithoutProjects()
- .setWithAnalyses()
- .build();
- }
-
- @Test
- public void throws_IAE_when_withoutProjects_is_used_together_with_analyzedAfter() {
- expectedException.expect(IllegalArgumentException.class);
- OrganizationQuery.newOrganizationQueryBuilder()
- .setWithoutProjects()
- .setAnalyzedAfter(1)
- .build();
- }
-
- @Test
- public void throws_IAE_when_withoutProjects_is_used_together_with_both_withAnalyses_and_analyzedAfter() {
- expectedException.expect(IllegalArgumentException.class);
- OrganizationQuery.newOrganizationQueryBuilder()
- .setWithoutProjects()
- .setWithAnalyses()
- .setAnalyzedAfter(1)
- .build();
- }
-}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
index e739b57e69a..1f02bd04a34 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
@@ -19,12 +19,15 @@
*/
package org.sonar.db.user;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.sonar.api.user.UserQuery;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.impl.utils.TestSystem2;
@@ -44,6 +47,7 @@ import static org.assertj.core.groups.Tuple.tuple;
import static org.sonar.db.user.GroupTesting.newGroupDto;
import static org.sonar.db.user.UserTesting.newUserDto;
+@RunWith(DataProviderRunner.class)
public class UserDaoTest {
private static final long NOW = 1_500_000_000_000L;
@@ -336,7 +340,6 @@ public class UserDaoTest {
.setLocal(true)
.setHomepageType("project")
.setHomepageParameter("OB1")
- .setOrganizationUuid("ORG_UUID")
.setCreatedAt(date)
.setUpdatedAt(date);
underTest.insert(db.getSession(), userDto);
@@ -361,7 +364,6 @@ public class UserDaoTest {
assertThat(user.isRoot()).isFalse();
assertThat(user.getHomepageType()).isEqualTo("project");
assertThat(user.getHomepageParameter()).isEqualTo("OB1");
- assertThat(user.getOrganizationUuid()).isEqualTo("ORG_UUID");
}
@Test
@@ -383,8 +385,7 @@ public class UserDaoTest {
.setEmail("jo@hn.com")
.setActive(true)
.setLocal(true)
- .setOnboarded(false)
- .setOrganizationUuid("OLD_ORG_UUID"));
+ .setOnboarded(false));
underTest.update(db.getSession(), newUserDto()
.setUuid(user.getUuid())
@@ -403,7 +404,6 @@ public class UserDaoTest {
.setLocal(false)
.setHomepageType("project")
.setHomepageParameter("OB1")
- .setOrganizationUuid("ORG_UUID")
.setLastConnectionDate(10_000_000_000L));
UserDto reloaded = underTest.selectByUuid(db.getSession(), user.getUuid());
@@ -425,7 +425,6 @@ public class UserDaoTest {
assertThat(reloaded.isRoot()).isFalse();
assertThat(reloaded.getHomepageType()).isEqualTo("project");
assertThat(reloaded.getHomepageParameter()).isEqualTo("OB1");
- assertThat(reloaded.getOrganizationUuid()).isEqualTo("ORG_UUID");
assertThat(reloaded.getLastConnectionDate()).isEqualTo(10_000_000_000L);
}
@@ -441,10 +440,40 @@ public class UserDaoTest {
UserDto userReloaded = underTest.selectUserById(session, user.getId());
assertThat(userReloaded.isActive()).isFalse();
- assertThat(userReloaded.getLogin()).isNotNull();
- assertThat(userReloaded.getExternalId()).isNotNull();
- assertThat(userReloaded.getExternalLogin()).isNotNull();
- assertThat(userReloaded.getExternalIdentityProvider()).isNotNull();
+ assertThat(userReloaded.getName()).isEqualTo(user.getName());
+ assertThat(userReloaded.getLogin()).isEqualTo(user.getLogin());
+ assertThat(userReloaded.getExternalId()).isEqualTo(user.getExternalId());
+ assertThat(userReloaded.getExternalLogin()).isEqualTo(user.getExternalLogin());
+ assertThat(userReloaded.getExternalIdentityProvider()).isEqualTo(user.getExternalIdentityProvider());
+ assertThat(userReloaded.getEmail()).isNull();
+ assertThat(userReloaded.getScmAccounts()).isNull();
+ assertThat(userReloaded.getSalt()).isNull();
+ assertThat(userReloaded.getCryptedPassword()).isNull();
+ assertThat(userReloaded.isRoot()).isFalse();
+ assertThat(userReloaded.getUpdatedAt()).isEqualTo(NOW);
+ assertThat(userReloaded.getHomepageType()).isNull();
+ assertThat(userReloaded.getHomepageParameter()).isNull();
+ assertThat(userReloaded.getLastConnectionDate()).isNull();
+ assertThat(underTest.selectUserById(session, otherUser.getId())).isNotNull();
+ }
+
+ @Test
+ public void deactivate_sonarcloud_user() {
+ UserDto user = insertActiveUser();
+ insertUserGroup(user);
+ UserDto otherUser = insertActiveUser();
+ underTest.update(db.getSession(), user.setLastConnectionDate(10_000_000_000L));
+ session.commit();
+
+ underTest.deactivateSonarCloudUser(session, user);
+
+ UserDto userReloaded = underTest.selectUserById(session, user.getId());
+ assertThat(userReloaded.isActive()).isFalse();
+ assertThat(userReloaded.getName()).isNull();
+ assertThat(userReloaded.getLogin()).isEqualTo(user.getLogin());
+ assertThat(userReloaded.getExternalId()).isEqualTo(user.getExternalId());
+ assertThat(userReloaded.getExternalLogin()).isEqualTo(user.getExternalLogin());
+ assertThat(userReloaded.getExternalIdentityProvider()).isEqualTo(user.getExternalIdentityProvider());
assertThat(userReloaded.getEmail()).isNull();
assertThat(userReloaded.getScmAccounts()).isNull();
assertThat(userReloaded.getSalt()).isNull();