]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16613 Migrate users field 'sonarlint_ad_seen' to use the new notice mechanism
authorPierre <pierre.guillot@sonarsource.com>
Fri, 15 Jul 2022 09:50:31 +0000 (11:50 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 21 Jul 2022 20:03:05 +0000 (20:03 +0000)
26 files changed:
server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDto.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/schema/schema-sq.ddl
server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DropColumnChange.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DropColumnWithConstraint.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v91/DropUserManagedColumnFromMetricsTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/DbVersion96.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTable.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToProperties.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest/schema.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest/schema.sql [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/CurrentAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/DismissNoticeAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/DismissSonarlintAdAction.java
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/user/ws/current-example.json
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/CurrentActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/DismissNoticeActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/DismissSonarlintAdActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java
sonar-ws/src/main/protobuf/ws-users.proto

index 82a7580087d1457db6d23be0872a49e6309472af..ea069210e789d110947d0e2f7047d95c5698c2ce 100644 (file)
@@ -458,4 +458,5 @@ public class DatabaseUtils {
       checkArgument(values.size() <= PARTITION_SIZE_FOR_ORACLE, message);
     }
   }
+
 }
index a859286377e7f4089e871daf325ef203748d2ac3..c43e3b1dce31a000d7ca05028488c91224210e80 100644 (file)
@@ -125,10 +125,6 @@ public class UserDao implements Dao {
     mapper(session).updateSonarlintLastConnectionDate(login, system2.now());
   }
 
-  public void dismissSonarlintAd(DbSession session, String login) {
-    mapper(session).dismissSonarlintAd(login);
-  }
-
   public void deactivateUser(DbSession dbSession, UserDto user) {
     mapper(dbSession).deactivateUser(user.getLogin(), system2.now());
     auditPersister.deactivateUser(dbSession, new UserNewValue(user.getUuid(), user.getLogin()));
index 71dcfd94b7c8af1331da1e9ce9a247ceb40c7d40..e9387657f66aae94484e3919690d2e4187e82b88 100644 (file)
@@ -53,7 +53,6 @@ public class UserDto implements UserId {
   private String homepageParameter;
   private boolean local = true;
   private boolean resetPassword = false;
-  private boolean sonarlintAdSeen = false;
 
   /**
    * Date of the last time the user has accessed to the server.
@@ -252,15 +251,6 @@ public class UserDto implements UserId {
     return this;
   }
 
-  public boolean isSonarlintAdSeen() {
-    return sonarlintAdSeen;
-  }
-
-  public UserDto setSonarlintAdSeen(boolean sonarlintAdSeen) {
-    this.sonarlintAdSeen = sonarlintAdSeen;
-    return this;
-  }
-
   @CheckForNull
   public Long getLastConnectionDate() {
     return lastConnectionDate;
index 802b1f1a30ee2c4975157aaceb51929b6a77c96f..5e59ef4958f1e0c06e413c97c22542712b434427 100644 (file)
@@ -79,6 +79,4 @@ public interface UserMapper {
   void clearHomepage(@Param("login") String login, @Param("now") long now);
 
   long countActiveSonarlintUsers(@Param("sinceDate") long sinceDate);
-
-  void dismissSonarlintAd(@Param("login") String login);
 }
index 858b063cc51dbf22e9eebd331eecd72d9cc21852..3dfd081b18f7a6db603ff83900d86bf8ce867415 100644 (file)
@@ -22,7 +22,6 @@
         u.homepage_parameter as "homepageParameter",
         u.last_connection_date as "lastConnectionDate",
         u.last_sonarlint_connection as "lastSonarlintConnectionDate",
-        u.sonarlint_ad_seen as "sonarlintAdSeen",
         u.created_at as "createdAt",
         u.updated_at as "updatedAt"
     </sql>
         login = #{login, jdbcType=VARCHAR}
     </update>
 
-    <update id="dismissSonarlintAd" parameterType="map">
-        update users set
-        sonarlint_ad_seen = ${_true}
-        where
-        login = #{login, jdbcType=VARCHAR}
-    </update>
-
     <update id="deactivateUser" parameterType="map">
         update users set
         <include refid="deactivateUserUpdatedFields"/>
         crypted_password,
         hash_method,
         last_sonarlint_connection,
-        sonarlint_ad_seen,
         reset_password,
         homepage_type,
         homepage_parameter,
         #{user.cryptedPassword,jdbcType=VARCHAR},
         #{user.hashMethod,jdbcType=VARCHAR},
         #{user.lastSonarlintConnectionDate,jdbcType=BIGINT},
-        #{user.sonarlintAdSeen,jdbcType=BOOLEAN},
         #{user.resetPassword,jdbcType=BOOLEAN},
         #{user.homepageType,jdbcType=VARCHAR},
         #{user.homepageParameter,jdbcType=VARCHAR},
         homepage_parameter = #{user.homepageParameter, jdbcType=VARCHAR},
         last_connection_date = #{user.lastConnectionDate,jdbcType=BIGINT},
         last_sonarlint_connection = #{user.lastSonarlintConnectionDate,jdbcType=BIGINT},
-        sonarlint_ad_seen = #{user.sonarlintAdSeen,jdbcType=BOOLEAN},
         updated_at = #{user.updatedAt,jdbcType=BIGINT}
         where
         uuid = #{user.uuid, jdbcType=VARCHAR}
index a9cfa3c66ad6cf892df8cb8e0bd6d68b4afecce9..074594cb5ebf819ff536873048c6daf5f2b6e44e 100644 (file)
@@ -993,8 +993,7 @@ CREATE TABLE "USERS"(
     "CREATED_AT" BIGINT,
     "UPDATED_AT" BIGINT,
     "RESET_PASSWORD" BOOLEAN NOT NULL,
-    "LAST_SONARLINT_CONNECTION" BIGINT,
-    "SONARLINT_AD_SEEN" BOOLEAN DEFAULT FALSE
+    "LAST_SONARLINT_CONNECTION" BIGINT
 );
 ALTER TABLE "USERS" ADD CONSTRAINT "PK_USERS" PRIMARY KEY("UUID");
 CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS"("LOGIN" NULLS FIRST);
index b43af0453c089f183c64839d211c356af2af530f..6d2005ef246d842d065d9a5cff8ab6640eacb270 100644 (file)
@@ -97,18 +97,6 @@ public class UserDaoTest {
     assertThat(user).isNull();
   }
 
-  @Test
-  public void dismiss_sonarlint_ad() {
-    UserDto user = db.users().insertUser(u -> u.setLogin("user"));
-    assertThat(user.isSonarlintAdSeen()).isFalse();
-
-    underTest.dismissSonarlintAd(session, "user");
-
-    user = db.users().selectUserByLogin("user").get();
-
-    assertThat(user.isSonarlintAdSeen()).isTrue();
-  }
-
   @Test
   public void selectUsersByLogins() {
     db.users().insertUser(user -> user.setLogin("user1"));
index 5bf051020f2b39e3605461656b3230edda7eff4c..ba7615267771926cc0edd2c58e4d393d8f12a086 100644 (file)
@@ -44,7 +44,7 @@ public abstract class DropColumnChange extends DdlChange {
     context.execute(new DropColumnsBuilder(getDatabase().getDialect(), tableName, columnName).build());
   }
 
-  private boolean checkIfUseManagedColumnExists() throws SQLException {
+  public boolean checkIfUseManagedColumnExists() throws SQLException {
     try (var connection = getDatabase().getDataSource().getConnection()) {
       if (DatabaseUtils.tableColumnExists(connection, tableName, columnName)) {
         return true;
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DropColumnWithConstraint.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DropColumnWithConstraint.java
new file mode 100644 (file)
index 0000000..34d9dc1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.step;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.dialect.MsSql;
+import org.sonar.server.platform.db.migration.sql.DropColumnsBuilder;
+import org.sonar.server.platform.db.migration.sql.DropMsSQLDefaultConstraintsBuilder;
+
+public class DropColumnWithConstraint extends DropColumnChange {
+
+  private final String tableName;
+  private final String column;
+
+  public DropColumnWithConstraint(Database db, String tableName, String column) {
+    super(db, tableName, column);
+    this.tableName = tableName;
+    this.column = column;
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    if (!checkIfUseManagedColumnExists()) {
+      return;
+    }
+
+    if (MsSql.ID.equals(getDatabase().getDialect().getId())) {
+      context.execute(new DropMsSQLDefaultConstraintsBuilder(getDatabase()).setTable(tableName).setColumns(column).build());
+    }
+    context.execute(new DropColumnsBuilder(getDatabase().getDialect(), tableName, column).build());
+  }
+
+}
index 05628583383d058dc91e1af178172dc6ae0cff47..3cfcce03f2789004cb62e9e60fe161c50cba76c4 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v91;
 
-import java.sql.SQLException;
 import org.sonar.db.Database;
-import org.sonar.db.DatabaseUtils;
-import org.sonar.db.dialect.MsSql;
-import org.sonar.server.platform.db.migration.sql.DropColumnsBuilder;
-import org.sonar.server.platform.db.migration.sql.DropMsSQLDefaultConstraintsBuilder;
-import org.sonar.server.platform.db.migration.step.DdlChange;
+import org.sonar.server.platform.db.migration.step.DropColumnWithConstraint;
 
-public class DropUserManagedColumnFromMetricsTable extends DdlChange {
+public class DropUserManagedColumnFromMetricsTable extends DropColumnWithConstraint {
 
   private static final String TABLE_NAME = "metrics";
   private static final String COLUMN = "user_managed";
 
   public DropUserManagedColumnFromMetricsTable(Database db) {
-    super(db);
+    super(db, TABLE_NAME, COLUMN);
   }
 
-  @Override
-  public void execute(Context context) throws SQLException {
-    if (!checkIfUseManagedColumnExists()) {
-      return;
-    }
-
-    if (MsSql.ID.equals(getDatabase().getDialect().getId())) {
-      context.execute(new DropMsSQLDefaultConstraintsBuilder(getDatabase()).setTable(TABLE_NAME).setColumns(COLUMN).build());
-    }
-    context.execute(new DropColumnsBuilder(getDatabase().getDialect(), TABLE_NAME, COLUMN).build());
-  }
-
-  private boolean checkIfUseManagedColumnExists() throws SQLException {
-    try (var connection = getDatabase().getDataSource().getConnection()) {
-      if (DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN)) {
-        return true;
-      }
-    }
-    return false;
-  }
 }
index 4c3ad0be119ca1f9cea97bbd792d37e4f1042832..71692004e5803eac7985e4777fcec98fad837d4d 100644 (file)
@@ -36,6 +36,8 @@ public class DbVersion96 implements DbVersion {
       .add(6505, "Add column 'rule_description_context_key' to 'issues'", AddRuleDescriptionContextKeyInIssuesTable.class)
       .add(6506, "Add column 'education_principles' to 'rules'", AddEducationPrinciplesColumnToRuleTable.class)
       .add(6507, "Overwrite plugin file hash to force reloading rules", ForceReloadingOfAllPlugins.class)
+      .add(6508, "Migrate 'sonarlint_ad_seen' from users to properties", MigrateSonarlintAdSeenFromUsersToProperties.class)
+      .add(6509, "Drop column sonarlint_ad_seen in 'users'", DropSonarlintAdSeenColumnInUsersTable.class)
     ;
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTable.java
new file mode 100644 (file)
index 0000000..fa8bc33
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.v96;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DropColumnWithConstraint;
+
+public class DropSonarlintAdSeenColumnInUsersTable extends DropColumnWithConstraint {
+
+  private static final String TABLE_NAME = "users";
+  private static final String COLUMN = "sonarlint_ad_seen";
+
+  public DropSonarlintAdSeenColumnInUsersTable(Database db) {
+    super(db, TABLE_NAME, COLUMN);
+  }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToProperties.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToProperties.java
new file mode 100644 (file)
index 0000000..99c52df
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.v96;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class MigrateSonarlintAdSeenFromUsersToProperties extends DataChange {
+
+  public static final String USER_DISMISSED_NOTICES_SONARLINT_AD = "user.dismissedNotices.sonarlintAd";
+
+  private final UuidFactory uuidFactory;
+  private final System2 system2;
+
+  public MigrateSonarlintAdSeenFromUsersToProperties(Database db, UuidFactory uuidFactory, System2 system2) {
+    super(db);
+    this.uuidFactory = uuidFactory;
+    this.system2 = system2;
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    MassUpdate massUpdate = context.prepareMassUpdate();
+
+    massUpdate.select("select u.uuid, u.sonarlint_ad_seen, p.uuid from users u" +
+        " left join properties p on u.uuid = p.user_uuid and p.prop_key = ?" +
+        " where u.sonarlint_ad_seen = ?" +
+        " and p.uuid is null")
+      .setString(1, USER_DISMISSED_NOTICES_SONARLINT_AD)
+      .setBoolean(2, true);
+
+    massUpdate.update("insert into properties (uuid,prop_key,user_uuid,is_empty,created_at) values (?, ?, ?, ?, ?)");
+
+    massUpdate.execute((row, update) -> {
+      update.setString(1, uuidFactory.create());
+      update.setString(2, USER_DISMISSED_NOTICES_SONARLINT_AD);
+      update.setString(3, row.getString(1));
+      update.setBoolean(4, true);
+      update.setLong(5, system2.now());
+
+      return true;
+    });
+
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest.java
new file mode 100644 (file)
index 0000000..1dca640
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.v96;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class DropSonarlintAdSeenColumnInUsersTableTest {
+
+  private static final String COLUMN_NAME = "sonarlint_ad_seen";
+  private static final String TABLE_NAME = "users";
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(DropSonarlintAdSeenColumnInUsersTableTest.class, "schema.sql");
+
+  private final DdlChange underTest = new DropSonarlintAdSeenColumnInUsersTable(db.database());
+
+  @Test
+  public void migration_should_drop_column() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.BOOLEAN, null, true);
+    underTest.execute();
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+  }
+
+  @Test
+  public void migration_should_be_reentrant() throws SQLException {
+    db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, Types.BOOLEAN, null, true);
+    underTest.execute();
+    // re-entrant
+    underTest.execute();
+    db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+  }
+}
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest.java
new file mode 100644 (file)
index 0000000..02d0c92
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.v96;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.core.util.UuidFactoryFast;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DataChange;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.platform.db.migration.version.v96.MigrateSonarlintAdSeenFromUsersToProperties.USER_DISMISSED_NOTICES_SONARLINT_AD;
+
+public class MigrateSonarlintAdSeenFromUsersToPropertiesTest {
+
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(MigrateSonarlintAdSeenFromUsersToPropertiesTest.class, "schema.sql");
+
+  private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
+  private final System2 system2 = new System2();
+
+  private final DataChange underTest = new MigrateSonarlintAdSeenFromUsersToProperties(db.database(), uuidFactory, system2);
+
+  @Test
+  public void migrate_sonarlintAd_to_properties() throws SQLException {
+    insertUser(db, "uuid-user-1", "user1", "externalId1", "externalLogin1", true);
+    insertUser(db, "uuid-user-2", "user2", "externalId2", "externalLogin2", false);
+
+    underTest.execute();
+
+    assertThat(db.countSql("select count(*) from properties where prop_key='" + USER_DISMISSED_NOTICES_SONARLINT_AD + "' and user_uuid='uuid-user-1'")).isEqualTo(1);
+    assertThat(db.countSql("select count(*) from properties where prop_key='" + USER_DISMISSED_NOTICES_SONARLINT_AD + "' and user_uuid='uuid-user-2'")).isZero();
+  }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    insertUser(db, "uuid-user-1", "user1", "externalId1", "externalLogin1", true);
+
+    underTest.execute();
+    underTest.execute();
+
+    assertThat(db.countSql("select count(*) from properties where prop_key='" + USER_DISMISSED_NOTICES_SONARLINT_AD + "' and user_uuid='uuid-user-1'")).isEqualTo(1);
+  }
+
+  private void insertUser(CoreDbTester db, String userUuid, String login, String externalId, String externalLogin, boolean seen) {
+    db.executeInsert("users", "UUID", userUuid,
+      "login", login,
+      "external_identity_provider", "none",
+      "external_id", externalId,
+      "external_login", externalLogin,
+      "reset_password", false,
+      "sonarlint_ad_seen", seen
+    );
+  }
+
+
+}
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/DropSonarlintAdSeenColumnInUsersTableTest/schema.sql
new file mode 100644 (file)
index 0000000..82da2b0
--- /dev/null
@@ -0,0 +1,28 @@
+CREATE TABLE "USERS"(
+    "UUID" CHARACTER VARYING(255) NOT NULL,
+    "LOGIN" CHARACTER VARYING(255) NOT NULL,
+    "NAME" CHARACTER VARYING(200),
+    "EMAIL" CHARACTER VARYING(100),
+    "CRYPTED_PASSWORD" CHARACTER VARYING(100),
+    "SALT" CHARACTER VARYING(40),
+    "HASH_METHOD" CHARACTER VARYING(10),
+    "ACTIVE" BOOLEAN DEFAULT TRUE,
+    "SCM_ACCOUNTS" CHARACTER VARYING(4000),
+    "EXTERNAL_LOGIN" CHARACTER VARYING(255) NOT NULL,
+    "EXTERNAL_IDENTITY_PROVIDER" CHARACTER VARYING(100) NOT NULL,
+    "EXTERNAL_ID" CHARACTER VARYING(255) NOT NULL,
+    "USER_LOCAL" BOOLEAN,
+    "HOMEPAGE_TYPE" CHARACTER VARYING(40),
+    "HOMEPAGE_PARAMETER" CHARACTER VARYING(40),
+    "LAST_CONNECTION_DATE" BIGINT,
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "RESET_PASSWORD" BOOLEAN NOT NULL,
+    "LAST_SONARLINT_CONNECTION" BIGINT,
+    "SONARLINT_AD_SEEN" BOOLEAN DEFAULT FALSE
+);
+ALTER TABLE "USERS" ADD CONSTRAINT "PK_USERS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS"("LOGIN" NULLS FIRST);
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS"("UPDATED_AT" NULLS FIRST);
+CREATE UNIQUE INDEX "UNIQ_EXTERNAL_ID" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_ID" NULLS FIRST);
+CREATE UNIQUE INDEX "UNIQ_EXTERNAL_LOGIN" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_LOGIN" NULLS FIRST);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v96/MigrateSonarlintAdSeenFromUsersToPropertiesTest/schema.sql
new file mode 100644 (file)
index 0000000..f5eda0e
--- /dev/null
@@ -0,0 +1,42 @@
+CREATE TABLE "USERS"(
+    "UUID" CHARACTER VARYING(255) NOT NULL,
+    "LOGIN" CHARACTER VARYING(255) NOT NULL,
+    "NAME" CHARACTER VARYING(200),
+    "EMAIL" CHARACTER VARYING(100),
+    "CRYPTED_PASSWORD" CHARACTER VARYING(100),
+    "SALT" CHARACTER VARYING(40),
+    "HASH_METHOD" CHARACTER VARYING(10),
+    "ACTIVE" BOOLEAN DEFAULT TRUE,
+    "SCM_ACCOUNTS" CHARACTER VARYING(4000),
+    "EXTERNAL_LOGIN" CHARACTER VARYING(255) NOT NULL,
+    "EXTERNAL_IDENTITY_PROVIDER" CHARACTER VARYING(100) NOT NULL,
+    "EXTERNAL_ID" CHARACTER VARYING(255) NOT NULL,
+    "USER_LOCAL" BOOLEAN,
+    "HOMEPAGE_TYPE" CHARACTER VARYING(40),
+    "HOMEPAGE_PARAMETER" CHARACTER VARYING(40),
+    "LAST_CONNECTION_DATE" BIGINT,
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "RESET_PASSWORD" BOOLEAN NOT NULL,
+    "LAST_SONARLINT_CONNECTION" BIGINT,
+    "SONARLINT_AD_SEEN" BOOLEAN DEFAULT FALSE
+);
+ALTER TABLE "USERS" ADD CONSTRAINT "PK_USERS" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS"("LOGIN" NULLS FIRST);
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS"("UPDATED_AT" NULLS FIRST);
+CREATE UNIQUE INDEX "UNIQ_EXTERNAL_ID" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_ID" NULLS FIRST);
+CREATE UNIQUE INDEX "UNIQ_EXTERNAL_LOGIN" ON "USERS"("EXTERNAL_IDENTITY_PROVIDER" NULLS FIRST, "EXTERNAL_LOGIN" NULLS FIRST);
+
+
+CREATE TABLE "PROPERTIES"(
+    "UUID" CHARACTER VARYING(40) NOT NULL,
+    "PROP_KEY" CHARACTER VARYING(512) NOT NULL,
+    "IS_EMPTY" BOOLEAN NOT NULL,
+    "TEXT_VALUE" CHARACTER VARYING(4000),
+    "CLOB_VALUE" CHARACTER LARGE OBJECT,
+    "CREATED_AT" BIGINT NOT NULL,
+    "COMPONENT_UUID" CHARACTER VARYING(40),
+    "USER_UUID" CHARACTER VARYING(255)
+);
+ALTER TABLE "PROPERTIES" ADD CONSTRAINT "PK_PROPERTIES" PRIMARY KEY("UUID");
+CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES"("PROP_KEY" NULLS FIRST);
index 9721fad227753ad045b141075eea8373c6906390..9d95d554204a333f6536c32c22b7d26221a5d055 100644 (file)
@@ -51,6 +51,7 @@ import static java.util.stream.Collectors.toList;
 import static org.apache.commons.lang.StringUtils.EMPTY;
 import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.server.user.ws.DismissNoticeAction.EDUCATION_PRINCIPLES;
+import static org.sonar.server.user.ws.DismissNoticeAction.SONARLINT_AD;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.APPLICATION;
 import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PORTFOLIO;
@@ -89,7 +90,9 @@ public class CurrentAction implements UsersWsAction {
         new Change("6.5", "showOnboardingTutorial is now returned in the response"),
         new Change("7.1", "'parameter' is replaced by 'component' and 'organization' in the response"),
         new Change("9.2", "boolean 'usingSonarLintConnectedMode' and 'sonarLintAdSeen' fields are now returned in the response"),
-        new Change("9.5", "showOnboardingTutorial is not returned anymore in the response"));
+        new Change("9.5", "showOnboardingTutorial is not returned anymore in the response"),
+        new Change("9.6", "'sonarLintAdSeen' is removed and replaced by a 'dismissedNotices' map that support multiple values")
+      );
   }
 
   @Override
@@ -122,8 +125,8 @@ public class CurrentAction implements UsersWsAction {
       .setPermissions(Permissions.newBuilder().addAllGlobal(getGlobalPermissions()).build())
       .setHomepage(buildHomepage(dbSession, user))
       .setUsingSonarLintConnectedMode(user.getLastSonarlintConnectionDate() != null)
-      .setSonarLintAdSeen(user.isSonarlintAdSeen())
-      .putDismissedNotices(EDUCATION_PRINCIPLES, isNoticeDismissed(user, EDUCATION_PRINCIPLES));
+      .putDismissedNotices(EDUCATION_PRINCIPLES, isNoticeDismissed(user, EDUCATION_PRINCIPLES))
+      .putDismissedNotices(SONARLINT_AD, isNoticeDismissed(user, SONARLINT_AD));
     ofNullable(emptyToNull(user.getEmail())).ifPresent(builder::setEmail);
     ofNullable(emptyToNull(user.getEmail())).ifPresent(u -> builder.setAvatar(avatarResolver.create(user)));
     ofNullable(user.getExternalLogin()).ifPresent(builder::setExternalIdentity);
index d4625ffb21eb5dffc86f4383260afe7270b6ff12..5b830ebe4866693dbceb51267ffc657342c37c98 100644 (file)
@@ -33,6 +33,7 @@ import static com.google.common.base.Preconditions.checkState;
 public class DismissNoticeAction implements UsersWsAction {
 
   public static final String EDUCATION_PRINCIPLES = "educationPrinciples";
+  public static final String SONARLINT_AD = "sonarlintAd";
   public static final String USER_DISMISS_CONSTANT = "user.dismissedNotices.";
 
   private final UserSession userSession;
@@ -46,7 +47,7 @@ public class DismissNoticeAction implements UsersWsAction {
   @Override
   public void define(WebService.NewController context) {
     WebService.NewAction action = context.createAction("dismiss_notice")
-      .setDescription("Dismiss a notice for the current user.")
+      .setDescription("Dismiss a notice for the current user. Silently ignore if the notice is already dismissed.")
       .setSince("9.6")
       .setInternal(true)
       .setHandler(this)
@@ -55,7 +56,7 @@ public class DismissNoticeAction implements UsersWsAction {
     action.createParam("notice")
       .setDescription("notice key to dismiss")
       .setExampleValue(EDUCATION_PRINCIPLES)
-      .setPossibleValues(EDUCATION_PRINCIPLES);
+      .setPossibleValues(EDUCATION_PRINCIPLES, SONARLINT_AD);
   }
 
   @Override
@@ -66,6 +67,10 @@ public class DismissNoticeAction implements UsersWsAction {
 
     String noticeKeyParam = request.mandatoryParam("notice");
 
+    dismissNotice(response, currentUserUuid, noticeKeyParam);
+  }
+
+  public void dismissNotice(Response response, String currentUserUuid, String noticeKeyParam) {
     try (DbSession dbSession = dbClient.openSession(false)) {
       String paramKey = USER_DISMISS_CONSTANT + noticeKeyParam;
       PropertyQuery query = new PropertyQuery.Builder()
@@ -74,7 +79,8 @@ public class DismissNoticeAction implements UsersWsAction {
         .build();
 
       if (!dbClient.propertiesDao().selectByQuery(query, dbSession).isEmpty()) {
-        throw new IllegalArgumentException(String.format("Notice %s is already dismissed", noticeKeyParam));
+        // already dismissed
+        response.noContent();
       }
 
       PropertyDto property = new PropertyDto().setUserUuid(currentUserUuid).setKey(paramKey);
@@ -82,6 +88,5 @@ public class DismissNoticeAction implements UsersWsAction {
       dbSession.commit();
       response.noContent();
     }
-
   }
 }
index 6762ffd6364041d50767444f6fa4de838bdc5d91..00840ca5d45f5c5ac43d1fe50d3490d2f742494a 100644 (file)
@@ -22,37 +22,37 @@ package org.sonar.server.user.ws;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.server.user.UserSession;
 
+import static org.sonar.server.user.ws.DismissNoticeAction.SONARLINT_AD;
 import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_DISMISS_SONARLINT_AD;
 
+/**
+ * @deprecated use DismissNoticeAction
+ */
+@Deprecated(since = "9.6", forRemoval = true)
 public class DismissSonarlintAdAction implements UsersWsAction {
   private final UserSession userSession;
-  private final DbClient dbClient;
+  private final DismissNoticeAction dismissNoticeAction;
 
-  public DismissSonarlintAdAction(UserSession userSession, DbClient dbClient) {
+  public DismissSonarlintAdAction(UserSession userSession, DismissNoticeAction dismissNoticeAction) {
     this.userSession = userSession;
-    this.dbClient = dbClient;
+    this.dismissNoticeAction = dismissNoticeAction;
   }
 
   @Override
   public void define(WebService.NewController controller) {
     controller.createAction(ACTION_DISMISS_SONARLINT_AD)
-      .setDescription("Dismiss SonarLint advertisement.")
+      .setDescription("Dismiss SonarLint advertisement. Deprecated since 9.6, replaced api/users/dismiss_notice")
       .setSince("9.2")
       .setPost(true)
+      .setDeprecatedSince("9.6")
       .setHandler(this);
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
     userSession.checkLoggedIn();
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      dbClient.userDao().dismissSonarlintAd(dbSession, userSession.getLogin());
-      dbSession.commit();
-    }
-    response.noContent();
+    dismissNoticeAction.dismissNotice(response, userSession.getUuid(), SONARLINT_AD);
   }
 }
index e1644c3788843efa3aba181bc8ef8d15dee7731b..50991030f29c6104267d6dc8a17099582e9d581c 100644 (file)
@@ -3,19 +3,22 @@
   "login": "obiwan.kenobi",
   "name": "Obiwan Kenobi",
   "email": "obiwan.kenobi@starwars.com",
-  "avatar": "f5aa64437a1821ffe8b563099d506aef",
   "local": true,
   "externalIdentity": "obiwan.kenobi",
   "externalProvider": "sonarqube",
   "scmAccounts": ["obiwan:github", "obiwan:bitbucket"],
   "groups": ["Jedi", "Rebel"],
-  "usingSonarLintConnectedMode": false,
-  "sonarLintAdSeen": false,
   "permissions": {
     "global": ["profileadmin", "scan"]
   },
+  "avatar": "f5aa64437a1821ffe8b563099d506aef",
   "homepage": {
     "type": "PROJECT",
     "component": "death-star-key"
+  },
+  "usingSonarLintConnectedMode": false,
+  "dismissedNotices": {
+    "educationPrinciples": false,
+    "sonarlintAd": false
   }
 }
index a46493caee5cbb49bca1fe53ccc977192d8df770..8707a53595b9404bc0e2309dd046f903592f3326 100644 (file)
@@ -130,8 +130,8 @@ public class CurrentActionTest {
 
     assertThat(response)
       .extracting(CurrentWsResponse::getIsLoggedIn, CurrentWsResponse::getLogin, CurrentWsResponse::getName, CurrentWsResponse::hasAvatar, CurrentWsResponse::getLocal,
-        CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::getUsingSonarLintConnectedMode, CurrentWsResponse::getSonarLintAdSeen)
-      .containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", false, false);
+        CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::getUsingSonarLintConnectedMode)
+      .containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", false);
     assertThat(response.hasEmail()).isFalse();
     assertThat(response.getScmAccountsList()).isEmpty();
     assertThat(response.getGroupsList()).isEmpty();
@@ -240,15 +240,33 @@ public class CurrentActionTest {
   }
 
   @Test
-  public void handle_givenSonarLintAdSeenUserInDatabase_returnSonarLintAdSeenUserFromTheEndpoint() {
-    UserDto user = db.users().insertUser(u -> u.setSonarlintAdSeen(true));
+  public void return_sonarlintAd_dismiss_notice() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+
+    PropertyDto property = new PropertyDto().setUserUuid(user.getUuid()).setKey("user.dismissedNotices.sonarlintAd");
+    db.properties().insertProperties(userSession.getLogin(), null, null, null, property);
+
+    CurrentWsResponse response = call();
+
+    assertThat(response.getDismissedNoticesMap().entrySet())
+      .extracting(Map.Entry::getKey, Map.Entry::getValue)
+      .contains(Tuple.tuple("sonarlintAd", true));
+  }
+
+  @Test
+  public void return_sonarlintAd_not_dismissed() {
+    UserDto user = db.users().insertUser();
     userSession.logIn(user);
 
     CurrentWsResponse response = call();
 
-    assertThat(response.getSonarLintAdSeen()).isTrue();
+    assertThat(response.getDismissedNoticesMap().entrySet())
+      .extracting(Map.Entry::getKey, Map.Entry::getValue)
+      .contains(Tuple.tuple("sonarlintAd", false));
   }
 
+
   @Test
   public void test_definition() {
     WebService.Action definition = ws.getDef();
@@ -259,7 +277,7 @@ public class CurrentActionTest {
     assertThat(definition.isInternal()).isTrue();
     assertThat(definition.responseExampleAsString()).isNotEmpty();
     assertThat(definition.params()).isEmpty();
-    assertThat(definition.changelog()).hasSize(4);
+    assertThat(definition.changelog()).isNotEmpty();
   }
 
   private CurrentWsResponse call() {
index d20d7eeb3012ef005acecb05a65af3fa9298d9c6..2edf0c4da9a7e6b48ff9b531d417b1faa458aa08 100644 (file)
@@ -57,6 +57,20 @@ public class DismissNoticeActionTest {
     assertThat(propertyDto).isPresent();
   }
 
+  @Test
+  public void dismiss_sonarlintAd() {
+    userSessionRule.logIn();
+
+    TestResponse testResponse = tester.newRequest()
+      .setParam("notice", "sonarlintAd")
+      .execute();
+
+    assertThat(testResponse.getStatus()).isEqualTo(204);
+
+    Optional<PropertyDto> propertyDto = db.properties().findFirstUserProperty(userSessionRule.getUuid(), "user.dismissedNotices.sonarlintAd");
+    assertThat(propertyDto).isPresent();
+  }
+
 
   @Test
   public void authentication_is_required() {
@@ -88,22 +102,23 @@ public class DismissNoticeActionTest {
 
     assertThatThrownBy(testRequest::execute)
       .isInstanceOf(IllegalArgumentException.class)
-      .hasMessage("Value of parameter 'notice' (not_supported_value) must be one of: [educationPrinciples]");
+      .hasMessage("Value of parameter 'notice' (not_supported_value) must be one of: [educationPrinciples, sonarlintAd]");
   }
 
 
   @Test
-  public void notice_already_exist() {
+  public void notice_already_exist_dont_fail() {
     userSessionRule.logIn();
     PropertyDto property = new PropertyDto().setKey("user.dismissedNotices.educationPrinciples").setUserUuid(userSessionRule.getUuid());
     db.properties().insertProperties(userSessionRule.getLogin(), null, null, null, property);
+    assertThat(db.properties().findFirstUserProperty(userSessionRule.getUuid(), "user.dismissedNotices.educationPrinciples")).isPresent();
 
-    TestRequest testRequest = tester.newRequest()
-      .setParam("notice", "educationPrinciples");
+    TestResponse testResponse = tester.newRequest()
+      .setParam("notice", "sonarlintAd")
+      .execute();
 
-    assertThatThrownBy(testRequest::execute)
-      .isInstanceOf(IllegalArgumentException.class)
-      .hasMessage("Notice educationPrinciples is already dismissed");
+    assertThat(testResponse.getStatus()).isEqualTo(204);
+    assertThat(db.properties().findFirstUserProperty(userSessionRule.getUuid(), "user.dismissedNotices.educationPrinciples")).isPresent();
   }
 
 
index 494016d9d2aca07b8927cd8819367ed0b6fd80b0..8b1a7b166e3bfa5a5806c7c1e098174cd5828e01 100644 (file)
@@ -40,13 +40,14 @@ public class DismissSonarlintAdActionTest {
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
 
-  private final WsActionTester tester = new WsActionTester(new DismissSonarlintAdAction(userSession, db.getDbClient()));
+  private final DismissNoticeAction dismissNoticeAction = new DismissNoticeAction(userSession, db.getDbClient());
+  private final WsActionTester underTest = new WsActionTester(new DismissSonarlintAdAction(userSession, dismissNoticeAction));
 
   @Test
   public void test_definition() {
-    WebService.Action definition = tester.getDef();
+    WebService.Action definition = underTest.getDef();
     assertThat(definition.key()).isEqualTo(ACTION_DISMISS_SONARLINT_AD);
-    assertThat(definition.description()).isEqualTo("Dismiss SonarLint advertisement.");
+    assertThat(definition.description()).isEqualTo("Dismiss SonarLint advertisement. Deprecated since 9.6, replaced api/users/dismiss_notice");
     assertThat(definition.since()).isEqualTo("9.2");
     assertThat(definition.isPost()).isTrue();
     assertThat(definition.params()).isEmpty();
@@ -55,7 +56,7 @@ public class DismissSonarlintAdActionTest {
 
   @Test
   public void endpoint_throw_exception_if_no_user_login() {
-    final TestRequest request = tester.newRequest();
+    final TestRequest request = underTest.newRequest();
     assertThatThrownBy(request::execute)
       .isInstanceOf(UnauthorizedException.class);
   }
@@ -67,10 +68,10 @@ public class DismissSonarlintAdActionTest {
       .setName("Obiwan Kenobi")
       .setEmail(null));
     userSession.logIn(user);
-    assertThat(user.isSonarlintAdSeen()).isFalse();
+    assertThat(db.properties().findFirstUserProperty(userSession.getUuid(), "user.dismissedNotices.sonarlintAd")).isEmpty();
 
-    tester.newRequest().execute();
+    underTest.newRequest().execute();
     UserDto updatedUser = db.users().selectUserByLogin(user.getLogin()).get();
-    assertThat(updatedUser.isSonarlintAdSeen()).isTrue();
+    assertThat(db.properties().findFirstUserProperty(userSession.getUuid(), "user.dismissedNotices.sonarlintAd")).isPresent();
   }
 }
index 0bdf172ec5c1646d28818ea90ec0802fea1cece3..f23de0edab844c593f401ec62aacd64780ee7ac5 100644 (file)
@@ -217,21 +217,6 @@ public class UsersService extends BaseService {
     ).content();
   }
 
-  /**
-   *
-   * This is part of the internal API.
-   * This is a POST request.
-   * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/dismiss_sonarlint_ad">Further information about this action online (including a response example)</a>
-   * @since 9.2
-   */
-  public void dismissSonarlintAd() {
-    call(
-      new PostRequest(path("dismiss_sonarlint_ad"))
-        .setMediaType(MediaTypes.JSON)
-    ).content();
-  }
-
-
   /**
    *
    * This is part of the internal API.
index 462aa020fc81b1e8d002495c9a0a6ec86835361d..cac3168f8d67dba7bbd3f7417a1825eaf9fa793e 100644 (file)
@@ -112,7 +112,7 @@ message CurrentWsResponse {
   optional Homepage homepage = 13;
   reserved 15; // settings removed
   optional bool usingSonarLintConnectedMode = 16;
-  optional bool sonarLintAdSeen = 17;
+  reserved 17; // sonarLintAdSeen removed
   map<string,bool> dismissedNotices = 18;
 
   message Permissions {