]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10426 Add homepage default when db is inconsistent
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>
Thu, 22 Feb 2018 10:00:45 +0000 (11:00 +0100)
committerStas Vilchik <stas.vilchik@sonarsource.com>
Fri, 2 Mar 2018 12:17:32 +0000 (13:17 +0100)
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/CurrentAction.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/HomepageTypes.java
server/sonar-server/src/main/java/org/sonar/server/user/ws/HomepageTypesImpl.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/CurrentActionTest.java
server/sonar-server/src/test/java/org/sonar/server/user/ws/SetHomepageActionTest.java

index c063482fc98bb38e4c0f344fa2218365463ca428..e58945b21aa39a1d2f2b9cdb8c0e00d7d8dcced9 100644 (file)
@@ -124,11 +124,15 @@ public class UserDao implements Dao {
   }
 
   public void cleanHomepage(DbSession dbSession, OrganizationDto organization) {
-    mapper(dbSession).clearHomepage("ORGANIZATION", organization.getUuid(), system2.now());
+    mapper(dbSession).clearHomepages("ORGANIZATION", organization.getUuid(), system2.now());
   }
 
   public void cleanHomepage(DbSession dbSession, ComponentDto project) {
-    mapper(dbSession).clearHomepage("PROJECT", project.uuid(), system2.now());
+    mapper(dbSession).clearHomepages("PROJECT", project.uuid(), system2.now());
+  }
+
+  public void cleanHomepage(DbSession dbSession, UserDto user) {
+    mapper(dbSession).clearHomepage(user.getLogin(), system2.now());
   }
 
   @CheckForNull
index 5d816dab951d9957e6452fb8f6f08f2d5ff89082..fa80aba9ac8584499669b8de13f76cc02c44bb03 100644 (file)
@@ -70,5 +70,7 @@ public interface UserMapper {
 
   void deactivateUser(@Param("login") String login, @Param("now") long now);
 
-  void clearHomepage(@Param("homepageType") String type, @Param("homepageParameter") String value, @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);
 }
index d7c568696e5eb4d4bdc252df0b60db0004ffd6ba..9b6f5c9f5eeb6cc0b81aaac5de5c26c67adcbb99 100644 (file)
 
 <mapper namespace="org.sonar.db.user.UserMapper">
 
-  <sql id="userColumns">
-    u.id as id,
-    u.login as login,
-    u.name as name,
-    u.email as email,
-    u.active as "active",
-    u.scm_accounts as "scmAccounts",
-    u.salt as "salt",
-    u.crypted_password as "cryptedPassword",
-    u.external_identity as "externalIdentity",
-    u.external_identity_provider as "externalIdentityProvider",
-    u.user_local as "local",
-    u.is_root as "root",
-    u.onboarded as "onboarded",
-    u.created_at as "createdAt",
-    u.updated_at as "updatedAt",
-    u.homepage_type as "homepageType",
-    u.homepage_parameter as "homepageParameter"
-  </sql>
-
-  <select id="selectByLogin" parameterType="String" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE u.login=#{login}
-  </select>
-
-  <select id="selectNullableByScmAccountOrLoginOrEmail" parameterType="map" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE
-    u.login=#{scmAccount}
-    OR u.email=#{scmAccount}
-    OR u.scm_accounts like #{likeScmAccount}
-  </select>
-
-  <select id="selectUser" parameterType="int" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE u.id=#{id}
-  </select>
-
-  <select id="selectUserByLogin" parameterType="string" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE u.login=#{id} AND u.active=${_true}
-  </select>
-
-  <select id="selectByLogins" parameterType="string" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE u.login in
-    <foreach collection="list" open="(" close=")" item="login" separator=",">
-      #{login}
-    </foreach>
-  </select>
-
-  <select id="scrollAll" resultType="User" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
-    select <include refid="userColumns"/>
-    from users u
-  </select>
-
-  <select id="selectByIds" parameterType="string" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE u.id in
-    <foreach collection="ids" open="(" close=")" item="id" separator=",">
-      #{id}
-    </foreach>
-  </select>
-
-  <select id="selectUsers" parameterType="map" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    <where>
-      <if test="logins != null and logins.size() > 0">
-        u.login IN
-        <foreach item="login" index="index" collection="logins" open="(" separator="," close=")">
-          #{login}
+    <sql id="userColumns">
+        u.id as id,
+        u.login as login,
+        u.name as name,
+        u.email as email,
+        u.active as "active",
+        u.scm_accounts as "scmAccounts",
+        u.salt as "salt",
+        u.crypted_password as "cryptedPassword",
+        u.external_identity as "externalIdentity",
+        u.external_identity_provider as "externalIdentityProvider",
+        u.user_local as "local",
+        u.is_root as "root",
+        u.onboarded as "onboarded",
+        u.created_at as "createdAt",
+        u.updated_at as "updatedAt",
+        u.homepage_type as "homepageType",
+        u.homepage_parameter as "homepageParameter"
+    </sql>
+
+    <select id="selectByLogin" parameterType="String" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.login=#{login}
+    </select>
+
+    <select id="selectNullableByScmAccountOrLoginOrEmail" parameterType="map" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE
+        u.login=#{scmAccount}
+        OR u.email=#{scmAccount}
+        OR u.scm_accounts like #{likeScmAccount}
+    </select>
+
+    <select id="selectUser" parameterType="int" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.id=#{id}
+    </select>
+
+    <select id="selectUserByLogin" parameterType="string" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.login=#{id} AND u.active=${_true}
+    </select>
+
+    <select id="selectByLogins" parameterType="string" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.login in
+        <foreach collection="list" open="(" close=")" item="login" separator=",">
+            #{login}
         </foreach>
-      </if>
-      <if test="includeDeactivated==false">
+    </select>
+
+    <select id="scrollAll" resultType="User" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
+        select
+        <include refid="userColumns"/>
+        from users u
+    </select>
+
+    <select id="selectByIds" parameterType="string" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.id in
+        <foreach collection="ids" open="(" close=")" item="id" separator=",">
+            #{id}
+        </foreach>
+    </select>
+
+    <select id="selectUsers" parameterType="map" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        <where>
+            <if test="logins != null and logins.size() > 0">
+                u.login IN
+                <foreach item="login" index="index" collection="logins" open="(" separator="," close=")">
+                    #{login}
+                </foreach>
+            </if>
+            <if test="includeDeactivated==false">
+                AND u.active=${_true}
+            </if>
+            <if test="searchText != null">
+                AND (u.login LIKE #{searchTextSql} ESCAPE '/' OR u.name LIKE #{searchTextSql} ESCAPE '/')
+            </if>
+            <if test="mustBeRoot != null and mustBeRoot==true">
+                AND u.is_root = ${_true}
+            </if>
+            <if test="mustBeRoot != null and mustBeRoot==false">
+                AND u.is_root = ${_false}
+            </if>
+        </where>
+        ORDER BY u.name
+    </select>
+
+    <select id="selectByEmail" parameterType="String" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE lower(u.email)=#{email, jdbcType=VARCHAR}
         AND u.active=${_true}
-      </if>
-      <if test="searchText != null">
-        AND (u.login LIKE #{searchTextSql} ESCAPE '/' OR u.name LIKE #{searchTextSql} ESCAPE '/')
-      </if>
-      <if test="mustBeRoot != null and mustBeRoot==true">
-        AND u.is_root = ${_true}
-      </if>
-      <if test="mustBeRoot != null and mustBeRoot==false">
-        AND u.is_root = ${_false}
-      </if>
-    </where>
-    ORDER BY u.name
-  </select>
-
-  <select id="selectByEmail" parameterType="String" resultType="User">
-    SELECT
-    <include refid="userColumns"/>
-    FROM users u
-    WHERE lower(u.email)=#{email, jdbcType=VARCHAR}
-    AND u.active=${_true}
-  </select>
-
-  <select id="countRootUsersButLogin" parameterType="String" resultType="long">
-    select
-      count(1)
-    from
-      users u
-    where
-      u.active = ${_true}
-      and u.is_root = ${_true}
-      and u.login &lt;&gt; #{login}
-  </select>
-
-  <update id="deactivateUser" parameterType="map">
-    update users set
-      active = ${_false},
-      email = null,
-      scm_accounts = null,
-      external_identity = null,
-      external_identity_provider = null,
-      salt = null,
-      crypted_password = null,
-      updated_at = #{now, jdbcType=BIGINT}
-    where
-      login = #{login, jdbcType=VARCHAR}
-  </update>
-
-  <update id="clearHomepage" parameterType="map">
-    update users set
-      homepage_type = null,
-      homepage_parameter = null,
-      updated_at = #{now, jdbcType=BIGINT}
-    where
-      homepage_type = #{homepageType, jdbcType=VARCHAR}
-      and homepage_parameter = #{homepageParameter, jdbcType=VARCHAR}
-  </update>
-
-  <update id="setRoot">
-    update users set
-      is_root = #{root, jdbcType=BOOLEAN},
-      updated_at = #{now, jdbcType=BIGINT}
-    where
-      login = #{login, jdbcType=VARCHAR}
-      and active = ${_true}
-  </update>
-
-  <insert id="insert" parameterType="map" keyColumn="id" useGeneratedKeys="true" keyProperty="user.id">
-    insert into users (
-      login,
-      name,
-      email,
-      active,
-      scm_accounts,
-      external_identity,
-      external_identity_provider,
-      user_local,
-      salt,
-      crypted_password,
-      is_root,
-      onboarded,
-      created_at,
-      updated_at,
-      homepage_type,
-      homepage_parameter
-    ) values (
-      #{user.login,jdbcType=VARCHAR},
-      #{user.name,jdbcType=VARCHAR},
-      #{user.email,jdbcType=VARCHAR},
-      #{user.active,jdbcType=BOOLEAN},
-      #{user.scmAccounts,jdbcType=VARCHAR},
-      #{user.externalIdentity,jdbcType=VARCHAR},
-      #{user.externalIdentityProvider,jdbcType=VARCHAR},
-      #{user.local,jdbcType=BOOLEAN},
-      #{user.salt,jdbcType=VARCHAR},
-      #{user.cryptedPassword,jdbcType=VARCHAR},
-      #{user.root,jdbcType=BOOLEAN},
-      #{user.onboarded,jdbcType=BOOLEAN},
-      #{now,jdbcType=BIGINT},
-      #{now,jdbcType=BIGINT},
-      #{user.homepageType,jdbcType=VARCHAR},
-      #{user.homepageParameter,jdbcType=VARCHAR}
-    )
-  </insert>
-
-  <update id="update" parameterType="map">
-    update users set
-      name = #{user.name, jdbcType=VARCHAR},
-      email = #{user.email, jdbcType=VARCHAR},
-      active = #{user.active, jdbcType=BOOLEAN},
-      scm_accounts = #{user.scmAccounts, jdbcType=VARCHAR},
-      external_identity = #{user.externalIdentity, jdbcType=VARCHAR},
-      external_identity_provider = #{user.externalIdentityProvider, jdbcType=VARCHAR},
-      user_local = #{user.local, jdbcType=BOOLEAN},
-      onboarded = #{user.onboarded, jdbcType=BOOLEAN},
-      salt = #{user.salt, jdbcType=VARCHAR},
-      crypted_password = #{user.cryptedPassword, jdbcType=BIGINT},
-      updated_at = #{now, jdbcType=BIGINT},
-      homepage_type = #{user.homepageType, jdbcType=VARCHAR},
-      homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR}
-    where
-      login = #{user.login, jdbcType=VARCHAR}
-  </update>
+    </select>
+
+    <select id="countRootUsersButLogin" parameterType="String" resultType="long">
+        select
+        count(1)
+        from
+        users u
+        where
+        u.active = ${_true}
+        and u.is_root = ${_true}
+        and u.login &lt;&gt; #{login}
+    </select>
+
+    <update id="deactivateUser" parameterType="map">
+        update users set
+        active = ${_false},
+        email = null,
+        scm_accounts = null,
+        external_identity = null,
+        external_identity_provider = null,
+        salt = null,
+        crypted_password = null,
+        updated_at = #{now, jdbcType=BIGINT}
+        where
+        login = #{login, jdbcType=VARCHAR}
+    </update>
+
+    <update id="clearHomepages" parameterType="map">
+        update users set
+        homepage_type = null,
+        homepage_parameter = null,
+        updated_at = #{now, jdbcType=BIGINT}
+        where
+        homepage_type = #{homepageType, jdbcType=VARCHAR}
+        and homepage_parameter = #{homepageParameter, jdbcType=VARCHAR}
+    </update>
+
+    <update id="clearHomepage" parameterType="map">
+        update users set
+        homepage_type = null,
+        homepage_parameter = null,
+        updated_at = #{now, jdbcType=BIGINT}
+        where
+        login = #{login, jdbcType=VARCHAR}
+    </update>
+
+    <update id="setRoot">
+        update users set
+        is_root = #{root, jdbcType=BOOLEAN},
+        updated_at = #{now, jdbcType=BIGINT}
+        where
+        login = #{login, jdbcType=VARCHAR}
+        and active = ${_true}
+    </update>
+
+    <insert id="insert" parameterType="map" keyColumn="id" useGeneratedKeys="true" keyProperty="user.id">
+        insert into users (
+        login,
+        name,
+        email,
+        active,
+        scm_accounts,
+        external_identity,
+        external_identity_provider,
+        user_local,
+        salt,
+        crypted_password,
+        is_root,
+        onboarded,
+        created_at,
+        updated_at,
+        homepage_type,
+        homepage_parameter
+        ) values (
+        #{user.login,jdbcType=VARCHAR},
+        #{user.name,jdbcType=VARCHAR},
+        #{user.email,jdbcType=VARCHAR},
+        #{user.active,jdbcType=BOOLEAN},
+        #{user.scmAccounts,jdbcType=VARCHAR},
+        #{user.externalIdentity,jdbcType=VARCHAR},
+        #{user.externalIdentityProvider,jdbcType=VARCHAR},
+        #{user.local,jdbcType=BOOLEAN},
+        #{user.salt,jdbcType=VARCHAR},
+        #{user.cryptedPassword,jdbcType=VARCHAR},
+        #{user.root,jdbcType=BOOLEAN},
+        #{user.onboarded,jdbcType=BOOLEAN},
+        #{now,jdbcType=BIGINT},
+        #{now,jdbcType=BIGINT},
+        #{user.homepageType,jdbcType=VARCHAR},
+        #{user.homepageParameter,jdbcType=VARCHAR}
+        )
+    </insert>
+
+    <update id="update" parameterType="map">
+        update users set
+        name = #{user.name, jdbcType=VARCHAR},
+        email = #{user.email, jdbcType=VARCHAR},
+        active = #{user.active, jdbcType=BOOLEAN},
+        scm_accounts = #{user.scmAccounts, jdbcType=VARCHAR},
+        external_identity = #{user.externalIdentity, jdbcType=VARCHAR},
+        external_identity_provider = #{user.externalIdentityProvider, jdbcType=VARCHAR},
+        user_local = #{user.local, jdbcType=BOOLEAN},
+        onboarded = #{user.onboarded, jdbcType=BOOLEAN},
+        salt = #{user.salt, jdbcType=VARCHAR},
+        crypted_password = #{user.cryptedPassword, jdbcType=BIGINT},
+        updated_at = #{now, jdbcType=BIGINT},
+        homepage_type = #{user.homepageType, jdbcType=VARCHAR},
+        homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR}
+        where
+        login = #{user.login, jdbcType=VARCHAR}
+    </update>
 
 </mapper>
index e4e219ec6654a74cc21a763e6e5248bd3159ebe6..1286768f703afcdb1fbbc9c4b4426779abc0c400 100644 (file)
@@ -466,6 +466,22 @@ public class UserDaoTest {
     assertThat(untouchedUserReloaded.getHomepageParameter()).isEqualTo(untouchedUser.getHomepageParameter());
   }
 
+  @Test
+  public void clean_user_homepage() {
+
+    UserDto user = newUserDto().setHomepageType("RANDOM").setHomepageParameter("any-string");
+    underTest.insert(session, user);
+    session.commit();
+
+    underTest.cleanHomepage(session,user);
+
+    UserDto reloaded = underTest.selectUserById(session, user.getId());
+    assertThat(reloaded.getUpdatedAt()).isEqualTo(NOW);
+    assertThat(reloaded.getHomepageType()).isNull();
+    assertThat(reloaded.getHomepageParameter()).isNull();
+
+  }
+
   @Test
   public void does_not_fail_to_deactivate_missing_user() {
     underTest.deactivateUser(session, UserTesting.newUserDto());
index 3b7ad430f56e37b7df898348ad7c4b86748386c1..2df9909bcee69ba0a2ae9bfa5078a596bf056e3a 100644 (file)
@@ -21,11 +21,12 @@ package org.sonar.server.user.ws;
 
 import java.util.Collection;
 import java.util.List;
-import javax.annotation.Nullable;
+import java.util.Optional;
 import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.core.platform.PluginRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
@@ -39,9 +40,12 @@ import org.sonarqube.ws.Users.CurrentWsResponse;
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Strings.emptyToNull;
-import static java.lang.String.format;
 import static java.util.Collections.singletonList;
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
+import static java.util.Optional.ofNullable;
 import static java.util.stream.Collectors.toList;
+import static org.apache.commons.lang.StringUtils.EMPTY;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.Users.CurrentWsResponse.Permissions;
@@ -54,20 +58,23 @@ import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CURRENT;
 
 public class CurrentAction implements UsersWsAction {
 
+  private static final String GOVERNANCE_PLUGIN_KEY = "governance";
+
   private final UserSession userSession;
   private final DbClient dbClient;
   private final DefaultOrganizationProvider defaultOrganizationProvider;
   private final AvatarResolver avatarResolver;
   private final HomepageTypes homepageTypes;
-  private static final String HOMEPAGE_PARAMETER_SHOULD_NOT_BE_NULL = "Homepage parameter should not be null";
+  private final PluginRepository pluginRepository;
 
   public CurrentAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider,
-    AvatarResolver avatarResolver, HomepageTypes homepageTypes) {
+    AvatarResolver avatarResolver, HomepageTypes homepageTypes, PluginRepository pluginRepository) {
     this.userSession = userSession;
     this.dbClient = dbClient;
     this.defaultOrganizationProvider = defaultOrganizationProvider;
     this.avatarResolver = avatarResolver;
     this.homepageTypes = homepageTypes;
+    this.pluginRepository = pluginRepository;
   }
 
   @Override
@@ -129,42 +136,74 @@ public class CurrentAction implements UsersWsAction {
   }
 
   private CurrentWsResponse.Homepage buildHomepage(DbSession dbSession, UserDto user) {
-    String homepageType = user.getHomepageType();
-    if (homepageType == null) {
+    if (noHomepageSet(user)) {
       return defaultHomepage();
     }
-    CurrentWsResponse.Homepage.Builder homepage = CurrentWsResponse.Homepage.newBuilder()
-      .setType(CurrentWsResponse.HomepageType.valueOf(homepageType));
-    setHomepageParameter(dbSession, homepageType, user.getHomepageParameter(), homepage);
-    return homepage.build();
+
+    return doBuildHomepage(dbSession, user).orElse(defaultHomepage());
+  }
+
+  private Optional<CurrentWsResponse.Homepage> doBuildHomepage(DbSession dbSession, UserDto user) {
+
+    if (PROJECT.toString().equals(user.getHomepageType())) {
+      return projectHomepage(dbSession, user);
+    }
+
+    if (APPLICATION.toString().equals(user.getHomepageType()) || PORTFOLIO.toString().equals(user.getHomepageType())) {
+      return applicationAndPortfolioHomepage(dbSession, user);
+    }
+
+    if (ORGANIZATION.toString().equals(user.getHomepageType())) {
+      return organizationHomepage(dbSession, user);
+    }
+
+    return of(CurrentWsResponse.Homepage.newBuilder()
+      .setType(CurrentWsResponse.HomepageType.valueOf(user.getHomepageType()))
+      .build());
   }
 
-  private void setHomepageParameter(DbSession dbSession, String homepageType, @Nullable String homepageParameter, CurrentWsResponse.Homepage.Builder homepage) {
-    if (PROJECT.toString().equals(homepageType)) {
-      checkState(homepageParameter != null, HOMEPAGE_PARAMETER_SHOULD_NOT_BE_NULL);
-      ComponentDto component = dbClient.componentDao().selectByUuid(dbSession, homepageParameter)
-        .or(() -> {
-          throw new IllegalStateException(format("Unknown component '%s' for homepageParameter", homepageParameter));
-        });
-      homepage.setComponent(component.getKey());
-      setNullable(component.getBranch(), homepage::setBranch);
-      return;
+  private Optional<CurrentWsResponse.Homepage> projectHomepage(DbSession dbSession, UserDto user) {
+    Optional<ComponentDto> projectOptional = ofNullable(dbClient.componentDao().selectByUuid(dbSession, of(user.getHomepageParameter()).orElse(EMPTY)).orNull());
+    if (!projectOptional.isPresent()) {
+      cleanUserHomepageInDb(dbSession, user);
+      return empty();
     }
-    if (APPLICATION.toString().equals(homepageType) || PORTFOLIO.toString().equals(homepageType)) {
-      checkState(homepageParameter != null, HOMEPAGE_PARAMETER_SHOULD_NOT_BE_NULL);
-      ComponentDto component = dbClient.componentDao().selectByUuid(dbSession, homepageParameter)
-        .or(() -> {
-          throw new IllegalStateException(format("Unknown component '%s' for homepageParameter", homepageParameter));
-        });
-      homepage.setComponent(component.getKey());
-      return;
+
+    CurrentWsResponse.Homepage.Builder homepage = CurrentWsResponse.Homepage.newBuilder()
+      .setType(CurrentWsResponse.HomepageType.valueOf(user.getHomepageType()))
+      .setComponent(projectOptional.get().getKey());
+    setNullable(projectOptional.get().getBranch(), homepage::setBranch);
+    return of(homepage.build());
+  }
+
+  private Optional<CurrentWsResponse.Homepage> applicationAndPortfolioHomepage(DbSession dbSession, UserDto user) {
+    Optional<ComponentDto> componentOptional = ofNullable(dbClient.componentDao().selectByUuid(dbSession, of(user.getHomepageParameter()).orElse(EMPTY)).orNull());
+    if (!componentOptional.isPresent() || !pluginRepository.hasPlugin(GOVERNANCE_PLUGIN_KEY)) {
+      cleanUserHomepageInDb(dbSession, user);
+      return empty();
     }
-    if (ORGANIZATION.toString().equals(homepageType)) {
-      checkState(homepageParameter != null, HOMEPAGE_PARAMETER_SHOULD_NOT_BE_NULL);
-      OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, homepageParameter)
-        .orElseThrow(() -> new IllegalStateException(format("Unknown organization '%s' for homepageParameter", homepageParameter)));
-      homepage.setOrganization(organization.getKey());
+
+    return of(CurrentWsResponse.Homepage.newBuilder()
+      .setType(CurrentWsResponse.HomepageType.valueOf(user.getHomepageType()))
+      .setComponent(componentOptional.get().getKey())
+      .build());
+  }
+
+  private Optional<CurrentWsResponse.Homepage> organizationHomepage(DbSession dbSession, UserDto user) {
+    Optional<OrganizationDto> organizationOptional = dbClient.organizationDao().selectByUuid(dbSession, of(user.getHomepageParameter()).orElse(EMPTY));
+    if (!organizationOptional.isPresent()) {
+      cleanUserHomepageInDb(dbSession, user);
+      return empty();
     }
+
+    return of(CurrentWsResponse.Homepage.newBuilder()
+      .setType(CurrentWsResponse.HomepageType.valueOf(user.getHomepageType()))
+      .setOrganization(organizationOptional.get().getKey())
+      .build());
+  }
+
+  private void cleanUserHomepageInDb(DbSession dbSession, UserDto user) {
+    dbClient.userDao().cleanHomepage(dbSession, user);
   }
 
   private CurrentWsResponse.Homepage defaultHomepage() {
@@ -173,4 +212,8 @@ public class CurrentAction implements UsersWsAction {
       .build();
   }
 
+  private static boolean noHomepageSet(UserDto user) {
+    return user.getHomepageType() == null;
+  }
+
 }
index be7f40ebc6091d2995fbc910e47dc4dd13dfeaa8..816555047f7a8397ac2f4c66b796605b6e97763b 100644 (file)
@@ -26,7 +26,7 @@ public interface HomepageTypes {
   enum Type {
     PROJECT,
     /**
-     * These types in only available on SonarQube
+     * These types are only available on SonarQube
      */
     PROJECTS, ISSUES, PORTFOLIOS, PORTFOLIO, APPLICATION,
     /**
@@ -34,7 +34,7 @@ public interface HomepageTypes {
      */
     MY_PROJECTS, MY_ISSUES,
     /**
-     * This type in only available when organizations are enabled
+     * This type is only available when organizations are enabled
      */
     ORGANIZATION
   }
index 7dfc2527d59178603eb26f2f0419d02cfe638f7f..d4ddeaa831885dbc6fcd50f950e14c27d0f7ea8b 100644 (file)
@@ -50,7 +50,6 @@ public class HomepageTypesImpl implements HomepageTypes, Startable {
   private final DbClient dbClient;
 
   private List<Type> types;
-  private Type defaultType;
 
   public HomepageTypesImpl(Configuration configuration, OrganizationFlags organizationFlags, DbClient dbClient) {
     this.configuration = configuration;
@@ -66,23 +65,29 @@ public class HomepageTypesImpl implements HomepageTypes, Startable {
 
   @Override
   public Type getDefaultType() {
-    checkState(types != null, "Homepage types  have not been initialized yet");
-    return defaultType;
+    return isOnSonarCloud() ? MY_PROJECTS : PROJECTS;
   }
 
   @Override
   public void start() {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      boolean isOnSonarCloud = configuration.getBoolean(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey()).orElse(false);
-      boolean isOrganizationEnabled = organizationFlags.isEnabled(dbSession);
+      boolean isOnSonarCloud = isOnSonarCloud();
+      boolean isOrganizationEnabled = isOrganizationEnabled(dbSession);
       this.types = stream(values())
         .filter(type -> (isOnSonarCloud && ON_SONARCLOUD.contains(type)) || (!isOnSonarCloud && ON_SONARQUBE.contains(type)))
         .filter(type -> isOrganizationEnabled || !(type.equals(ORGANIZATION)))
         .collect(toList());
-      this.defaultType = isOnSonarCloud ? Type.MY_PROJECTS : PROJECTS;
     }
   }
 
+  private boolean isOrganizationEnabled(DbSession dbSession) {
+    return organizationFlags.isEnabled(dbSession);
+  }
+
+  private Boolean isOnSonarCloud() {
+    return configuration.getBoolean(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey()).orElse(false);
+  }
+
   @Override
   public void stop() {
     // Nothing to do
index 7748ff9181157569d89d3abe39b5b8b99fbd418f..f148c0308609b2a12a86f379cbb0a8c1d2486ac7 100644 (file)
  */
 package org.sonar.server.user.ws;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
+import org.sonar.core.platform.PluginRepository;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
@@ -32,6 +33,7 @@ import org.sonar.db.user.UserDto;
 import org.sonar.server.issue.ws.AvatarResolverImpl;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.organization.TestOrganizationFlags;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.Users.CurrentWsResponse;
@@ -57,15 +59,14 @@ public class CurrentActionTest {
 
   private DbClient dbClient = db.getDbClient();
   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
-  private HomepageTypes homepageTypes = mock(HomepageTypes.class);
 
-  private WsActionTester ws = new WsActionTester(new CurrentAction(userSessionRule, dbClient, defaultOrganizationProvider, new AvatarResolverImpl(), homepageTypes));
+  private PluginRepository pluginRepository = mock(PluginRepository.class);
+  private MapSettings settings = new MapSettings();
+  private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
+  private HomepageTypesImpl homepageTypes = new HomepageTypesImpl(settings.asConfig(), organizationFlags, db.getDbClient());
 
-  @Before
-  public void setUp() {
-    when(homepageTypes.getDefaultType()).thenReturn(HomepageTypes.Type.MY_PROJECTS);
-    ws = new WsActionTester(new CurrentAction(userSessionRule, dbClient, defaultOrganizationProvider, new AvatarResolverImpl(), homepageTypes));
-  }
+  private WsActionTester ws = new WsActionTester(
+    new CurrentAction(userSessionRule, dbClient, defaultOrganizationProvider, new AvatarResolverImpl(), homepageTypes, pluginRepository));
 
   @Test
   public void return_user_info() {
@@ -180,6 +181,7 @@ public class CurrentActionTest {
 
   @Test
   public void return_homepage_when_set_to_a_portfolio() {
+    withGovernancePlugin();
     ComponentDto portfolio = db.components().insertPrivatePortfolio(db.getDefaultOrganization());
     UserDto user = db.users().insertUser(u -> u.setHomepageType("PORTFOLIO").setHomepageParameter(portfolio.uuid()));
     userSessionRule.logIn(user);
@@ -193,6 +195,7 @@ public class CurrentActionTest {
 
   @Test
   public void return_homepage_when_set_to_an_application() {
+    withGovernancePlugin();
     ComponentDto application = db.components().insertPrivateApplication(db.getDefaultOrganization());
     UserDto user = db.users().insertUser(u -> u.setHomepageType("APPLICATION").setHomepageParameter(application.uuid()));
     userSessionRule.logIn(user);
@@ -306,25 +309,90 @@ public class CurrentActionTest {
   }
 
   @Test
-  public void fail_with_ISE_when_user_homepage_project_does_not_exist_in_db() {
+  public void fallback_when_user_homepage_project_does_not_exist_in_db() {
     UserDto user = db.users().insertUser(u -> u.setHomepageType("PROJECT").setHomepageParameter("not-existing-project-uuid"));
     userSessionRule.logIn(user.getLogin());
 
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Unknown component 'not-existing-project-uuid' for homepageParameter");
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
 
-    call();
+    assertThat(response.getHomepage()).isNotNull();
   }
 
   @Test
-  public void fail_with_ISE_when_user_homepage_organization_does_not_exist_in_db() {
+  public void fallback_when_user_homepage_organization_does_not_exist_in_db() {
     UserDto user = db.users().insertUser(u -> u.setHomepageType("ORGANIZATION").setHomepageParameter("not-existing-organization-uuid"));
     userSessionRule.logIn(user.getLogin());
 
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Unknown organization 'not-existing-organization-uuid' for homepageParameter");
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
 
-    call();
+    assertThat(response.getHomepage()).isNotNull();
+  }
+
+  @Test
+  public void fallback_when_user_homepage_portfolio_does_not_exist_in_db() {
+    withGovernancePlugin();
+    UserDto user = db.users().insertUser(u -> u.setHomepageType("PORTFOLIO").setHomepageParameter("not-existing-portfolio-uuid"));
+    userSessionRule.logIn(user.getLogin());
+
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+
+    assertThat(response.getHomepage()).isNotNull();
+  }
+
+  @Test
+  public void fallback_when_user_homepage_application_does_not_exist_in_db() {
+    withGovernancePlugin();
+    UserDto user = db.users().insertUser(u -> u.setHomepageType("APPLICATION").setHomepageParameter("not-existing-application-uuid"));
+    userSessionRule.logIn(user.getLogin());
+
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+
+    assertThat(response.getHomepage()).isNotNull();
+  }
+
+  @Test
+  public void fallback_when_user_homepage_application_and_governance_plugin_is_not_installed() {
+    withoutGovernancePlugin();
+    ComponentDto application = db.components().insertPrivateApplication(db.getDefaultOrganization());
+    UserDto user = db.users().insertUser(u -> u.setHomepageType("APPLICATION").setHomepageParameter(application.uuid()));
+    userSessionRule.logIn(user.getLogin());
+
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+
+    assertThat(response.getHomepage().getType().toString()).isEqualTo("PROJECTS");
+  }
+
+  @Test
+  public void fallback_to_PROJECTS_when_on_SonarQube() {
+    UserDto user = db.users().insertUser(u -> u.setHomepageType("PROJECT").setHomepageParameter("not-existing-project-uuid"));
+    userSessionRule.logIn(user.getLogin());
+
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+
+    assertThat(response.getHomepage().getType().toString()).isEqualTo("PROJECTS");
+  }
+
+  @Test
+  public void fallback_to_MY_PROJECTS_when_on_SonarCloud() {
+    onSonarCloud();
+    UserDto user = db.users().insertUser(u -> u.setHomepageType("PROJECT").setHomepageParameter("not-existing-project-uuid"));
+    userSessionRule.logIn(user.getLogin());
+
+    CurrentWsResponse response = ws.newRequest().executeProtobuf(CurrentWsResponse.class);
+
+    assertThat(response.getHomepage().getType().toString()).isEqualTo("MY_PROJECTS");
+  }
+
+  private void onSonarCloud() {
+    settings.setProperty("sonar.sonarcloud.enabled", true);
+  }
+
+  private void withGovernancePlugin(){
+    when(pluginRepository.hasPlugin("governance")).thenReturn(true);
+  }
+
+  private void withoutGovernancePlugin(){
+    when(pluginRepository.hasPlugin("governance")).thenReturn(false);
   }
 
 }
index 4d221650f45d208445f5feada8c9e981640de46a..92e8444c54b7482cb9a2b3d92b126d822bd73a94 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.user.ws;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -35,17 +34,8 @@ import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestResponse;
 import org.sonar.server.ws.WsActionTester;
 
-import static java.util.Arrays.asList;
 import static org.apache.http.HttpStatus.SC_NO_CONTENT;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.server.user.ws.HomepageTypes.Type.ISSUES;
-import static org.sonar.server.user.ws.HomepageTypes.Type.MY_ISSUES;
-import static org.sonar.server.user.ws.HomepageTypes.Type.MY_PROJECTS;
-import static org.sonar.server.user.ws.HomepageTypes.Type.ORGANIZATION;
-import static org.sonar.server.user.ws.HomepageTypes.Type.PROJECT;
-import static org.sonar.server.user.ws.HomepageTypes.Type.PROJECTS;
 import static org.sonar.server.user.ws.SetHomepageAction.PARAM_COMPONENT;
 import static org.sonar.server.user.ws.SetHomepageAction.PARAM_TYPE;
 
@@ -61,15 +51,8 @@ public class SetHomepageActionTest {
   public ExpectedException expectedException = ExpectedException.none();
 
   private DbClient dbClient = db.getDbClient();
-  private HomepageTypes homepageTypes = mock(HomepageTypes.class);
 
-  private WsActionTester ws;
-
-  @Before
-  public void setUp() {
-    when(homepageTypes.getTypes()).thenReturn(asList(PROJECT, ORGANIZATION, MY_ISSUES, MY_PROJECTS));
-    ws = new WsActionTester(new SetHomepageAction(userSession, dbClient, TestComponentFinder.from(db)));
-  }
+  private WsActionTester ws = new WsActionTester(new SetHomepageAction(userSession, dbClient, TestComponentFinder.from(db)));
 
   @Test
   public void verify_definition() {
@@ -163,7 +146,7 @@ public class SetHomepageActionTest {
   }
 
   @Test
-  public void set_sonarcloud_my_issues_homepage() {
+  public void set_SonarCloud_my_issues_homepage() {
     UserDto user = db.users().insertUser();
     userSession.logIn(user);
 
@@ -179,10 +162,7 @@ public class SetHomepageActionTest {
   }
 
   @Test
-  public void set_sonarqube_issues_homepage() {
-
-    when(homepageTypes.getTypes()).thenReturn(asList(PROJECT, ORGANIZATION, ISSUES, PROJECTS));
-    ws = new WsActionTester(new SetHomepageAction(userSession, dbClient, TestComponentFinder.from(db)));
+  public void set_SonarQube_issues_homepage() {
 
     UserDto user = db.users().insertUser();
     userSession.logIn(user);
@@ -199,7 +179,7 @@ public class SetHomepageActionTest {
   }
 
   @Test
-  public void set_sonarcloud_my_projects_homepage() {
+  public void set_SonarCloud_my_projects_homepage() {
     UserDto user = db.users().insertUser();
     userSession.logIn(user);
 
@@ -215,7 +195,7 @@ public class SetHomepageActionTest {
   }
 
   @Test
-  public void set_sonarqube_projects_homepage() {
+  public void set_SonarQube_projects_homepage() {
     UserDto user = db.users().insertUser();
     userSession.logIn(user);
 
@@ -327,6 +307,21 @@ public class SetHomepageActionTest {
       .execute();
   }
 
+  @Test
+  public void fail_when_invalid_homepage_type() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException
+      .expectMessage("Value of parameter 'type' (PIPO) must be one of: [PROJECT, PROJECTS, ISSUES, PORTFOLIOS, PORTFOLIO, APPLICATION, MY_PROJECTS, MY_ISSUES, ORGANIZATION]");
+
+    ws.newRequest()
+      .setMethod("POST")
+      .setParam(PARAM_TYPE, "PIPO")
+      .execute();
+  }
+
   @Test
   public void fail_for_anonymous() {
     userSession.anonymous();