]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20156 Create api/dismiss_message/dismiss endpoint
authorNolwenn Cadic <98824442+Nolwenn-cadic-sonarsource@users.noreply.github.com>
Thu, 17 Aug 2023 10:15:05 +0000 (12:15 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 24 Aug 2023 20:03:06 +0000 (20:03 +0000)
36 files changed:
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/language/HandleUnanalyzedLanguagesStep.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/language/HandleUnanalyzedLanguagesStepTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/log/CeTaskMessages.java
server/sonar-db-dao/src/it/java/org/sonar/db/ce/CeActivityDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/ce/CeTaskMessageDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeCommandsIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
server/sonar-db-dao/src/it/java/org/sonar/db/user/UserDismissedMessagesDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageType.java [deleted file]
server/sonar-db-dao/src/main/java/org/sonar/db/dismissmessage/MessageType.java [new file with mode: 0644]
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDismissedMessageDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDismissedMessagesDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDismissedMessagesMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserDismissedMessagesMapper.xml
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/user/UserDbTester.java
server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java
server/sonar-webserver-core/src/it/java/org/sonar/server/startup/UpgradeSuggestionsCleanerIT.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/UpgradeSuggestionsCleaner.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ActivityActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/AnalysisStatusActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/ComponentActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/DismissAnalysisWarningActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/ws/TaskActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionIT.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionParameterizedIT.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/it/java/org/sonar/server/user/ws/DeactivateActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/DismissAnalysisWarningAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissAction.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissActionWs.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsAction.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsModule.java [new file with mode: 0644]
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/TaskFormatterTest.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java

index 1a97da5b50cba81c7783c417b690633cad2a8f1c..10959fb405ed58fde5b0f48c03430e21b29c6fed 100644 (file)
@@ -36,7 +36,7 @@ import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
 import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.core.platform.EditionProvider;
 import org.sonar.core.platform.PlatformEditionProvider;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 
 import static java.lang.String.format;
 import static org.sonar.core.language.UnanalyzedLanguages.C;
@@ -124,7 +124,7 @@ public class HandleUnanalyzedLanguagesStep implements ComputationStep {
     }
 
     String message = format(LANGUAGE_UPGRADE_MESSAGE, fileCountLabel, languageLabel, sortedLanguageMap.size() == 1 ? "this file" : "these files");
-    return new CeTaskMessages.Message(message, system.now(), CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    return new CeTaskMessages.Message(message, system.now(), MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
   }
 
   private void computeMeasures(Map<String, Integer> filesPerLanguage) {
index 0a72338702db0e8fd1d46364375362be45a826a8..1df4d69e30b361dd356ac0bc3cc32c071b8c4613 100644 (file)
@@ -40,7 +40,7 @@ import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
 import org.sonar.ce.task.step.TestComputationStepContext;
 import org.sonar.core.platform.EditionProvider;
 import org.sonar.core.platform.PlatformEditionProvider;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.scanner.protocol.output.ScannerReport;
 
 import static com.google.common.collect.ImmutableList.of;
@@ -112,7 +112,7 @@ public class HandleUnanalyzedLanguagesStepTest {
           " C++ and SomeLang cannot be analyzed with your current SonarQube edition. Please consider" +
           " <a target=\"_blank\" href=\"https://www.sonarqube.org/trial-request/developer-edition/?referrer=sonarqube-cpp\">upgrading to Developer Edition</a> to find Bugs," +
           " Code Smells, Vulnerabilities and Security Hotspots in these files.",
-        CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE));
+        MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE));
     assertThat(measureRepository.getAddedRawMeasure(PROJECT_REF, UNANALYZED_C_KEY).get().getIntValue()).isEqualTo(10);
     assertThat(measureRepository.getAddedRawMeasure(PROJECT_REF, UNANALYZED_CPP_KEY).get().getIntValue()).isEqualTo(20);
   }
index 15088a76fc5d4331038d5f26ff99c6576de2a876..d0c2a2c41807b9548d47f1b895402f0146ddf48e 100644 (file)
@@ -30,7 +30,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.sonar.ce.task.log.CeTaskMessages;
 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
 import org.sonar.ce.task.step.TestComputationStepContext;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.scanner.protocol.output.ScannerReport;
 
 import static com.google.common.collect.ImmutableList.of;
@@ -71,7 +71,7 @@ public class PersistAnalysisWarningsStepTest {
     verify(ceTaskMessages, times(1)).addAll(argumentCaptor.capture());
     assertThat(argumentCaptor.getValue())
       .extracting(CeTaskMessages.Message::getText, CeTaskMessages.Message::getType)
-      .containsExactly(tuple("warning 1", CeTaskMessageType.GENERIC), tuple("warning 2", CeTaskMessageType.GENERIC));
+      .containsExactly(tuple("warning 1", MessageType.GENERIC), tuple("warning 2", MessageType.GENERIC));
   }
 
   @Test
index 9c9ce465f6156f0c43aaf261a0d2d4fdb537e408..a90d92ece04a8daf4c289354ba06b1ab62fa58dc 100644 (file)
@@ -23,7 +23,7 @@ import java.util.Collection;
 import java.util.Objects;
 import javax.annotation.concurrent.Immutable;
 import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
@@ -49,9 +49,9 @@ public interface CeTaskMessages {
   class Message {
     private final String text;
     private final long timestamp;
-    private final CeTaskMessageType type;
+    private final MessageType type;
 
-    public Message(String text, long timestamp, CeTaskMessageType type) {
+    public Message(String text, long timestamp, MessageType type) {
       requireNonNull(text, "Text can't be null");
       checkArgument(!text.isEmpty(), "Text can't be empty");
       checkArgument(timestamp >= 0, "Timestamp can't be less than 0");
@@ -61,7 +61,7 @@ public interface CeTaskMessages {
     }
 
     public Message(String text, long timestamp) {
-      this(text, timestamp, CeTaskMessageType.GENERIC);
+      this(text, timestamp, MessageType.GENERIC);
     }
 
     public String getText() {
@@ -72,7 +72,7 @@ public interface CeTaskMessages {
       return timestamp;
     }
 
-    public CeTaskMessageType getType() {
+    public MessageType getType() {
       return type;
     }
 
index 1b3ff6f93d2259b23c9caf1232401c01c0df4a36..1b2def402079ff58f91529832be59e74d59d5582 100644 (file)
@@ -47,6 +47,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.Pagination;
 import org.sonar.db.component.BranchDto;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.project.ProjectDto;
 
 import static java.util.Collections.emptyList;
@@ -153,7 +154,7 @@ public class CeActivityDaoIT {
       .setUuid(UuidFactoryFast.getInstance().create())
       .setTaskUuid(task.getUuid())
       .setMessage("message_" + task.getUuid() + "_" + i)
-      .setType(CeTaskMessageType.GENERIC)
+      .setType(MessageType.GENERIC)
       .setCreatedAt(task.getUuid().hashCode() + i);
   }
 
index 0e5b6a295e7209d44f903bafbb219c0fb509b97d..6d16f66c0f3f952108f3d0b34ed05979fdc3a885 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Test;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.user.UserDto;
 
@@ -44,7 +45,7 @@ public class CeTaskMessageDaoIT {
       .setUuid("uuid_1")
       .setTaskUuid("task_uuid_1")
       .setMessage("message_1")
-      .setType(CeTaskMessageType.GENERIC)
+      .setType(MessageType.GENERIC)
       .setCreatedAt(1_222_333L));
     dbTester.getSession().commit();
 
@@ -52,9 +53,9 @@ public class CeTaskMessageDaoIT {
       dbTester.select("select uuid as \"UUID\", task_uuid as \"TASK_UUID\", message as \"MESSAGE\", message_type as \"TYPE\", " +
         "created_at as \"CREATED_AT\" from ce_task_message"))
           .hasSize(1)
-          .extracting(t -> t.get("UUID"), t -> t.get("TASK_UUID"), t -> t.get("MESSAGE"), t -> CeTaskMessageType.valueOf((String) t.get("TYPE")),
+          .extracting(t -> t.get("UUID"), t -> t.get("TASK_UUID"), t -> t.get("MESSAGE"), t -> MessageType.valueOf((String) t.get("TYPE")),
             t -> t.get("CREATED_AT"))
-          .containsOnly(Tuple.tuple("uuid_1", "task_uuid_1", "message_1", CeTaskMessageType.GENERIC, 1_222_333L));
+          .containsOnly(Tuple.tuple("uuid_1", "task_uuid_1", "message_1", MessageType.GENERIC, 1_222_333L));
   }
 
   @Test
@@ -78,13 +79,13 @@ public class CeTaskMessageDaoIT {
   public void deleteByType_deletes_messages_of_given_type() {
     String task1 = "task1";
     CeTaskMessageDto[] messages = {
-      insertMessage(task1, 0, 1_222_333L, CeTaskMessageType.GENERIC),
-      insertMessage(task1, 1, 2_222_333L, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE),
-      insertMessage(task1, 2, 1_111_333L, CeTaskMessageType.GENERIC),
-      insertMessage(task1, 3, 1_222_111L, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE)
+      insertMessage(task1, 0, 1_222_333L, MessageType.GENERIC),
+      insertMessage(task1, 1, 2_222_333L, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE),
+      insertMessage(task1, 2, 1_111_333L, MessageType.GENERIC),
+      insertMessage(task1, 3, 1_222_111L, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE)
     };
 
-    underTest.deleteByType(dbTester.getSession(), CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    underTest.deleteByType(dbTester.getSession(), MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     assertThat(underTest.selectByUuid(dbTester.getSession(), messages[0].getUuid())).isPresent();
     assertThat(underTest.selectByUuid(dbTester.getSession(), messages[1].getUuid())).isEmpty();
@@ -106,10 +107,10 @@ public class CeTaskMessageDaoIT {
   public void selectNonDismissedByUserAndTask_returns_non_dismissed_messages() {
     UserDto user = dbTester.users().insertUser();
     ProjectDto project = dbTester.components().insertPrivateProject().getProjectDto();
-    dbTester.users().insertUserDismissedMessage(user, project, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    dbTester.users().insertUserDismissedMessageOnProject(user, project, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
     String taskUuid = "17ae66e6-fe83-4c80-b704-4b04e9c5abe8";
     CeTaskMessageDto msg1 = insertMessage(taskUuid, 1, 1_222_333L);
-    insertMessage(taskUuid, 2, 1_222_334L, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    insertMessage(taskUuid, 2, 1_222_334L, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
     CeTaskMessageDto msg3 = insertMessage(taskUuid, 3, 1_222_335L);
     List<CeTaskMessageDto> messages = underTest.selectNonDismissedByUserAndTask(dbTester.getSession(), taskUuid, user.getUuid());
 
@@ -118,10 +119,10 @@ public class CeTaskMessageDaoIT {
   }
 
   private CeTaskMessageDto insertMessage(String taskUuid, int i, long createdAt) {
-    return insertMessage(taskUuid, i, createdAt, CeTaskMessageType.GENERIC);
+    return insertMessage(taskUuid, i, createdAt, MessageType.GENERIC);
   }
 
-  private CeTaskMessageDto insertMessage(String taskUuid, int i, long createdAt, CeTaskMessageType messageType) {
+  private CeTaskMessageDto insertMessage(String taskUuid, int i, long createdAt, MessageType messageType) {
     CeTaskMessageDto res = new CeTaskMessageDto()
       .setUuid("message_" + i)
       .setTaskUuid(taskUuid)
index b89a854e0090b7795a5a630f93d91920dfb0c6a1..890a6f81ee78f6aa9ee5950b37e1f9dc312d485f 100644 (file)
@@ -42,7 +42,7 @@ import org.sonar.api.issue.impact.SoftwareQuality;
 import org.sonar.api.utils.System2;
 import org.sonar.core.util.UuidFactoryFast;
 import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
@@ -702,9 +702,9 @@ public class PurgeCommandsIT {
     UserDto user2 = dbTester.users().insertUser();
     ProjectDto project = dbTester.components().insertPrivateProject().getProjectDto();
     ProjectDto anotherProject = dbTester.components().insertPrivateProject().getProjectDto();
-    dbTester.users().insertUserDismissedMessage(user1, project, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    dbTester.users().insertUserDismissedMessage(user2, project, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    dbTester.users().insertUserDismissedMessage(user1, anotherProject, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    dbTester.users().insertUserDismissedMessageOnProject(user1, project, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    dbTester.users().insertUserDismissedMessageOnProject(user2, project, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    dbTester.users().insertUserDismissedMessageOnProject(user1, anotherProject, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
     PurgeCommands purgeCommands = new PurgeCommands(dbTester.getSession(), profiler, system2);
 
     purgeCommands.deleteUserDismissedMessages(project.getUuid());
index 5fa203103b0e1ce534c07f61fb20e395e77a4a19..808bb724f1259e3b777c41e8096caa90f735bdab 100644 (file)
@@ -62,7 +62,7 @@ import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeQueueDto.Status;
 import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.BranchType;
@@ -910,9 +910,9 @@ public class PurgeDaoIT {
     ProjectDto project = db.components().insertPrivateProject().getProjectDto();
     ProjectDto anotherProject = db.components().insertPrivateProject().getProjectDto();
 
-    UserDismissedMessageDto msg1 = db.users().insertUserDismissedMessage(user1, project, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    UserDismissedMessageDto msg2 = db.users().insertUserDismissedMessage(user2, project, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessage(user1, anotherProject, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg1 = db.users().insertUserDismissedMessageOnProject(user1, project, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg2 = db.users().insertUserDismissedMessageOnProject(user2, project, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessageOnProject(user1, anotherProject, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     assertThat(uuidsIn("user_dismissed_messages")).containsOnly(msg1.getUuid(), msg2.getUuid(), msg3.getUuid());
 
@@ -2002,7 +2002,7 @@ public class PurgeDaoIT {
         .setUuid(UuidFactoryFast.getInstance().create())
         .setTaskUuid(uuid)
         .setMessage("key_" + uuid.hashCode() + i)
-        .setType(CeTaskMessageType.GENERIC)
+        .setType(MessageType.GENERIC)
         .setCreatedAt(2_333_444L + i))
       .forEach(dto -> dbClient.ceTaskMessageDao().insert(dbSession, dto));
     dbSession.commit();
index 1746aa2caceaa23af310691e12560cc468ad0893..aabd4617f56fd02697c43f5253dc501a873bb389 100644 (file)
@@ -26,12 +26,12 @@ import org.junit.Test;
 import org.sonar.api.utils.System2;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.project.ProjectDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.db.ce.CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE;
+import static org.sonar.db.dismissmessage.MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE;
 
 public class UserDismissedMessagesDaoIT {
 
@@ -48,13 +48,13 @@ public class UserDismissedMessagesDaoIT {
 
     underTest.insert(db.getSession(), dto);
 
-    Optional<UserDismissedMessageDto> dtoFromDb = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user, project, dto.getCeMessageType());
+    Optional<UserDismissedMessageDto> dtoFromDb = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user.getUuid(), project, dto.getMessageType());
     assertThat(dtoFromDb).isPresent();
     assertThat(dtoFromDb.get().getUuid()).isEqualTo(dto.getUuid());
     assertThat(dtoFromDb.get().getUserUuid()).isEqualTo(dto.getUserUuid());
     assertThat(dtoFromDb.get().getProjectUuid()).isEqualTo(dto.getProjectUuid());
-    assertThat(dtoFromDb.get().getCeMessageType()).isEqualTo(dto.getCeMessageType());
-    assertThat(dtoFromDb.get().getCeMessageType().isDismissible()).isEqualTo(dto.getCeMessageType().isDismissible());
+    assertThat(dtoFromDb.get().getMessageType()).isEqualTo(dto.getMessageType());
+    assertThat(dtoFromDb.get().getMessageType().isDismissible()).isEqualTo(dto.getMessageType().isDismissible());
     assertThat(dtoFromDb.get().getCreatedAt()).isEqualTo(dto.getCreatedAt());
   }
 
@@ -62,23 +62,36 @@ public class UserDismissedMessagesDaoIT {
   public void selectByUserAndProjectAndMessageType_returns_object_if_record_found() {
     UserDto user = db.users().insertUser();
     ProjectDto project = db.components().insertPrivateProject().getProjectDto();
-    db.users().insertUserDismissedMessage(user, project, CeTaskMessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user, project, MessageType.GENERIC);
 
-    Optional<UserDismissedMessageDto> result = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user, project, CeTaskMessageType.GENERIC);
+    Optional<UserDismissedMessageDto> result = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user.getUuid(), project, MessageType.GENERIC);
 
     assertThat(result).isPresent();
     assertThat(result.get().getUserUuid()).isEqualTo(user.getUuid());
     assertThat(result.get().getProjectUuid()).isEqualTo(project.getUuid());
-    assertThat(result.get().getCeMessageType()).isEqualTo(CeTaskMessageType.GENERIC);
+    assertThat(result.get().getMessageType()).isEqualTo(MessageType.GENERIC);
+  }
+
+  @Test
+  public void selectByUserAndMessageType_returns_object_if_record_found() {
+    UserDto user = db.users().insertUser();
+    db.users().insertUserDismissedMessageOnInstance(user, MessageType.GENERIC);
+
+    Optional<UserDismissedMessageDto> result = underTest.selectByUserUuidAndMessageType(db.getSession(), user.getUuid(),MessageType.GENERIC);
+
+    assertThat(result).isPresent();
+    assertThat(result.get().getUserUuid()).isEqualTo(user.getUuid());
+    assertThat(result.get().getProjectUuid()).isNull();
+    assertThat(result.get().getMessageType()).isEqualTo(MessageType.GENERIC);
   }
 
   @Test
   public void selectByUserAndProjectAndMessageType_returns_absent_if_no_record_found() {
     UserDto user = db.users().insertUser();
     ProjectDto project = db.components().insertPrivateProject().getProjectDto();
-    db.users().insertUserDismissedMessage(user, project, CeTaskMessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user, project, MessageType.GENERIC);
 
-    Optional<UserDismissedMessageDto> result = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user, project, SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    Optional<UserDismissedMessageDto> result = underTest.selectByUserAndProjectAndMessageType(db.getSession(), user.getUuid(), project, SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     assertThat(result).isNotPresent();
   }
@@ -89,19 +102,19 @@ public class UserDismissedMessagesDaoIT {
     UserDto user2 = db.users().insertUser();
     ProjectDto project1 = db.components().insertPrivateProject().getProjectDto();
     ProjectDto project2 = db.components().insertPrivateProject().getProjectDto();
-    db.users().insertUserDismissedMessage(user1, project1, CeTaskMessageType.GENERIC);
-    db.users().insertUserDismissedMessage(user1, project2, CeTaskMessageType.GENERIC);
-    UserDismissedMessageDto dto1 = db.users().insertUserDismissedMessage(user2, project1, CeTaskMessageType.GENERIC);
-    UserDismissedMessageDto dto2 = db.users().insertUserDismissedMessage(user2, project2, CeTaskMessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user1, project1, MessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user1, project2, MessageType.GENERIC);
+    UserDismissedMessageDto dto1 = db.users().insertUserDismissedMessageOnProject(user2, project1, MessageType.GENERIC);
+    UserDismissedMessageDto dto2 = db.users().insertUserDismissedMessageOnProject(user2, project2, MessageType.GENERIC);
 
     List<UserDismissedMessageDto> result = underTest.selectByUser(db.getSession(), user2);
 
     assertThat(result).hasSize(2);
     assertThat(result).extracting(UserDismissedMessageDto::getUuid, UserDismissedMessageDto::getUserUuid, UserDismissedMessageDto::getProjectUuid,
-      UserDismissedMessageDto::getCeMessageType)
+      UserDismissedMessageDto::getMessageType)
       .containsExactlyInAnyOrder(
-        tuple(dto1.getUuid(), user2.getUuid(), project1.getUuid(), CeTaskMessageType.GENERIC),
-        tuple(dto2.getUuid(), user2.getUuid(), project2.getUuid(), CeTaskMessageType.GENERIC));
+        tuple(dto1.getUuid(), user2.getUuid(), project1.getUuid(), MessageType.GENERIC),
+        tuple(dto2.getUuid(), user2.getUuid(), project2.getUuid(), MessageType.GENERIC));
   }
 
   @Test
@@ -110,10 +123,10 @@ public class UserDismissedMessagesDaoIT {
     UserDto user2 = db.users().insertUser();
     ProjectDto project1 = db.components().insertPrivateProject().getProjectDto();
     ProjectDto project2 = db.components().insertPrivateProject().getProjectDto();
-    db.users().insertUserDismissedMessage(user1, project1, CeTaskMessageType.GENERIC);
-    db.users().insertUserDismissedMessage(user1, project2, CeTaskMessageType.GENERIC);
-    db.users().insertUserDismissedMessage(user2, project1, CeTaskMessageType.GENERIC);
-    db.users().insertUserDismissedMessage(user2, project2, CeTaskMessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user1, project1, MessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user1, project2, MessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user2, project1, MessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user2, project2, MessageType.GENERIC);
 
     underTest.deleteByUser(db.getSession(), user2);
 
@@ -127,10 +140,10 @@ public class UserDismissedMessagesDaoIT {
     UserDto user2 = db.users().insertUser();
     ProjectDto project1 = db.components().insertPrivateProject().getProjectDto();
     ProjectDto project2 = db.components().insertPrivateProject().getProjectDto();
-    UserDismissedMessageDto dto1 = db.users().insertUserDismissedMessage(user1, project1, CeTaskMessageType.GENERIC);
-    db.users().insertUserDismissedMessage(user1, project2, SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    db.users().insertUserDismissedMessage(user2, project1, SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    UserDismissedMessageDto dto2 = db.users().insertUserDismissedMessage(user2, project2, CeTaskMessageType.GENERIC);
+    UserDismissedMessageDto dto1 = db.users().insertUserDismissedMessageOnProject(user1, project1, MessageType.GENERIC);
+    db.users().insertUserDismissedMessageOnProject(user1, project2, SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    db.users().insertUserDismissedMessageOnProject(user2, project1, SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto dto2 = db.users().insertUserDismissedMessageOnProject(user2, project2, MessageType.GENERIC);
 
     underTest.deleteByType(db.getSession(), SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
@@ -145,7 +158,7 @@ public class UserDismissedMessagesDaoIT {
   public static UserDismissedMessageDto newDto(ProjectDto project, UserDto user) {
     return new UserDismissedMessageDto()
       .setUuid(Uuids.createFast())
-      .setCeMessageType(CeTaskMessageType.GENERIC)
+      .setMessageType(MessageType.GENERIC)
       .setUserUuid(user.getUuid())
       .setProjectUuid(project.getUuid());
   }
index 588827cef606161c3acf9ba711ed3e1e2a96ef10..89d1b36e044ee770e0d0296ee518b19c8c9e4e8d 100644 (file)
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Optional;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
+import org.sonar.db.dismissmessage.MessageType;
 
 public class CeTaskMessageDao implements Dao {
   public void insert(DbSession dbSession, CeTaskMessageDto dto) {
@@ -41,7 +42,7 @@ public class CeTaskMessageDao implements Dao {
     return getMapper(dbSession).selectNonDismissedByUserAndTask(taskUuid, userUuid);
   }
 
-  public void deleteByType(DbSession session, CeTaskMessageType type) {
+  public void deleteByType(DbSession session, MessageType type) {
     getMapper(session).deleteByType(type.name());
   }
 
index 1b3b710fa81e010611a57cfb95a61a69c2e49cc7..52831188c2bd0098cc809b4042ad68b64c86f923 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.db.ce;
 
 import com.google.common.annotations.VisibleForTesting;
+import org.sonar.db.dismissmessage.MessageType;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.apache.commons.lang.StringUtils.abbreviate;
@@ -35,19 +36,25 @@ public class CeTaskMessageDto {
    * UUID of the task the message belongs to. Not null
    */
   private String taskUuid;
+
   /**
    * The text of the message. Not null
    */
   private String message;
+
   /**
    * Type of the message
    */
-  private CeTaskMessageType type;
+  private MessageType type;
   /**
    * Timestamp the message was created. Not null
    */
   private long createdAt;
 
+  public CeTaskMessageDto() {
+    //Nothing to do
+  }
+
   public String getUuid() {
     return uuid;
   }
@@ -76,11 +83,11 @@ public class CeTaskMessageDto {
     return this;
   }
 
-  public CeTaskMessageType getType() {
+  public MessageType getType() {
     return type;
   }
 
-  public CeTaskMessageDto setType(CeTaskMessageType type) {
+  public CeTaskMessageDto setType(MessageType type) {
     this.type = type;
     return this;
   }
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageType.java b/server/sonar-db-dao/src/main/java/org/sonar/db/ce/CeTaskMessageType.java
deleted file mode 100644 (file)
index da7a1dd..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.db.ce;
-
-public enum CeTaskMessageType {
-  INFO(false, false),
-  GENERIC(false, true),
-  SUGGEST_DEVELOPER_EDITION_UPGRADE(true, true);
-
-  private final boolean dismissible;
-  private final boolean isWarning;
-
-  CeTaskMessageType(boolean dismissible, boolean isWarning) {
-    this.dismissible = dismissible;
-    this.isWarning = isWarning;
-  }
-
-  public boolean isDismissible() {
-    return dismissible;
-  }
-
-  public boolean isWarning() {
-    return isWarning;
-  }
-}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/dismissmessage/MessageType.java b/server/sonar-db-dao/src/main/java/org/sonar/db/dismissmessage/MessageType.java
new file mode 100644 (file)
index 0000000..8a48282
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.db.dismissmessage;
+
+public enum MessageType {
+  INFO(false, false),
+  GENERIC(false, true),
+  SUGGEST_DEVELOPER_EDITION_UPGRADE(true, true),
+  GLOBAL_NCD_90(true, false),
+  GLOBAL_NCD_PAGE_90(true, false),
+  PROJECT_NCD_90(true, false),
+  PROJECT_NCD_PAGE_90(true, false),
+  BRANCH_NCD_90(true, false);
+
+  private final boolean dismissible;
+  private final boolean isWarning;
+
+  MessageType(boolean dismissible, boolean isWarning) {
+    this.dismissible = dismissible;
+    this.isWarning = isWarning;
+  }
+
+  public boolean isDismissible() {
+    return dismissible;
+  }
+
+  public boolean isWarning() {
+    return isWarning;
+  }
+}
index 26db8577a53854e2cea663cc7a5e1293dcabd9d7..c2154f076fe0128f37e18a7f07f59c778b1d12ba 100644 (file)
@@ -19,7 +19,9 @@
  */
 package org.sonar.db.user;
 
-import org.sonar.db.ce.CeTaskMessageType;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.dismissmessage.MessageType;
 
 public class UserDismissedMessageDto {
 
@@ -31,11 +33,12 @@ public class UserDismissedMessageDto {
   /**
    * Uuid of the project for which the message type was dismissed
    */
+  @CheckForNull
   private String projectUuid;
   /**
    * Message type of the dismissed message
    */
-  private CeTaskMessageType ceMessageType;
+  private MessageType messageType;
   /**
    * Technical creation date
    */
@@ -67,17 +70,17 @@ public class UserDismissedMessageDto {
     return projectUuid;
   }
 
-  public UserDismissedMessageDto setProjectUuid(String projectUuid) {
+  public UserDismissedMessageDto setProjectUuid(@Nullable String projectUuid) {
     this.projectUuid = projectUuid;
     return this;
   }
 
-  public CeTaskMessageType getCeMessageType() {
-    return ceMessageType;
+  public MessageType getMessageType() {
+    return messageType;
   }
 
-  public UserDismissedMessageDto setCeMessageType(CeTaskMessageType ceMessageType) {
-    this.ceMessageType = ceMessageType;
+  public UserDismissedMessageDto setMessageType(MessageType messageType) {
+    this.messageType = messageType;
     return this;
   }
 
index b1b4ba41cc81a1bcd606c868999a31e09714ff28..577567e54e63bec617a67cc583434d5b0597fb9b 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Optional;
 import org.sonar.api.utils.System2;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.project.ProjectDto;
 
 public class UserDismissedMessagesDao implements Dao {
@@ -40,9 +40,14 @@ public class UserDismissedMessagesDao implements Dao {
     return dto;
   }
 
-  public Optional<UserDismissedMessageDto> selectByUserAndProjectAndMessageType(DbSession session, UserDto user, ProjectDto project,
-    CeTaskMessageType ceMessageType) {
-    return mapper(session).selectByUserUuidAndProjectUuidAndMessageType(user.getUuid(), project.getUuid(), ceMessageType.name());
+  public Optional<UserDismissedMessageDto> selectByUserAndProjectAndMessageType(DbSession session, String userUuid, ProjectDto project,
+    MessageType messageType) {
+    return mapper(session).selectByUserUuidAndProjectUuidAndMessageType(userUuid, project.getUuid(), messageType.name());
+  }
+
+  public Optional<UserDismissedMessageDto> selectByUserUuidAndMessageType(DbSession session, String userUuid,
+    MessageType messageType) {
+    return mapper(session).selectByUserUuidAndMessageType(userUuid, messageType.name());
   }
 
   public List<UserDismissedMessageDto> selectByUser(DbSession session, UserDto user) {
@@ -53,7 +58,7 @@ public class UserDismissedMessagesDao implements Dao {
     mapper(session).deleteByUserUuid(user.getUuid());
   }
 
-  public void deleteByType(DbSession session, CeTaskMessageType type) {
+  public void deleteByType(DbSession session, MessageType type) {
     mapper(session).deleteByType(type.name());
   }
 
index 367ae5b5f9db0659b236004542fed6cbe9b4f739..0f27dd75cd720861a064d2bfc5a1045b123a2ab4 100644 (file)
@@ -27,11 +27,13 @@ public interface UserDismissedMessagesMapper {
   void insert(@Param("dto") UserDismissedMessageDto dto);
 
   Optional<UserDismissedMessageDto> selectByUserUuidAndProjectUuidAndMessageType(@Param("userUuid") String userUuid, @Param("projectUuid") String projectUuid,
-    @Param("ceMessageType") String ceMessageType);
+    @Param("messageType") String messageType);
+
+  Optional<UserDismissedMessageDto> selectByUserUuidAndMessageType(@Param("userUuid") String userUuid, @Param("messageType") String messageType);
 
   List<UserDismissedMessageDto> selectByUserUuid(@Param("userUuid") String userUuid);
 
   void deleteByUserUuid(@Param("userUuid") String userUuid);
 
-  void deleteByType(@Param("ceMessageType") String ceMessageType);
+  void deleteByType(@Param("messageType") String messageType);
 }
index 12fad9f464354d7c82e31259f9f2b80ecbc83c76..bf10b1759074d85844ba3deb4226189eeac0efe0 100644 (file)
@@ -7,7 +7,7 @@
     udm.uuid,
     udm.user_uuid as userUuid,
     udm.project_uuid as projectUuid,
-    udm.message_type as ceMessageType,
+    udm.message_type as messageType,
     udm.created_at as createdAt
   </sql>
 
@@ -24,7 +24,7 @@
       #{dto.uuid,jdbcType=VARCHAR},
       #{dto.userUuid,jdbcType=VARCHAR},
       #{dto.projectUuid,jdbcType=VARCHAR},
-      #{dto.ceMessageType,jdbcType=VARCHAR},
+      #{dto.messageType,jdbcType=VARCHAR},
       #{dto.createdAt,jdbcType=BIGINT}
     )
   </insert>
     where
       udm.user_uuid=#{userUuid,jdbcType=VARCHAR} and
       udm.project_uuid=#{projectUuid,jdbcType=VARCHAR} and
-      udm.message_type=#{ceMessageType,jdbcType=VARCHAR}
+      udm.message_type=#{messageType,jdbcType=VARCHAR}
   </select>
 
-    <select id="selectByUserUuid" resultType="org.sonar.db.user.UserDismissedMessageDto" parameterType="String">
+  <select id="selectByUserUuidAndMessageType" resultType="org.sonar.db.user.UserDismissedMessageDto">
+    select
+      <include refid="columns"/>
+    from
+      user_dismissed_messages udm
+    where
+      udm.user_uuid=#{userUuid,jdbcType=VARCHAR} and
+      udm.message_type=#{messageType,jdbcType=VARCHAR}
+  </select>
+
+  <select id="selectByUserUuid" resultType="org.sonar.db.user.UserDismissedMessageDto" parameterType="String">
     select
       <include refid="columns"/>
     from
@@ -54,7 +64,7 @@
   </delete>
 
   <delete id="deleteByType" parameterType="String">
-    delete from user_dismissed_messages where message_type = #{ceMessageType, jdbcType=VARCHAR}
+    delete from user_dismissed_messages where message_type = #{messageType, jdbcType=VARCHAR}
   </delete>
 
 </mapper>
index db69a16773f309da948894b523c7d355c2f5bd04..c10acd666b60590542884cbb4b766f9cd125e74f 100644 (file)
@@ -32,7 +32,7 @@ import org.sonar.api.web.UserRole;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.entity.EntityDto;
@@ -489,12 +489,22 @@ public class UserDbTester {
     return dto;
   }
 
-  public final UserDismissedMessageDto insertUserDismissedMessage(UserDto userDto, ProjectDto projectDto, CeTaskMessageType messageType) {
+  public final UserDismissedMessageDto insertUserDismissedMessageOnProject(UserDto userDto, ProjectDto projectDto, MessageType messageType) {
     UserDismissedMessageDto dto = new UserDismissedMessageDto()
       .setUuid(Uuids.create())
       .setUserUuid(userDto.getUuid())
       .setProjectUuid(projectDto.getUuid())
-      .setCeMessageType(messageType);
+      .setMessageType(messageType);
+    db.getDbClient().userDismissedMessagesDao().insert(db.getSession(), dto);
+    db.commit();
+    return dto;
+  }
+
+  public final UserDismissedMessageDto insertUserDismissedMessageOnInstance(UserDto userDto, MessageType messageType) {
+    UserDismissedMessageDto dto = new UserDismissedMessageDto()
+      .setUuid(Uuids.create())
+      .setUserUuid(userDto.getUuid())
+      .setMessageType(messageType);
     db.getDbClient().userDismissedMessagesDao().insert(db.getSession(), dto);
     db.commit();
     return dto;
index 29d711b5d99d11f99556ca104eb6239807692a8d..80d881fb26f99756380e6878cccbb72bd0cfb99b 100644 (file)
@@ -38,7 +38,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.alm.setting.AlmSettingDto;
 import org.sonar.db.audit.NoOpAuditPersister;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.permission.template.PermissionTemplateDto;
@@ -617,11 +617,11 @@ public class UserServiceIT {
     ProjectDto project2 = db.components().insertPrivateProject().getProjectDto();
     UserDto user = db.users().insertUser();
 
-    db.users().insertUserDismissedMessage(user, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    db.users().insertUserDismissedMessage(user, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    db.users().insertUserDismissedMessageOnProject(user, project1, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    db.users().insertUserDismissedMessageOnProject(user, project2, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
     UserDto anotherUser = db.users().insertUser();
-    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessage(anotherUser, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    UserDismissedMessageDto msg4 = db.users().insertUserDismissedMessage(anotherUser, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessageOnProject(anotherUser, project1, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg4 = db.users().insertUserDismissedMessageOnProject(anotherUser, project2, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     userService.deactivate(user.getLogin(), false);
 
index b621a7e8238ae2fcf504774a9802cbc43c8bb362..4940f511519d070f68d6c7f71beb3ade0a9e08d6 100644 (file)
@@ -34,7 +34,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.user.UserDismissedMessageDto;
 import org.sonar.db.user.UserDto;
 
@@ -83,11 +83,11 @@ public class UpgradeSuggestionsCleanerIT {
   public void start_cleans_up_obsolete_upgrade_suggestions(SonarEdition edition) {
     when(sonarRuntime.getEdition()).thenReturn(edition);
     insertTask(TASK_UUID);
-    insertCeTaskMessage("ctm1", CeTaskMessageType.GENERIC, "msg1");
-    insertCeTaskMessage("ctm2", CeTaskMessageType.GENERIC, "msg2");
-    insertCeTaskMessage("ctm3", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE, "upgrade-msg-1");
-    insertInUserDismissedMessages("u1", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    insertInUserDismissedMessages("u2", CeTaskMessageType.GENERIC);
+    insertCeTaskMessage("ctm1", MessageType.GENERIC, "msg1");
+    insertCeTaskMessage("ctm2", MessageType.GENERIC, "msg2");
+    insertCeTaskMessage("ctm3", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE, "upgrade-msg-1");
+    insertInUserDismissedMessages("u1", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    insertInUserDismissedMessages("u2", MessageType.GENERIC);
 
     underTest.start();
     underTest.stop();
@@ -104,11 +104,11 @@ public class UpgradeSuggestionsCleanerIT {
   public void start_does_nothing_in_community_edition() {
     when(sonarRuntime.getEdition()).thenReturn(SonarEdition.COMMUNITY);
     insertTask(TASK_UUID);
-    insertCeTaskMessage("ctm1", CeTaskMessageType.GENERIC, "msg1");
-    insertCeTaskMessage("ctm2", CeTaskMessageType.GENERIC, "msg2");
-    insertCeTaskMessage("ctm3", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE, "upgrade-msg-1");
-    insertInUserDismissedMessages("u1", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    insertInUserDismissedMessages("u2", CeTaskMessageType.GENERIC);
+    insertCeTaskMessage("ctm1", MessageType.GENERIC, "msg1");
+    insertCeTaskMessage("ctm2", MessageType.GENERIC, "msg2");
+    insertCeTaskMessage("ctm3", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE, "upgrade-msg-1");
+    insertInUserDismissedMessages("u1", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    insertInUserDismissedMessages("u2", MessageType.GENERIC);
 
     underTest.start();
 
@@ -140,7 +140,7 @@ public class UpgradeSuggestionsCleanerIT {
       new CeActivityDto(new CeQueueDto().setUuid(taskUuid).setTaskType("ISSUE_SYNC")).setStatus(CeActivityDto.Status.FAILED));
   }
 
-  private void insertCeTaskMessage(String uuid, CeTaskMessageType messageType, String msg) {
+  private void insertCeTaskMessage(String uuid, MessageType messageType, String msg) {
     CeTaskMessageDto dto = new CeTaskMessageDto()
       .setUuid(uuid)
       .setMessage(msg)
@@ -150,12 +150,12 @@ public class UpgradeSuggestionsCleanerIT {
     dbTester.getSession().commit();
   }
 
-  private void insertInUserDismissedMessages(String uuid, CeTaskMessageType messageType) {
+  private void insertInUserDismissedMessages(String uuid, MessageType messageType) {
     UserDismissedMessageDto dto = new UserDismissedMessageDto()
       .setUuid(uuid)
       .setUserUuid(user.getUuid())
       .setProjectUuid("PROJECT_1")
-      .setCeMessageType(messageType);
+      .setMessageType(messageType);
     dbTester.getDbClient().userDismissedMessagesDao().insert(dbTester.getSession(), dto);
     dbTester.getSession().commit();
   }
index 8dbd9a916ae2408d4c5c19c653c98d0ac89aec6b..535ff838ea9d615d7217580adb943b176fca77ea 100644 (file)
@@ -27,7 +27,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 
 /**
  * Clean up messages (like removing upgrade suggestions after an edition upgrade)
@@ -57,8 +57,8 @@ public class UpgradeSuggestionsCleaner implements Startable {
   private void deleteUpgradeMessageDismissals() {
     LOGGER.info("Dismissed messages cleanup");
     try (DbSession dbSession = dbClient.openSession(false)) {
-      dbClient.userDismissedMessagesDao().deleteByType(dbSession, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-      dbClient.ceTaskMessageDao().deleteByType(dbSession, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+      dbClient.userDismissedMessagesDao().deleteByType(dbSession, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+      dbClient.ceTaskMessageDao().deleteByType(dbSession, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
       dbSession.commit();
     }
   }
index fc866c680e037bebbbf7b2432e9ba66cc8fbaae2..f1ce1fe1834528e0a2c2288613f61fdcba28d428 100644 (file)
@@ -37,7 +37,7 @@ import org.sonar.db.ce.CeActivityDto.Status;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.BranchType;
 import org.sonar.db.component.ComponentDto;
@@ -268,7 +268,7 @@ public class ActivityActionIT {
         .setUuid("uuid_" + taskUuid + "_" + i)
         .setTaskUuid(taskUuid)
         .setMessage("m_" + taskUuid + "_" + i)
-        .setType(CeTaskMessageType.GENERIC)
+        .setType(MessageType.GENERIC)
         .setCreatedAt(taskUuid.hashCode() + i))
       .toList();
 
index 5cfe22c349fdb427f5e64bf9fb0d25bab31959fe..02a743353ec7c9e28caf4802e25007fd31e60cfd 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.BranchType;
 import org.sonar.db.component.ProjectData;
@@ -93,7 +93,7 @@ public class AnalysisStatusActionIT {
     SnapshotDto analysis = db.components().insertSnapshot(project);
     CeActivityDto activity = insertActivity("task-uuid" + counter++, projectData.getMainBranchDto(), SUCCESS, analysis, REPORT);
     createTaskMessage(activity, WARNING_IN_MAIN);
-    createTaskMessage(activity, "Dismissible warning", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    createTaskMessage(activity, "Dismissible warning", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     Ce.AnalysisStatusWsResponse response = ws.newRequest()
       .setParam(PARAM_COMPONENT, project.getKey())
@@ -111,7 +111,7 @@ public class AnalysisStatusActionIT {
     SnapshotDto analysis = db.components().insertSnapshot(project);
     CeActivityDto activity = insertActivity("task-uuid" + counter++, projectData.getMainBranchDto(), SUCCESS, analysis, REPORT);
     CeTaskMessageDto taskMessage = createTaskMessage(activity, WARNING_IN_MAIN);
-    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "Dismissible warning", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "Dismissible warning", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     Ce.AnalysisStatusWsResponse response = ws.newRequest()
       .setParam(PARAM_COMPONENT, project.getKey())
@@ -307,7 +307,7 @@ public class AnalysisStatusActionIT {
       .setUuid("AU-Tpxb--iU5OvuD2FLy")
       .setTaskUuid(activity.getUuid())
       .setMessage("Property \"sonar.jacoco.reportPaths\" is no longer supported. Use JaCoCo xml report and sonar-jacoco plugin.")
-      .setType(CeTaskMessageType.GENERIC)
+      .setType(MessageType.GENERIC)
       .setCreatedAt(counter);
     db.getDbClient().ceTaskMessageDao().insert(db.getSession(), ceTaskMessage);
     db.commit();
@@ -348,10 +348,10 @@ public class AnalysisStatusActionIT {
   }
 
   private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning) {
-    return createTaskMessage(activity, warning, CeTaskMessageType.GENERIC);
+    return createTaskMessage(activity, warning, MessageType.GENERIC);
   }
 
-  private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning, CeTaskMessageType messageType) {
+  private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning, MessageType messageType) {
     CeTaskMessageDto ceTaskMessageDto = new CeTaskMessageDto()
       .setUuid("m-uuid-" + counter++)
       .setTaskUuid(activity.getUuid())
index 2018a1b80ba1fe1d0acc05fbd62925ba2da7fe41..ec9046cefa0d9dc2f1894dc5094c0e1158337302 100644 (file)
@@ -33,7 +33,7 @@ import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ProjectData;
@@ -259,7 +259,7 @@ public class ComponentActionIT {
         .setUuid("uuid_" + i)
         .setTaskUuid(activity.getUuid())
         .setMessage("m_" + i)
-        .setType(CeTaskMessageType.GENERIC)
+        .setType(MessageType.GENERIC)
         .setCreatedAt(i))
       .toList();
 
index 6f7c2edea43107605fb5c7ffaf4288ae5194500a..cad9b42797dd5683254d0165290eee983940fd22 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ProjectData;
 import org.sonar.db.component.SnapshotDto;
@@ -46,8 +46,8 @@ import org.sonar.server.ws.WsActionTester;
 
 import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.Assertions.tuple;
-import static org.junit.Assert.assertThrows;
 import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
 import static org.sonar.db.ce.CeTaskTypes.REPORT;
 
@@ -80,7 +80,9 @@ public class DismissAnalysisWarningActionIT {
       .setParam("component", "6653f062-7c03-4b55-bcd2-0dac67640c4d")
       .setParam("warning", "55c40b35-4145-4b78-bdf2-dfb242c25f15");
 
-    assertThrows("Authentication is required", UnauthorizedException.class, request::execute);
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(UnauthorizedException.class)
+      .hasMessage("Authentication is required");
   }
 
   @Test
@@ -93,7 +95,9 @@ public class DismissAnalysisWarningActionIT {
       .setParam("component", project.getKee())
       .setParam("warning", "55c40b35-4145-4b78-bdf2-dfb242c25f15");
 
-    assertThrows("Insufficient privileges", ForbiddenException.class, request::execute);
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(ForbiddenException.class)
+      .hasMessage("Insufficient privileges");
   }
 
   @Test
@@ -103,7 +107,7 @@ public class DismissAnalysisWarningActionIT {
     userSession.logIn(user).addProjectPermission(UserRole.USER, project.getProjectDto());
     SnapshotDto analysis = db.components().insertSnapshot(project.getMainBranchComponent());
     CeActivityDto activity = insertActivity("task-uuid" + counter++, project.getMainBranchComponent(), SUCCESS, analysis, REPORT);
-    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "dismissable warning", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "dismissable warning", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     TestResponse response = underTest.newRequest()
       .setParam("component", project.projectKey())
@@ -113,7 +117,7 @@ public class DismissAnalysisWarningActionIT {
     assertThat(response.getStatus()).isEqualTo(204);
     assertThat(db.select("select * from user_dismissed_messages"))
       .extracting("USER_UUID", "PROJECT_UUID", "MESSAGE_TYPE")
-      .containsExactly(tuple(userSession.getUuid(), project.projectUuid(), CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE.name()));
+      .containsExactly(tuple(userSession.getUuid(), project.projectUuid(), MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE.name()));
   }
 
   @Test
@@ -123,7 +127,7 @@ public class DismissAnalysisWarningActionIT {
     userSession.logIn(user).addProjectPermission(UserRole.USER, project.getProjectDto());
     SnapshotDto analysis = db.components().insertSnapshot(project.getMainBranchComponent());
     CeActivityDto activity = insertActivity("task-uuid" + counter++, project.getMainBranchComponent(), SUCCESS, analysis, REPORT);
-    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "dismissable warning", CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    CeTaskMessageDto taskMessageDismissible = createTaskMessage(activity, "dismissable warning", MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     underTest.newRequest()
       .setParam("component", project.projectKey())
@@ -137,7 +141,7 @@ public class DismissAnalysisWarningActionIT {
     assertThat(response.getStatus()).isEqualTo(204);
     assertThat(db.select("select * from user_dismissed_messages"))
       .extracting("USER_UUID", "PROJECT_UUID", "MESSAGE_TYPE")
-      .containsExactly(tuple(userSession.getUuid(), project.projectUuid(), CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE.name()));
+      .containsExactly(tuple(userSession.getUuid(), project.projectUuid(), MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE.name()));
   }
 
   @Test
@@ -153,7 +157,9 @@ public class DismissAnalysisWarningActionIT {
       .setParam("component", project.projectKey())
       .setParam("warning", taskMessage.getUuid());
 
-    assertThrows(format("Message '%s' cannot be dismissed.", taskMessage.getUuid()), IllegalArgumentException.class, request::execute);
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(IllegalArgumentException.class)
+      .hasMessage(format("Message '%s' cannot be dismissed.", taskMessage.getUuid()));
     assertThat(db.countRowsOfTable("USER_DISMISSED_MESSAGES")).isZero();
   }
 
@@ -170,15 +176,17 @@ public class DismissAnalysisWarningActionIT {
       .setParam("component", project.projectKey())
       .setParam("warning", warningUuid);
 
-    assertThrows(format("Message '%s' not found", warningUuid), NotFoundException.class, request::execute);
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(NotFoundException.class)
+      .hasMessage(format("Message '%s' not found.", warningUuid));
     assertThat(db.countRowsOfTable("USER_DISMISSED_MESSAGES")).isZero();
   }
 
   private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning) {
-    return createTaskMessage(activity, warning, CeTaskMessageType.GENERIC);
+    return createTaskMessage(activity, warning, MessageType.GENERIC);
   }
 
-  private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning, CeTaskMessageType messageType) {
+  private CeTaskMessageDto createTaskMessage(CeActivityDto activity, String warning, MessageType messageType) {
     CeTaskMessageDto ceTaskMessageDto = new CeTaskMessageDto()
       .setUuid("m-uuid-" + counter++)
       .setTaskUuid(activity.getUuid())
index 4986f2c78f4a2728bdbd4277a5835643cfb64942..7f03efe53d2287ca98dccfa12885587d3dbe6d2a 100644 (file)
@@ -36,7 +36,7 @@ import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskCharacteristicDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ProjectData;
@@ -129,7 +129,7 @@ public class TaskActionIT {
           .setUuid("u_" + i)
           .setTaskUuid(queueDto.getUuid())
           .setMessage("m_" + i)
-          .setType(CeTaskMessageType.GENERIC)
+          .setType(MessageType.GENERIC)
           .setCreatedAt(queueDto.getUuid().hashCode() + i)));
     db.commit();
 
@@ -500,8 +500,8 @@ public class TaskActionIT {
     logInAsSystemAdministrator();
 
     CeActivityDto activityDto = persist(createActivityDto("uuid1"));
-    insertMessage(activityDto, 1, CeTaskMessageType.INFO);
-    CeTaskMessageDto warning = insertMessage(activityDto, 2, CeTaskMessageType.GENERIC);
+    insertMessage(activityDto, 1, MessageType.INFO);
+    CeTaskMessageDto warning = insertMessage(activityDto, 2, MessageType.GENERIC);
 
     callEndpointAndAssertWarnings(activityDto, List.of(warning));
   }
@@ -520,15 +520,15 @@ public class TaskActionIT {
   }
 
   private CeTaskMessageDto insertWarning(CeActivityDto task, int i) {
-    return insertMessage(task, i, CeTaskMessageType.GENERIC);
+    return insertMessage(task, i, MessageType.GENERIC);
   }
 
-  private CeTaskMessageDto insertMessage(CeActivityDto task, int i, CeTaskMessageType ceTaskMessageType) {
+  private CeTaskMessageDto insertMessage(CeActivityDto task, int i, MessageType messageType) {
     CeTaskMessageDto res = new CeTaskMessageDto()
       .setUuid(UuidFactoryFast.getInstance().create())
       .setTaskUuid(task.getUuid())
       .setMessage("msg_" + task.getUuid() + "_" + i)
-      .setType(ceTaskMessageType)
+      .setType(messageType)
       .setCreatedAt(task.getUuid().hashCode() + i);
     db.getDbClient().ceTaskMessageDao().insert(db.getSession(), res);
     db.getSession().commit();
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionIT.java
new file mode 100644 (file)
index 0000000..3482e19
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.dismissmessage.MessageType;
+import org.sonar.db.component.ProjectData;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.component.TestComponentFinder;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class DismissActionIT {
+
+  private static final String PROJECT_KEY = "project-key";
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+
+  private final WsActionTester underTest = new WsActionTester(new DismissAction(userSession, db.getDbClient(), TestComponentFinder.from(db)));
+
+  @Test
+  public void definition() {
+    WebService.Action def = underTest.getDef();
+    assertThat(def.key()).isEqualTo("dismiss");
+    assertThat(def.isInternal()).isTrue();
+    assertThat(def.isPost()).isTrue();
+    assertThat(def.params()).extracting(WebService.Param::key, WebService.Param::isRequired).containsOnly(
+      tuple("projectKey", false),
+      tuple("messageType", true));
+  }
+
+  @Test
+  public void return_401_if_user_is_not_logged_in() {
+    userSession.anonymous();
+    TestRequest request = underTest.newRequest()
+      .setParam("projectKey", PROJECT_KEY)
+      .setParam("messageType", MessageType.PROJECT_NCD_90.name());
+
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(UnauthorizedException.class)
+      .hasMessage("Authentication is required");
+  }
+
+  @Test
+  public void throw_IAE_if_messageType_is_not_valid() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    TestRequest request = underTest.newRequest()
+      .setParam("projectKey", PROJECT_KEY)
+      .setParam("messageType", "invalid");
+
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(IllegalArgumentException.class)
+      .hasMessage("Invalid message type: invalid");
+
+  }
+
+  @Test
+  public void throw_IAE_if_messageType_is_missing() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+    TestRequest request = underTest.newRequest()
+      .setParam("projectKey", PROJECT_KEY);
+
+    assertThatThrownBy(request::execute)
+      .isInstanceOf(IllegalArgumentException.class)
+      .hasMessage("The 'messageType' parameter is missing");
+
+  }
+
+
+  @Test
+  public void return_204_on_success() {
+    UserDto user = db.users().insertUser();
+    ProjectData project = db.components().insertPrivateProject();
+    userSession.logIn(user);
+
+    TestResponse response = underTest.newRequest()
+      .setParam("projectKey", project.projectKey())
+      .setParam("messageType", MessageType.BRANCH_NCD_90.name())
+      .execute();
+
+    assertThat(response.getStatus()).isEqualTo(204);
+    assertThat(db.select("select * from user_dismissed_messages"))
+      .extracting("USER_UUID", "PROJECT_UUID", "MESSAGE_TYPE")
+      .containsExactly(tuple(userSession.getUuid(), project.projectUuid(), MessageType.BRANCH_NCD_90.name()));
+  }
+
+}
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionParameterizedIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/dismissmessage/ws/DismissActionParameterizedIT.java
new file mode 100644 (file)
index 0000000..8b9b03e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import java.util.Arrays;
+import java.util.Collection;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.dismissmessage.MessageType;
+import org.sonar.db.component.ProjectData;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.component.TestComponentFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@RunWith(Parameterized.class)
+public class DismissActionParameterizedIT {
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  @Nullable
+  private final boolean isProjectKeyNull;
+
+  private final MessageType messageType;
+
+  private final Class<? extends Throwable> expectedException;
+  private final WsActionTester underTest = new WsActionTester(new DismissAction(userSession, db.getDbClient(), TestComponentFinder.from(db)));
+
+  public DismissActionParameterizedIT(boolean isProjectKeyNull, MessageType messageType, Class<? extends Throwable> expectedException) {
+    this.isProjectKeyNull = isProjectKeyNull;
+    this.messageType = messageType;
+    this.expectedException = expectedException;
+  }
+
+  @Test
+  public void test_verifyProjectKeyAndMessageType() {
+    UserDto user = db.users().insertUser();
+    userSession.logIn(user);
+
+    TestRequest request = underTest.newRequest()
+      .setParam("messageType", messageType.name());
+
+    if(!isProjectKeyNull) {
+      ProjectData project = db.components().insertPrivateProject();
+      request.setParam("projectKey", project.projectKey());
+    }
+
+    if(expectedException != null) {
+      assertThatThrownBy(request::execute)
+        .isInstanceOf(expectedException);
+    }  else {
+      TestResponse response = request.execute();
+      assertThat(response.getStatus()).isEqualTo(204);
+    }
+  }
+
+  @Parameterized.Parameters
+  public static Collection<Object[]> parameterCombination() {
+    return Arrays.asList(new Object[][]{
+      {true, MessageType.INFO, IllegalArgumentException.class},
+      {true, MessageType.GENERIC, IllegalArgumentException.class},
+      {true, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE, IllegalArgumentException.class},
+      {false, MessageType.GLOBAL_NCD_90, IllegalArgumentException.class},
+      {false, MessageType.GLOBAL_NCD_PAGE_90, IllegalArgumentException.class},
+      {true, MessageType.PROJECT_NCD_90, IllegalArgumentException.class},
+      {true, MessageType.PROJECT_NCD_PAGE_90, IllegalArgumentException.class},
+      {true, MessageType.BRANCH_NCD_90, IllegalArgumentException.class},
+      {true, MessageType.GLOBAL_NCD_90, null},
+      {true, MessageType.GLOBAL_NCD_PAGE_90, null},
+      {false, MessageType.PROJECT_NCD_90, null},
+      {false, MessageType.PROJECT_NCD_PAGE_90, null},
+      {false, MessageType.BRANCH_NCD_90, null},
+    });
+  }
+}
index 87eebebcc4e68e82053440a6485f41f64aedd1dd..6fc3a2815bcfc9fff7775f6fad2056586d576b5b 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.alm.setting.AlmSettingDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.permission.template.PermissionTemplateDto;
@@ -289,11 +289,11 @@ public class DeactivateActionIT {
     ProjectDto project2 = db.components().insertPrivateProject().getProjectDto();
     UserDto user = db.users().insertUser();
 
-    db.users().insertUserDismissedMessage(user, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    db.users().insertUserDismissedMessage(user, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    db.users().insertUserDismissedMessageOnProject(user, project1, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    db.users().insertUserDismissedMessageOnProject(user, project2, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
     UserDto anotherUser = db.users().insertUser();
-    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessage(anotherUser, project1, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
-    UserDismissedMessageDto msg4 = db.users().insertUserDismissedMessage(anotherUser, project2, CeTaskMessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg3 = db.users().insertUserDismissedMessageOnProject(anotherUser, project1, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
+    UserDismissedMessageDto msg4 = db.users().insertUserDismissedMessageOnProject(anotherUser, project2, MessageType.SUGGEST_DEVELOPER_EDITION_UPGRADE);
 
     deactivate(user.getLogin());
 
index fd5a8e680a088e2b747ead4f53966939881fcd17..03bc3edb479c422b5f22314ede1003d4df383dac 100644 (file)
@@ -79,12 +79,10 @@ public class DismissAnalysisWarningAction implements CeWsAction {
   @Override
   public void handle(Request request, Response response) throws Exception {
     userSession.checkLoggedIn();
-    String userLogin = requireNonNull(userSession.getLogin());
     String projectKey = request.mandatoryParam(PARAM_COMPONENT_KEY);
     String messageKey = request.mandatoryParam(PARAM_MESSAGE_KEY);
 
     try (DbSession dbSession = dbClient.openSession(false)) {
-      UserDto user = getUser(dbSession, userLogin);
       ProjectDto project = componentFinder.getProjectByKey(dbSession, projectKey);
       userSession.checkEntityPermission(UserRole.USER, project);
 
@@ -95,13 +93,14 @@ public class DismissAnalysisWarningAction implements CeWsAction {
         throw new IllegalArgumentException(format(MESSAGE_CANNOT_BE_DISMISSED, messageKey));
       }
 
-      Optional<UserDismissedMessageDto> result = dbClient.userDismissedMessagesDao().selectByUserAndProjectAndMessageType(dbSession, user, project, messageDto.getType());
+      Optional<UserDismissedMessageDto> result = dbClient.userDismissedMessagesDao().selectByUserAndProjectAndMessageType(dbSession,
+        userSession.getUuid(), project, messageDto.getType());
       if (!result.isPresent()) {
         dbClient.userDismissedMessagesDao().insert(dbSession, new UserDismissedMessageDto()
           .setUuid(Uuids.create())
-          .setUserUuid(user.getUuid())
+          .setUserUuid(userSession.getUuid())
           .setProjectUuid(project.getUuid())
-          .setCeMessageType(messageDto.getType()));
+          .setMessageType(messageDto.getType()));
         dbSession.commit();
       }
 
@@ -109,7 +108,4 @@ public class DismissAnalysisWarningAction implements CeWsAction {
     }
   }
 
-  private UserDto getUser(DbSession dbSession, String userLogin) {
-    return checkFound(dbClient.userDao().selectByLogin(dbSession, userLogin), "User '%s' not found", userLogin);
-  }
 }
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissAction.java
new file mode 100644 (file)
index 0000000..2c50ad5
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.dismissmessage.MessageType;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.user.UserDismissedMessageDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
+
+public class DismissAction implements DismissMessageWsAction {
+
+
+  private static final String PARAM_PROJECT_KEY = "projectKey";
+  private static final String PARAM_MESSAGE_TYPE = "messageType";
+  private final UserSession userSession;
+  private final DbClient dbClient;
+  private final ComponentFinder componentFinder;
+
+  public DismissAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder) {
+    this.userSession = userSession;
+    this.dbClient = dbClient;
+    this.componentFinder = componentFinder;
+  }
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context.createAction("dismiss")
+      .setDescription("Dismiss a message.")
+      .setSince("10.2")
+      .setPost(true)
+      .setInternal(true)
+      .setHandler(this);
+
+    action.createParam(PARAM_PROJECT_KEY)
+      .setDescription("The project key");
+
+    action.createParam(PARAM_MESSAGE_TYPE)
+      .setDescription("The type of the message dismissed")
+      .setRequired(true);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn();
+    ProjectDto project = null;
+    String projectKey = request.param(PARAM_PROJECT_KEY);
+    String messageType = request.mandatoryParam(PARAM_MESSAGE_TYPE);
+
+    MessageType type = parseMessageType(messageType);
+    verifyProjectKeyAndMessageType(projectKey, type);
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      if(projectKey != null) {
+        project = componentFinder.getProjectByKey(dbSession, projectKey);
+      }
+      dismissMessage(dbSession, project, type);
+      dbSession.commit();
+    }
+
+    response.noContent();
+
+  }
+
+  private void dismissMessage(DbSession dbSession, @Nullable ProjectDto project, MessageType type) {
+    Optional<UserDismissedMessageDto> result;
+    if (project == null) {
+      result = dbClient.userDismissedMessagesDao().selectByUserUuidAndMessageType(dbSession, userSession.getUuid(), type);
+    } else {
+      result = dbClient.userDismissedMessagesDao().selectByUserAndProjectAndMessageType(dbSession, userSession.getUuid(), project, type);
+    }
+    if (!result.isPresent()) {
+      dbClient.userDismissedMessagesDao().insert(dbSession, new UserDismissedMessageDto()
+        .setUuid(Uuids.create())
+        .setUserUuid(userSession.getUuid())
+        .setProjectUuid(project == null ? null: project.getUuid())
+        .setMessageType(type));
+    }
+  }
+
+  private static MessageType parseMessageType(String messageType) throws IllegalArgumentException {
+    try {
+      return MessageType.valueOf(messageType);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException("Invalid message type: " + messageType);
+    }
+  }
+
+  private static void verifyProjectKeyAndMessageType(@Nullable String projectKey, MessageType type) {
+    switch (type) {
+      case GLOBAL_NCD_90, GLOBAL_NCD_PAGE_90 -> {
+        if (projectKey != null) {
+          throw new IllegalArgumentException("The 'projectKey' parameter is not expected for message type: " + type);
+        }
+      }
+      case PROJECT_NCD_90, PROJECT_NCD_PAGE_90, BRANCH_NCD_90 -> {
+        if(projectKey == null) {
+          throw new IllegalArgumentException("The 'projectKey' parameter is missing for message type: " + type);
+        }
+      }
+      default -> throw new IllegalArgumentException("Unexpected message type: " + type);
+    }
+  }
+
+
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissActionWs.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissActionWs.java
new file mode 100644 (file)
index 0000000..265a332
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class DismissActionWs implements WebService {
+
+  private final DismissMessageWsAction[] actions;
+  public DismissActionWs(DismissMessageWsAction... actions) {
+    this.actions = actions;
+  }
+
+  @Override
+  public void define(Context context) {
+    NewController controller = context.createController("api/dismiss_message")
+      .setDescription("Manage message dismissal.")
+      .setSince("10.2");
+    for (DismissMessageWsAction action : actions) {
+      action.define(controller);
+    }
+    controller.done();
+  }
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsAction.java
new file mode 100644 (file)
index 0000000..8d0fc16
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface DismissMessageWsAction extends WsAction {
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/dismissmessage/ws/DismissMessageWsModule.java
new file mode 100644 (file)
index 0000000..cb6b24a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.dismissmessage.ws;
+
+import org.sonar.core.platform.Module;
+
+public class DismissMessageWsModule extends Module {
+  @Override
+  protected void configureModule() {
+    add(
+      DismissActionWs.class,
+      DismissAction.class);
+  }
+}
index ed2da8ed38b32fa97359ab7df3fb0a2be6e3956b..e8d1bec6d2261d064f1695a3a13c6057532720f9 100644 (file)
@@ -33,7 +33,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeActivityDto;
 import org.sonar.db.ce.CeQueueDto;
 import org.sonar.db.ce.CeTaskMessageDto;
-import org.sonar.db.ce.CeTaskMessageType;
+import org.sonar.db.dismissmessage.MessageType;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.user.UserDto;
 import org.sonarqube.ws.Ce;
@@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.tuple;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.sonar.db.ce.CeQueueTesting.makeInProgress;
-import static org.sonar.db.ce.CeTaskMessageType.INFO;
+import static org.sonar.db.dismissmessage.MessageType.INFO;
 
 public class TaskFormatterTest {
 
@@ -202,8 +202,8 @@ public class TaskFormatterTest {
   @Test
   public void formatActivity_filterNonWarnings_andSetMessagesAndCount() {
     TestActivityDto dto = newActivity("UUID", "COMPONENT_UUID", CeActivityDto.Status.FAILED, null);
-    CeTaskMessageDto warning1 = createCeTaskMessageDto(1998, CeTaskMessageType.GENERIC);
-    CeTaskMessageDto warning2 = createCeTaskMessageDto(1999, CeTaskMessageType.GENERIC);
+    CeTaskMessageDto warning1 = createCeTaskMessageDto(1998, MessageType.GENERIC);
+    CeTaskMessageDto warning2 = createCeTaskMessageDto(1999, MessageType.GENERIC);
 
     List<CeTaskMessageDto> ceTaskMessageDtos = new ArrayList<>(dto.getCeTaskMessageDtos());
     ceTaskMessageDtos.add(warning1);
@@ -292,12 +292,12 @@ public class TaskFormatterTest {
       .setAnalysisUuid("U1");
   }
 
-  private CeTaskMessageDto createCeTaskMessageDto(int i, CeTaskMessageType ceTaskMessageType) {
+  private CeTaskMessageDto createCeTaskMessageDto(int i, MessageType messageType) {
     CeTaskMessageDto ceTaskMessageDto = new CeTaskMessageDto();
     ceTaskMessageDto.setMessage("message_" + i);
     ceTaskMessageDto.setCreatedAt(system2.now());
     ceTaskMessageDto.setTaskUuid("uuid_" + i);
-    ceTaskMessageDto.setType(ceTaskMessageType);
+    ceTaskMessageDto.setType(messageType);
     return ceTaskMessageDto;
   }
 
index d35a4504d3f98d0bfa9153667cc73b57b317064b..9a286b3e2ef888d969057bdd0ff2e6ab19f775a4 100644 (file)
@@ -85,6 +85,7 @@ import org.sonar.server.component.index.EntityDefinitionIndexer;
 import org.sonar.server.component.ws.ComponentViewerJsonWriter;
 import org.sonar.server.component.ws.ComponentsWsModule;
 import org.sonar.server.developers.ws.DevelopersWsModule;
+import org.sonar.server.dismissmessage.ws.DismissMessageWsModule;
 import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
 import org.sonar.server.duplication.ws.ShowResponseBuilder;
@@ -623,6 +624,9 @@ public class PlatformLevel4 extends PlatformLevel {
       // monitoring
       ServerMonitoringMetrics.class,
 
+      // dismiss message
+      new DismissMessageWsModule(),
+
       AzureMetricsTask.class,
       BitbucketMetricsTask.class,
       GithubMetricsTask.class,