]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15603 - Quality Profile permission delegation logs
authorBelen Pruvost <belen.pruvost@sonarsource.com>
Wed, 3 Nov 2021 15:32:41 +0000 (16:32 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 3 Nov 2021 20:03:31 +0000 (20:03 +0000)
15 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java

index 5cb1ef0604423314b9640cb6ba68097b54896f2f..60987dbf424ba81686adad4091390641a6c31bdf 100644 (file)
@@ -101,6 +101,10 @@ public interface AuditPersister {
 
   void deleteQualityGateEditor(DbSession dbSession, AbstractEditorNewValue newValue);
 
+  void addQualityProfileEditor(DbSession dbSession, AbstractEditorNewValue newValue);
+
+  void deleteQualityProfileEditor(DbSession dbSession, AbstractEditorNewValue newValue);
+
   void addCharacteristicToPermissionTemplate(DbSession dbSession, PermissionTemplateNewValue newValue);
 
   void updateCharacteristicInPermissionTemplate(DbSession dbSession, PermissionTemplateNewValue newValue);
index 52a44b4a6ee19e4cfd802c664d36b0ce537f3ddb..2de7874e9f83f2471fa8715bc16c691f0bc7793a 100644 (file)
@@ -188,6 +188,16 @@ public class NoOpAuditPersister implements AuditPersister {
     // no op
   }
 
+  @Override
+  public void addQualityProfileEditor(DbSession dbSession, AbstractEditorNewValue newValue) {
+    // no op
+  }
+
+  @Override
+  public void deleteQualityProfileEditor(DbSession dbSession, AbstractEditorNewValue newValue) {
+    // no op
+  }
+
   @Override
   public void addCharacteristicToPermissionTemplate(DbSession dbSession, PermissionTemplateNewValue newValue) {
     // no op
index 0146375640ab22fb8f8199a5e130603f543b0294..7969d398732b123a21dff484ffff1bb8aec11f5d 100644 (file)
@@ -27,6 +27,10 @@ public abstract class AbstractEditorNewValue extends NewValue {
   protected String qualityGateUuid;
   @Nullable
   protected String qualityGateName;
+  @Nullable
+  protected String qualityProfileUuid;
+  @Nullable
+  protected String qualityProfileName;
 
   @CheckForNull
   public String getQualityGateUuid() {
@@ -37,4 +41,14 @@ public abstract class AbstractEditorNewValue extends NewValue {
   public String getQualityGateName() {
     return this.qualityGateName;
   }
+
+  @CheckForNull
+  public String getQualityProfileUuid() {
+    return this.qualityProfileUuid;
+  }
+
+  @CheckForNull
+  public String getQualityProfileName() {
+    return this.qualityProfileName;
+  }
 }
index d846220e2f2875fed06b5ea598f0bf3cf7cf88ee..21436bb81cf17e5ae4c40e0f80accb0c8c951864 100644 (file)
@@ -23,6 +23,8 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.db.qualitygate.QualityGateGroupPermissionsDto;
+import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.qualityprofile.QProfileEditGroupsDto;
 import org.sonar.db.user.GroupDto;
 
 public class GroupEditorNewValue extends AbstractEditorNewValue {
@@ -55,6 +57,25 @@ public class GroupEditorNewValue extends AbstractEditorNewValue {
     this.groupName = groupDto.getName();
   }
 
+  public GroupEditorNewValue(QProfileEditGroupsDto qProfileEditGroupsDto, String qualityProfileName, String groupName) {
+    this.qualityProfileUuid = qProfileEditGroupsDto.getQProfileUuid();
+    this.qualityProfileName = qualityProfileName;
+    this.groupUuid = qProfileEditGroupsDto.getGroupUuid();
+    this.groupName = groupName;
+  }
+
+  public GroupEditorNewValue(QProfileDto qualityProfileDto, GroupDto groupDto) {
+    this.qualityProfileUuid = qualityProfileDto.getKee();
+    this.qualityProfileName = qualityProfileDto.getName();
+    this.groupUuid = groupDto.getUuid();
+    this.groupName = groupDto.getName();
+  }
+
+  public GroupEditorNewValue(QProfileDto qualityProfileDto) {
+    this.qualityProfileUuid = qualityProfileDto.getKee();
+    this.qualityProfileName = qualityProfileDto.getName();
+  }
+
   @CheckForNull
   public String getGroupUuid() {
     return this.groupUuid;
@@ -70,6 +91,8 @@ public class GroupEditorNewValue extends AbstractEditorNewValue {
     StringBuilder sb = new StringBuilder("{");
     addField(sb, "\"qualityGateUuid\": ", this.qualityGateUuid, true);
     addField(sb, "\"qualityGateName\": ", this.qualityGateName, true);
+    addField(sb, "\"qualityProfileUuid\": ", this.qualityProfileUuid, true);
+    addField(sb, "\"qualityProfileName\": ", this.qualityProfileName, true);
     addField(sb, "\"groupUuid\": ", this.groupUuid, true);
     addField(sb, "\"groupName\": ", this.groupName, true);
     endString(sb);
index 32cca98a725c9bbaa6eedfe8e1fbe45c05d0aa02..ed378d0a2cd694a5f2e8a24b00e09c8ec1188388 100644 (file)
@@ -23,6 +23,8 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.db.qualitygate.QualityGateUserPermissionsDto;
+import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.qualityprofile.QProfileEditUsersDto;
 import org.sonar.db.user.UserDto;
 
 public class UserEditorNewValue extends AbstractEditorNewValue {
@@ -38,16 +40,40 @@ public class UserEditorNewValue extends AbstractEditorNewValue {
     this.userLogin = userLogin;
   }
 
-  public UserEditorNewValue(@Nullable QualityGateDto qualityGateDto, @Nullable UserDto userDto) {
-    if (qualityGateDto != null) {
-      this.qualityGateUuid = qualityGateDto.getUuid();
-      this.qualityGateName = qualityGateDto.getName();
-    }
+  public UserEditorNewValue(QualityGateDto qualityGateDto, UserDto userDto) {
+    this.qualityGateUuid = qualityGateDto.getUuid();
+    this.qualityGateName = qualityGateDto.getName();
+    this.userUuid = userDto.getUuid();
+    this.userLogin = userDto.getLogin();
+  }
+
+  public UserEditorNewValue(QualityGateDto qualityGateDto) {
+    this.qualityGateUuid = qualityGateDto.getUuid();
+    this.qualityGateName = qualityGateDto.getName();
+  }
+
+  public UserEditorNewValue(UserDto userDto) {
+    this.userUuid = userDto.getUuid();
+    this.userLogin = userDto.getLogin();
+  }
+
+  public UserEditorNewValue(QProfileEditUsersDto qProfileEditUsersDto, String qualityProfileName, String userLogin) {
+    this.qualityProfileUuid = qProfileEditUsersDto.getQProfileUuid();
+    this.qualityProfileName = qualityProfileName;
+    this.userUuid = qProfileEditUsersDto.getUserUuid();
+    this.userLogin = userLogin;
+  }
+
+  public UserEditorNewValue(QProfileDto qProfileDto, UserDto userDto) {
+    this.qualityProfileUuid = qProfileDto.getKee();
+    this.qualityProfileName = qProfileDto.getName();
+    this.userUuid = userDto.getUuid();
+    this.userLogin = userDto.getLogin();
+  }
 
-    if (userDto != null) {
-      this.userUuid = userDto.getUuid();
-      this.userLogin = userDto.getLogin();
-    }
+  public UserEditorNewValue(QProfileDto qProfileDto) {
+    this.qualityProfileUuid = qProfileDto.getKee();
+    this.qualityProfileName = qProfileDto.getName();
   }
 
   @CheckForNull
@@ -65,6 +91,8 @@ public class UserEditorNewValue extends AbstractEditorNewValue {
     StringBuilder sb = new StringBuilder("{");
     addField(sb, "\"qualityGateUuid\": ", this.qualityGateUuid, true);
     addField(sb, "\"qualityGateName\": ", this.qualityGateName, true);
+    addField(sb, "\"qualityProfileUuid\": ", this.qualityProfileUuid, true);
+    addField(sb, "\"qualityProfileName\": ", this.qualityProfileName, true);
     addField(sb, "\"userUuid\": ", this.userUuid, true);
     addField(sb, "\"userLogin\": ", this.userLogin, true);
     endString(sb);
index e6c205c4acb9363f71b63b92cb061ef52e168a45..5fb87f1cbb5aec1a677c18591b93ab6881142303 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.db.qualityprofile;
 
 import java.util.Date;
+import java.util.Objects;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.core.util.UtcDateUtils;
@@ -27,7 +28,7 @@ import org.sonar.core.util.UtcDateUtils;
 /**
  * Represents the join of "org_qprofiles" and "rules_profiles"
  */
-public class QProfileDto {
+public class QProfileDto implements Comparable<QProfileDto> {
   private String kee;
   private String name;
   private String language;
@@ -139,4 +140,26 @@ public class QProfileDto {
       .setLastUsed(org.getLastUsed())
       .setUserUpdatedAt(org.getUserUpdatedAt());
   }
+
+  @Override
+  public int compareTo(QProfileDto o) {
+    return kee.compareTo(o.kee);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    QProfileDto that = (QProfileDto) o;
+    return kee.equals(that.kee);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(kee);
+  }
 }
index 484a406dd0df1d6b27bd8df21a80b064acc443c1..a86a90537a9b30ac215f1f8181b539b197cdd8f2 100644 (file)
@@ -27,6 +27,8 @@ import org.sonar.db.Dao;
 import org.sonar.db.DatabaseUtils;
 import org.sonar.db.DbSession;
 import org.sonar.db.Pagination;
+import org.sonar.db.audit.AuditPersister;
+import org.sonar.db.audit.model.GroupEditorNewValue;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.SearchGroupMembershipDto;
 
@@ -37,9 +39,11 @@ import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
 public class QProfileEditGroupsDao implements Dao {
 
   private final System2 system2;
+  private final AuditPersister auditPersister;
 
-  public QProfileEditGroupsDao(System2 system2) {
+  public QProfileEditGroupsDao(System2 system2, AuditPersister auditPersister) {
     this.system2 = system2;
+    this.auditPersister = auditPersister;
   }
 
   public boolean exists(DbSession dbSession, QProfileDto profile, GroupDto group) {
@@ -64,20 +68,40 @@ public class QProfileEditGroupsDao implements Dao {
       g -> mapper(dbSession).selectQProfileUuidsByGroups(g));
   }
 
-  public void insert(DbSession dbSession, QProfileEditGroupsDto dto) {
+  public void insert(DbSession dbSession, QProfileEditGroupsDto dto, String qualityProfileName, String groupName) {
     mapper(dbSession).insert(dto, system2.now());
+    auditPersister.addQualityProfileEditor(dbSession, new GroupEditorNewValue(dto, qualityProfileName, groupName));
   }
 
   public void deleteByQProfileAndGroup(DbSession dbSession, QProfileDto profile, GroupDto group) {
-    mapper(dbSession).delete(profile.getKee(), group.getUuid());
+    int deletedRows = mapper(dbSession).delete(profile.getKee(), group.getUuid());
+
+    if (deletedRows > 0) {
+      auditPersister.deleteQualityProfileEditor(dbSession, new GroupEditorNewValue(profile, group));
+    }
   }
 
   public void deleteByQProfiles(DbSession dbSession, List<QProfileDto> qProfiles) {
-    executeLargeUpdates(qProfiles.stream().map(QProfileDto::getKee).collect(toList()), p -> mapper(dbSession).deleteByQProfiles(p));
+    executeLargeUpdates(qProfiles,
+      partitionedProfiles ->
+      {
+        int deletedRows = mapper(dbSession).deleteByQProfiles(partitionedProfiles
+          .stream()
+          .map(QProfileDto::getKee)
+          .collect(toList()));
+
+        if (deletedRows > 0) {
+          partitionedProfiles.forEach(p -> auditPersister.deleteQualityProfileEditor(dbSession, new GroupEditorNewValue(p)));
+        }
+      });
   }
 
   public void deleteByGroup(DbSession dbSession, GroupDto group) {
-    mapper(dbSession).deleteByGroup(group.getUuid());
+    int deletedRows = mapper(dbSession).deleteByGroup(group.getUuid());
+
+    if (deletedRows > 0) {
+      auditPersister.deleteQualityProfileEditor(dbSession, new GroupEditorNewValue(group));
+    }
   }
 
   private static QProfileEditGroupsMapper mapper(DbSession dbSession) {
index e849f4c984bd3936e90b52feefc5d0aecf6a82bb..a20fe731f7d3c80feb6039bb899bdd5848c80278 100644 (file)
@@ -37,10 +37,10 @@ public interface QProfileEditGroupsMapper {
 
   void insert(@Param("dto") QProfileEditGroupsDto dto, @Param("now") long now);
 
-  void delete(@Param("qProfileUuid") String qProfileUuid, @Param("groupUuid") String groupUuid);
+  int delete(@Param("qProfileUuid") String qProfileUuid, @Param("groupUuid") String groupUuid);
 
-  void deleteByQProfiles(@Param("qProfileUuids") Collection<String> qProfileUuids);
+  int deleteByQProfiles(@Param("qProfileUuids") Collection<String> qProfileUuids);
 
-  void deleteByGroup(@Param("groupUuid") String groupUuid);
+  int deleteByGroup(@Param("groupUuid") String groupUuid);
 
 }
index 911867520a1cbd893cfcc19d99c16af38399fdfa..88a189f756e489e3d0bb41980cc26ca7c22fcb5b 100644 (file)
@@ -24,6 +24,8 @@ import org.sonar.api.utils.System2;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
 import org.sonar.db.Pagination;
+import org.sonar.db.audit.AuditPersister;
+import org.sonar.db.audit.model.UserEditorNewValue;
 import org.sonar.db.user.SearchUserMembershipDto;
 import org.sonar.db.user.UserDto;
 
@@ -33,9 +35,11 @@ import static org.sonar.db.DatabaseUtils.executeLargeUpdates;
 public class QProfileEditUsersDao implements Dao {
 
   private final System2 system2;
+  private final AuditPersister auditPersister;
 
-  public QProfileEditUsersDao(System2 system2) {
+  public QProfileEditUsersDao(System2 system2, AuditPersister auditPersister) {
     this.system2 = system2;
+    this.auditPersister = auditPersister;
   }
 
   public boolean exists(DbSession dbSession, QProfileDto profile, UserDto user) {
@@ -54,20 +58,40 @@ public class QProfileEditUsersDao implements Dao {
     return mapper(dbSession).selectQProfileUuidsByUser(userDto.getUuid());
   }
 
-  public void insert(DbSession dbSession, QProfileEditUsersDto dto) {
+  public void insert(DbSession dbSession, QProfileEditUsersDto dto, String qualityProfileName, String userLogin) {
     mapper(dbSession).insert(dto, system2.now());
+    auditPersister.addQualityProfileEditor(dbSession, new UserEditorNewValue(dto, qualityProfileName, userLogin));
   }
 
   public void deleteByQProfileAndUser(DbSession dbSession, QProfileDto profile, UserDto user) {
-    mapper(dbSession).delete(profile.getKee(), user.getUuid());
+    int deletedRows = mapper(dbSession).delete(profile.getKee(), user.getUuid());
+
+    if (deletedRows > 0) {
+      auditPersister.deleteQualityProfileEditor(dbSession, new UserEditorNewValue(profile, user));
+    }
   }
 
   public void deleteByQProfiles(DbSession dbSession, List<QProfileDto> qProfiles) {
-    executeLargeUpdates(qProfiles.stream().map(QProfileDto::getKee).collect(toList()), p -> mapper(dbSession).deleteByQProfiles(p));
+    executeLargeUpdates(qProfiles,
+      partitionedProfiles ->
+      {
+        int deletedRows = mapper(dbSession).deleteByQProfiles(partitionedProfiles
+          .stream()
+          .map(QProfileDto::getKee)
+          .collect(toList()));
+
+        if (deletedRows > 0) {
+          partitionedProfiles.forEach(p -> auditPersister.deleteQualityProfileEditor(dbSession, new UserEditorNewValue(p)));
+        }
+      });
   }
 
   public void deleteByUser(DbSession dbSession, UserDto user) {
-    mapper(dbSession).deleteByUser(user.getUuid());
+    int deletedRows = mapper(dbSession).deleteByUser(user.getUuid());
+
+    if (deletedRows > 0) {
+      auditPersister.deleteQualityProfileEditor(dbSession, new UserEditorNewValue(user));
+    }
   }
 
   private static QProfileEditUsersMapper mapper(DbSession dbSession) {
index fdd09a5cc8b0caa22fb829bdd68643e00d4f9597..1af27baf9ae46ce4eb09c33a4fe71db3a6969833 100644 (file)
@@ -37,9 +37,9 @@ public interface QProfileEditUsersMapper {
 
   void insert(@Param("dto") QProfileEditUsersDto dto, @Param("now") long now);
 
-  void delete(@Param("qProfileUuid") String qProfileUuid, @Param("userUuid") String userUuid);
+  int delete(@Param("qProfileUuid") String qProfileUuid, @Param("userUuid") String userUuid);
 
-  void deleteByQProfiles(@Param("qProfileUuids") Collection<String> qProfileUuids);
+  int deleteByQProfiles(@Param("qProfileUuids") Collection<String> qProfileUuids);
 
-  void deleteByUser(@Param("userUuid") String userUuid);
+  int deleteByUser(@Param("userUuid") String userUuid);
 }
index b90b8e207952703e8cb26e102f6a77fc037314fa..919f596e8fd9ee78be8d05511a003940c632bea7 100644 (file)
  */
 package org.sonar.db.qualityprofile;
 
+import java.util.List;
 import org.junit.Rule;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.sonar.api.impl.utils.TestSystem2;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
 import org.sonar.db.Pagination;
+import org.sonar.db.audit.AuditPersister;
+import org.sonar.db.audit.model.GroupEditorNewValue;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.SearchGroupMembershipDto;
 
@@ -34,6 +38,10 @@ import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
 import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.ANY;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.IN;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.OUT;
@@ -43,10 +51,13 @@ public class QProfileEditGroupsDaoTest {
 
   private static final long NOW = 10_000_000_000L;
 
+  private final AuditPersister auditPersister = mock(AuditPersister.class);
+  private final ArgumentCaptor<GroupEditorNewValue> newValueCaptor = ArgumentCaptor.forClass(GroupEditorNewValue.class);
+
   private System2 system2 = new TestSystem2().setNow(NOW);
 
   @Rule
-  public DbTester db = DbTester.create(system2);
+  public DbTester db = DbTester.create(system2, auditPersister);
 
   private QProfileEditGroupsDao underTest = db.getDbClient().qProfileEditGroupsDao();
 
@@ -201,22 +212,37 @@ public class QProfileEditGroupsDaoTest {
       .containsExactlyInAnyOrder(profile1.getKee(), profile2.getKee());
     assertThat(underTest.selectQProfileUuidsByGroups(db.getSession(), asList(group1, group2, group3)))
       .containsExactlyInAnyOrder(profile1.getKee(), profile2.getKee());
-    assertThat(underTest.selectQProfileUuidsByGroups(db.getSession(),emptyList())).isEmpty();
+    assertThat(underTest.selectQProfileUuidsByGroups(db.getSession(), emptyList())).isEmpty();
   }
 
   @Test
   public void insert() {
+    String qualityProfileName = "QPROFILE_NAME";
+    String qualityProfileKee = "QPROFILE";
+    String groupUuid = "100";
+    String groupName = "GROUP_NAME";
     underTest.insert(db.getSession(), new QProfileEditGroupsDto()
-      .setUuid("ABCD")
-      .setGroupUuid("100")
-      .setQProfileUuid("QPROFILE")
+        .setUuid("ABCD")
+        .setGroupUuid(groupUuid)
+        .setQProfileUuid(qualityProfileKee),
+      qualityProfileName,
+      groupName
     );
 
+    verify(auditPersister).addQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    GroupEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileUuid,
+        GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
+      .containsExactly(qualityProfileName, qualityProfileKee, groupName, groupUuid);
+    assertThat(newValue.toString()).contains("\"qualityProfileName\"").contains("\"groupName\"");
+
     assertThat(db.selectFirst(db.getSession(),
       "select uuid as \"uuid\", group_uuid as \"groupUuid\", qprofile_uuid as \"qProfileUuid\", created_at as \"createdAt\" from qprofile_edit_groups")).contains(
       entry("uuid", "ABCD"),
-      entry("groupUuid", "100"),
-      entry("qProfileUuid", "QPROFILE"),
+      entry("groupUuid", groupUuid),
+      entry("qProfileUuid", qualityProfileKee),
       entry("createdAt", NOW));
   }
 
@@ -229,6 +255,15 @@ public class QProfileEditGroupsDaoTest {
 
     underTest.deleteByQProfileAndGroup(db.getSession(), profile, group);
 
+    verify(auditPersister).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    GroupEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileName,
+        GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
+      .containsExactly(profile.getName(), profile.getKee(), group.getName(), group.getUuid());
+    assertThat(newValue.toString()).contains("\"qualityProfileName\"").contains("\"groupName\"");
+
     assertThat(underTest.exists(db.getSession(), profile, group)).isFalse();
   }
 
@@ -245,6 +280,20 @@ public class QProfileEditGroupsDaoTest {
 
     underTest.deleteByQProfiles(db.getSession(), asList(profile1, profile2));
 
+    verify(auditPersister, times(2)).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    List<GroupEditorNewValue> newValues = newValueCaptor.getAllValues();
+    assertThat(newValues.get(0))
+      .extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileUuid,
+        GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
+      .containsExactly(profile1.getName(), profile1.getKee(), null, null);
+    assertThat(newValues.get(0).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+    assertThat(newValues.get(1))
+      .extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileUuid,
+        GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
+      .containsExactly(profile2.getName(), profile2.getKee(), null, null);
+    assertThat(newValues.get(1).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+
     assertThat(underTest.exists(db.getSession(), profile1, group1)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile2, group2)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile3, group1)).isTrue();
@@ -263,6 +312,15 @@ public class QProfileEditGroupsDaoTest {
 
     underTest.deleteByGroup(db.getSession(), group1);
 
+    verify(auditPersister).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    GroupEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(GroupEditorNewValue::getQualityProfileName, GroupEditorNewValue::getQualityProfileName,
+        GroupEditorNewValue::getGroupName, GroupEditorNewValue::getGroupUuid)
+      .containsExactly(null, null, group1.getName(), group1.getUuid());
+    assertThat(newValue.toString()).doesNotContain("\"qualityProfileName\"").contains("\"groupName\"");
+
     assertThat(underTest.exists(db.getSession(), profile1, group1)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile2, group2)).isTrue();
     assertThat(underTest.exists(db.getSession(), profile3, group1)).isFalse();
index c68922dd5a7e815d0bc648c3cd6d64a1fd560757..8989a72e6ac39d694c0641f3001f81cf24e87670 100644 (file)
 package org.sonar.db.qualityprofile;
 
 import java.sql.SQLException;
+import java.util.List;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
+import org.mockito.ArgumentCaptor;
 import org.sonar.api.impl.utils.TestSystem2;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
 import org.sonar.db.Pagination;
+import org.sonar.db.audit.AuditPersister;
+import org.sonar.db.audit.model.UserEditorNewValue;
 import org.sonar.db.user.SearchUserMembershipDto;
 import org.sonar.db.user.UserDto;
 
@@ -34,6 +38,10 @@ import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
 import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.ANY;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.IN;
 import static org.sonar.db.qualityprofile.SearchQualityProfilePermissionQuery.OUT;
@@ -45,11 +53,13 @@ public class QProfileEditUsersDaoTest {
   private static final long NOW = 10_000_000_000L;
 
   private final System2 system2 = new TestSystem2().setNow(NOW);
+  private final AuditPersister auditPersister = mock(AuditPersister.class);
+  private final ArgumentCaptor<UserEditorNewValue> newValueCaptor = ArgumentCaptor.forClass(UserEditorNewValue.class);
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
-  public DbTester db = DbTester.create(system2);
+  public DbTester db = DbTester.create(system2, auditPersister);
 
   private final QProfileEditUsersDao underTest = db.getDbClient().qProfileEditUsersDao();
 
@@ -61,6 +71,15 @@ public class QProfileEditUsersDaoTest {
     UserDto anotherUser = db.users().insertUser();
     db.qualityProfiles().addUserPermission(profile, user);
 
+    verify(auditPersister).addQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    UserEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
+        UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+      .containsExactly(profile.getName(), profile.getKee(), user.getLogin(), user.getUuid());
+    assertThat(newValue.toString()).contains("\"qualityProfileName\"").contains("\"userLogin\"");
+
     assertThat(underTest.exists(db.getSession(), profile, user)).isTrue();
     assertThat(underTest.exists(db.getSession(), profile, anotherUser)).isFalse();
     assertThat(underTest.exists(db.getSession(), anotherProfile, user)).isFalse();
@@ -79,17 +98,17 @@ public class QProfileEditUsersDaoTest {
     assertThat(underTest.countByQuery(db.getSession(), builder()
       .setProfile(profile)
       .setMembership(ANY).build()))
-        .isEqualTo(3);
+      .isEqualTo(3);
 
     assertThat(underTest.countByQuery(db.getSession(), builder()
       .setProfile(profile)
       .setMembership(IN).build()))
-        .isEqualTo(2);
+      .isEqualTo(2);
 
     assertThat(underTest.countByQuery(db.getSession(), builder()
       .setProfile(profile)
       .setMembership(OUT).build()))
-        .isEqualTo(1);
+      .isEqualTo(1);
   }
 
   @Test
@@ -105,24 +124,24 @@ public class QProfileEditUsersDaoTest {
       .setProfile(profile)
       .setMembership(ANY).build(), Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid, SearchUserMembershipDto::isSelected)
-        .containsExactlyInAnyOrder(
-          tuple(user1.getUuid(), true),
-          tuple(user2.getUuid(), true),
-          tuple(user3.getUuid(), false));
+      .containsExactlyInAnyOrder(
+        tuple(user1.getUuid(), true),
+        tuple(user2.getUuid(), true),
+        tuple(user3.getUuid(), false));
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
         .setMembership(IN).build(),
       Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid, SearchUserMembershipDto::isSelected)
-        .containsExactlyInAnyOrder(tuple(user1.getUuid(), true), tuple(user2.getUuid(), true));
+      .containsExactlyInAnyOrder(tuple(user1.getUuid(), true), tuple(user2.getUuid(), true));
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
         .setMembership(OUT).build(),
       Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid, SearchUserMembershipDto::isSelected)
-        .containsExactlyInAnyOrder(tuple(user3.getUuid(), false));
+      .containsExactlyInAnyOrder(tuple(user3.getUuid(), false));
   }
 
   @Test
@@ -141,7 +160,7 @@ public class QProfileEditUsersDaoTest {
         .setQuery("user2").build(),
       Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactlyInAnyOrder(user2.getUuid());
+      .containsExactlyInAnyOrder(user2.getUuid());
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
@@ -149,7 +168,7 @@ public class QProfileEditUsersDaoTest {
         .setQuery("joh").build(),
       Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactlyInAnyOrder(user1.getUuid(), user2.getUuid());
+      .containsExactlyInAnyOrder(user1.getUuid(), user2.getUuid());
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
@@ -157,7 +176,7 @@ public class QProfileEditUsersDaoTest {
         .setQuery("Doe").build(),
       Pagination.all()))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactlyInAnyOrder(user1.getUuid(), user3.getUuid());
+      .containsExactlyInAnyOrder(user1.getUuid(), user3.getUuid());
   }
 
   @Test
@@ -175,7 +194,7 @@ public class QProfileEditUsersDaoTest {
         .build(),
       Pagination.forPage(1).andSize(1)))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactly(user1.getUuid());
+      .containsExactly(user1.getUuid());
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
@@ -183,7 +202,7 @@ public class QProfileEditUsersDaoTest {
         .build(),
       Pagination.forPage(3).andSize(1)))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactly(user3.getUuid());
+      .containsExactly(user3.getUuid());
 
     assertThat(underTest.selectByQuery(db.getSession(), builder()
         .setProfile(profile)
@@ -191,7 +210,7 @@ public class QProfileEditUsersDaoTest {
         .build(),
       Pagination.forPage(1).andSize(10)))
       .extracting(SearchUserMembershipDto::getUserUuid)
-        .containsExactly(user1.getUuid(), user2.getUuid(), user3.getUuid());
+      .containsExactly(user1.getUuid(), user2.getUuid(), user3.getUuid());
   }
 
   @Test
@@ -210,32 +229,43 @@ public class QProfileEditUsersDaoTest {
 
   @Test
   public void insert() {
+    String qualityProfileUuid = "QPROFILE";
+    String qualityProfileName = "QPROFILE_NAME";
+    String userUuid = "100";
+    String userLogin = "USER_LOGIN";
     underTest.insert(db.getSession(), new QProfileEditUsersDto()
-      .setUuid("ABCD")
-      .setUserUuid("100")
-      .setQProfileUuid("QPROFILE"));
+        .setUuid("ABCD")
+        .setUserUuid(userUuid)
+        .setQProfileUuid(qualityProfileUuid),
+      qualityProfileName, userLogin);
 
     assertThat(db.selectFirst(db.getSession(),
       "select uuid as \"uuid\", user_uuid as \"userUuid\", qprofile_uuid as \"qProfileUuid\", created_at as \"createdAt\" from qprofile_edit_users")).contains(
-        entry("uuid", "ABCD"),
-        entry("userUuid", "100"),
-        entry("qProfileUuid", "QPROFILE"),
-        entry("createdAt", NOW));
+      entry("uuid", "ABCD"),
+      entry("userUuid", userUuid),
+      entry("qProfileUuid", qualityProfileUuid),
+      entry("createdAt", NOW));
   }
 
   @Test
   public void fail_to_insert_same_row_twice() {
+    String qualityProfileUuid = "QPROFILE";
+    String qualityProfileName = "QPROFILE_NAME";
+    String userUuid = "100";
+    String userLogin = "USER_LOGIN";
     underTest.insert(db.getSession(), new QProfileEditUsersDto()
-      .setUuid("UUID-1")
-      .setUserUuid("100")
-      .setQProfileUuid("QPROFILE"));
+        .setUuid("UUID-1")
+        .setUserUuid(userUuid)
+        .setQProfileUuid(qualityProfileUuid),
+      qualityProfileName, userLogin);
 
     expectedException.expectCause(hasType(SQLException.class));
 
     underTest.insert(db.getSession(), new QProfileEditUsersDto()
-      .setUuid("UUID-2")
-      .setUserUuid("100")
-      .setQProfileUuid("QPROFILE"));
+        .setUuid("UUID-2")
+        .setUserUuid(userUuid)
+        .setQProfileUuid(qualityProfileUuid),
+      qualityProfileName, userLogin);
   }
 
   @Test
@@ -247,6 +277,15 @@ public class QProfileEditUsersDaoTest {
 
     underTest.deleteByQProfileAndUser(db.getSession(), profile, user);
 
+    verify(auditPersister).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    UserEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
+        UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+      .containsExactly(profile.getName(), profile.getKee(), user.getLogin(), user.getUuid());
+    assertThat(newValue.toString()).contains("\"qualityProfileName\"").contains("\"userLogin\"");
+
     assertThat(underTest.exists(db.getSession(), profile, user)).isFalse();
   }
 
@@ -263,6 +302,20 @@ public class QProfileEditUsersDaoTest {
 
     underTest.deleteByQProfiles(db.getSession(), asList(profile1, profile2));
 
+    verify(auditPersister, times(2)).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    List<UserEditorNewValue> newValues = newValueCaptor.getAllValues();
+    assertThat(newValues.get(0))
+      .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
+        UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+      .containsExactly(profile1.getName(), profile1.getKee(), null, null);
+    assertThat(newValues.get(0).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+    assertThat(newValues.get(1))
+      .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
+        UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+      .containsExactly(profile2.getName(), profile2.getKee(), null, null);
+    assertThat(newValues.get(1).toString()).contains("\"qualityProfileName\"").doesNotContain("\"groupName\"");
+
     assertThat(underTest.exists(db.getSession(), profile1, user1)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile2, user2)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile3, user1)).isTrue();
@@ -279,6 +332,15 @@ public class QProfileEditUsersDaoTest {
 
     underTest.deleteByUser(db.getSession(), user1);
 
+    verify(auditPersister).deleteQualityProfileEditor(eq(db.getSession()), newValueCaptor.capture());
+
+    UserEditorNewValue newValue = newValueCaptor.getValue();
+    assertThat(newValue)
+      .extracting(UserEditorNewValue::getQualityProfileName, UserEditorNewValue::getQualityProfileUuid,
+        UserEditorNewValue::getUserLogin, UserEditorNewValue::getUserUuid)
+      .containsExactly(null, null, user1.getLogin(), user1.getUuid());
+    assertThat(newValue.toString()).doesNotContain("\"qualityProfileName\"").contains("\"userLogin\"");
+
     assertThat(underTest.exists(db.getSession(), profile1, user1)).isFalse();
     assertThat(underTest.exists(db.getSession(), profile3, user2)).isTrue();
   }
index 45f859a97c29e757acd2661b938bd22bb0c6ecdf..43f30fe9a0d7b3c2db0f53400eab3a0eb0cabc5b 100644 (file)
@@ -106,29 +106,30 @@ public class QualityProfileDbTester {
   public QualityProfileDbTester setAsDefault(QProfileDto profile, QProfileDto... others) {
     dbClient.defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(profile));
     for (QProfileDto other : others) {
-      dbClient.defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from( other));
+      dbClient.defaultQProfileDao().insertOrUpdate(dbSession, DefaultQProfileDto.from(other));
     }
     dbSession.commit();
     return this;
   }
 
-  public void addUserPermission(QProfileDto profile, UserDto user){
+  public void addUserPermission(QProfileDto profile, UserDto user) {
     checkArgument(!profile.isBuiltIn(), "Built-In profile cannot be used");
     dbClient.qProfileEditUsersDao().insert(dbSession, new QProfileEditUsersDto()
-      .setUuid(Uuids.createFast())
-      .setUserUuid(user.getUuid())
-      .setQProfileUuid(profile.getKee())
+        .setUuid(Uuids.createFast())
+        .setUserUuid(user.getUuid())
+        .setQProfileUuid(profile.getKee()),
+      profile.getName(), user.getLogin()
     );
     dbSession.commit();
   }
 
-  public void addGroupPermission(QProfileDto profile, GroupDto group){
+  public void addGroupPermission(QProfileDto profile, GroupDto group) {
     checkArgument(!profile.isBuiltIn(), "Built-In profile cannot be used");
     dbClient.qProfileEditGroupsDao().insert(dbSession, new QProfileEditGroupsDto()
-      .setUuid(Uuids.createFast())
-      .setGroupUuid(group.getUuid())
-      .setQProfileUuid(profile.getKee())
-    );
+        .setUuid(Uuids.createFast())
+        .setGroupUuid(group.getUuid())
+        .setQProfileUuid(profile.getKee()),
+      profile.getName(), group.getName());
     dbSession.commit();
   }
 }
index a39f48f93947865c506ea37a8483e4bdb1f58f06..48d4a19838929cbb13b7caee2597ea9e977fbad5 100644 (file)
@@ -103,7 +103,9 @@ public class AddGroupAction implements QProfileWsAction {
       new QProfileEditGroupsDto()
         .setUuid(uuidFactory.create())
         .setGroupUuid(group.getUuid())
-        .setQProfileUuid(profile.getKee()));
+        .setQProfileUuid(profile.getKee()),
+      profile.getName(),
+      group.getName());
     dbSession.commit();
   }
 }
index 9472ff01bce739a1c23f0d972af5a313b41be3f2..3115a019ab2211029fad0b584ddb5023c33deb9f 100644 (file)
@@ -104,7 +104,8 @@ public class AddUserAction implements QProfileWsAction {
       new QProfileEditUsersDto()
         .setUuid(uuidFactory.create())
         .setUserUuid(user.getUuid())
-        .setQProfileUuid(profile.getKee()));
+        .setQProfileUuid(profile.getKee()),
+      profile.getName(), user.getLogin());
     dbSession.commit();
   }