aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorBelen Pruvost <belen.pruvost@sonarsource.com>2021-11-03 16:32:41 +0100
committersonartech <sonartech@sonarsource.com>2021-11-03 20:03:31 +0000
commit812ba30a2eb3f13768b75dd40c40a0fcccad0425 (patch)
treebd038fd4f79045842be526ad003d384a08ec8cb4 /server
parent9f52d281c9697b69ec44cc592445525b50e50182 (diff)
downloadsonarqube-812ba30a2eb3f13768b75dd40c40a0fcccad0425.tar.gz
sonarqube-812ba30a2eb3f13768b75dd40c40a0fcccad0425.zip
SONAR-15603 - Quality Profile permission delegation logs
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java4
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java10
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java14
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java23
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java46
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java25
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java34
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java6
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java34
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java6
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java72
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java120
-rw-r--r--server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java21
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java4
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java3
15 files changed, 348 insertions, 74 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java
index 5cb1ef06044..60987dbf424 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/AuditPersister.java
@@ -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);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java
index 52a44b4a6ee..2de7874e9f8 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java
@@ -189,6 +189,16 @@ public class NoOpAuditPersister implements AuditPersister {
}
@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
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java
index 0146375640a..7969d398732 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/AbstractEditorNewValue.java
@@ -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;
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java
index d846220e2f2..21436bb81cf 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/GroupEditorNewValue.java
@@ -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);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java
index 32cca98a725..ed378d0a2cd 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/UserEditorNewValue.java
@@ -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);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java
index e6c205c4acb..5fb87f1cbb5 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileDto.java
@@ -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);
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java
index 484a406dd0d..a86a90537a9 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java
@@ -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) {
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java
index e849f4c984b..a20fe731f7d 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java
@@ -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);
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java
index 911867520a1..88a189f756e 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersDao.java
@@ -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) {
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java
index fdd09a5cc8b..1af27baf9ae 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditUsersMapper.java
@@ -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);
}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java
index b90b8e20795..919f596e8fd 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java
@@ -19,12 +19,16 @@
*/
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();
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java
index c68922dd5a7..8989a72e6ac 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditUsersDaoTest.java
@@ -20,13 +20,17 @@
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();
}
diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java
index 45f859a97c2..43f30fe9a0d 100644
--- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java
+++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualityprofile/QualityProfileDbTester.java
@@ -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();
}
}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java
index a39f48f9394..48d4a198389 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddGroupAction.java
@@ -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();
}
}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java
index 9472ff01bce..3115a019ab2 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/AddUserAction.java
@@ -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();
}