Browse Source

SONAR-10074 Add QP actions "delete" and "associateProjects"

In api/qualityprofiles/search, the following actions are now availables :
- delete : Available when not built-it, not default, and have either QP admin permission or have rights to edit
- associateProjects : Available when not default and have either QP admin permission or have rights to edit
tags/7.0-RC1
Julien Lancelot 6 years ago
parent
commit
f25ece8fe8

+ 19
- 17
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java View File

.setSince("5.2") .setSince("5.2")
.setDescription("Search quality profiles") .setDescription("Search quality profiles")
.setHandler(this) .setHandler(this)
.setChangelog(new Change("6.5", format("The parameters '%s', '%s' and '%s' can be combined without any constraint", PARAM_DEFAULTS, PARAM_PROJECT, PARAM_LANGUAGE)))
.setChangelog(
new Change("6.5", format("The parameters '%s', '%s' and '%s' can be combined without any constraint", PARAM_DEFAULTS, PARAM_PROJECT, PARAM_LANGUAGE)),
new Change("6.6", "Add available actions 'edit', 'copy' and 'setAsDefault' and global action 'create'"),
new Change("7.0", "Add available actions 'delete' and 'associateProjects'")
)
.setResponseExample(getClass().getResource("search-example.json")); .setResponseExample(getClass().getResource("search-example.json"));


QProfileWsSupport.createOrganizationParam(action
)
QProfileWsSupport.createOrganizationParam(action)
.setSince("6.4"); .setSince("6.4");


action action
dbClient.activeRuleDao().countActiveRulesByQuery(dbSession, builder.setProfiles(profiles).setRuleStatus(DEPRECATED).build())) dbClient.activeRuleDao().countActiveRulesByQuery(dbSession, builder.setProfiles(profiles).setRuleStatus(DEPRECATED).build()))
.setProjectCountByProfileKey(dbClient.qualityProfileDao().countProjectsByOrganizationAndProfiles(dbSession, organization, profiles)) .setProjectCountByProfileKey(dbClient.qualityProfileDao().countProjectsByOrganizationAndProfiles(dbSession, organization, profiles))
.setDefaultProfileKeys(defaultProfiles) .setDefaultProfileKeys(defaultProfiles)
.setEditableProfileKeys(editableProfiles)
.setGlobalQProfileAdmin(userSession.hasPermission(ADMINISTER_QUALITY_PROFILES, organization));
.setEditableProfileKeys(editableProfiles);
} }
} }


UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login); UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, login);
checkState(user != null, "User with login '%s' is not found'", login); checkState(user != null, "User with login '%s' is not found'", login);


return
Stream.concat(
dbClient.qProfileEditUsersDao().selectQProfileUuidsByOrganizationAndUser(dbSession, organization, user).stream(),
dbClient.qProfileEditGroupsDao().selectQProfileUuidsByOrganizationAndGroups(dbSession, organization, userSession.getGroups()).stream())
.collect(toList());
return Stream.concat(
dbClient.qProfileEditUsersDao().selectQProfileUuidsByOrganizationAndUser(dbSession, organization, user).stream(),
dbClient.qProfileEditGroupsDao().selectQProfileUuidsByOrganizationAndGroups(dbSession, organization, userSession.getGroups()).stream())
.collect(toList());
} }


private List<QProfileDto> searchProfiles(DbSession dbSession, SearchRequest request, OrganizationDto organization, List<QProfileDto> defaultProfiles, private List<QProfileDto> searchProfiles(DbSession dbSession, SearchRequest request, OrganizationDto organization, List<QProfileDto> defaultProfiles,
@Nullable ComponentDto project) {
@Nullable ComponentDto project) {
Collection<QProfileDto> profiles = selectAllProfiles(dbSession, organization); Collection<QProfileDto> profiles = selectAllProfiles(dbSession, organization);


return profiles.stream() return profiles.stream()
private SearchWsResponse buildResponse(SearchData data) { private SearchWsResponse buildResponse(SearchData data) {
List<QProfileDto> profiles = data.getProfiles(); List<QProfileDto> profiles = data.getProfiles();
Map<String, QProfileDto> profilesByKey = profiles.stream().collect(Collectors.toMap(QProfileDto::getKee, identity())); Map<String, QProfileDto> profilesByKey = profiles.stream().collect(Collectors.toMap(QProfileDto::getKee, identity()));
boolean isGlobalQProfileAdmin = userSession.hasPermission(ADMINISTER_QUALITY_PROFILES, data.getOrganization());


SearchWsResponse.Builder response = SearchWsResponse.newBuilder(); SearchWsResponse.Builder response = SearchWsResponse.newBuilder();
response.setActions(SearchWsResponse.Actions.newBuilder().setCreate(data.isGlobalQProfileAdmin()));

response.setActions(SearchWsResponse.Actions.newBuilder().setCreate(isGlobalQProfileAdmin));
for (QProfileDto profile : profiles) { for (QProfileDto profile : profiles) {
QualityProfile.Builder profileBuilder = response.addProfilesBuilder(); QualityProfile.Builder profileBuilder = response.addProfilesBuilder();


profileBuilder.setIsBuiltIn(profile.isBuiltIn()); profileBuilder.setIsBuiltIn(profile.isBuiltIn());


profileBuilder.setActions(SearchWsResponse.QualityProfile.Actions.newBuilder() profileBuilder.setActions(SearchWsResponse.QualityProfile.Actions.newBuilder()
.setEdit(data.isEditable(profile))
.setSetAsDefault(data.isGlobalQProfileAdmin())
.setCopy(data.isGlobalQProfileAdmin()));
.setEdit(!profile.isBuiltIn() && (isGlobalQProfileAdmin || data.isEditable(profile)))
.setSetAsDefault(!isDefault && isGlobalQProfileAdmin)
.setCopy(isGlobalQProfileAdmin)
.setDelete(!isDefault && !profile.isBuiltIn() && (isGlobalQProfileAdmin || data.isEditable(profile)))
.setAssociateProjects(!isDefault && (isGlobalQProfileAdmin || data.isEditable(profile))));
} }

return response.build(); return response.build();
} }



+ 1
- 10
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchData.java View File

private Map<String, Long> projectCountByProfileKey; private Map<String, Long> projectCountByProfileKey;
private Set<String> defaultProfileKeys; private Set<String> defaultProfileKeys;
private Set<String> editableProfileKeys; private Set<String> editableProfileKeys;
private boolean isGlobalQProfileAdmin;


SearchData setOrganization(OrganizationDto organization) { SearchData setOrganization(OrganizationDto organization) {
this.organization = organization; this.organization = organization;
} }


boolean isEditable(QProfileDto profile) { boolean isEditable(QProfileDto profile) {
return !profile.isBuiltIn() && (isGlobalQProfileAdmin || editableProfileKeys.contains(profile.getKee()));
return editableProfileKeys.contains(profile.getKee());
} }


SearchData setEditableProfileKeys(List<String> editableProfileKeys) { SearchData setEditableProfileKeys(List<String> editableProfileKeys) {
return this; return this;
} }


boolean isGlobalQProfileAdmin() {
return isGlobalQProfileAdmin;
}

SearchData setGlobalQProfileAdmin(boolean globalQProfileAdmin) {
isGlobalQProfileAdmin = globalQProfileAdmin;
return this;
}
} }

+ 12
- 4
server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/search-example.json View File

"actions": { "actions": {
"edit": false, "edit": false,
"setAsDefault": false, "setAsDefault": false,
"copy": false
"copy": false,
"delete": false,
"associateProjects": false
} }
}, },
{ {
"actions": { "actions": {
"edit": true, "edit": true,
"setAsDefault": false, "setAsDefault": false,
"copy": false
"copy": false,
"delete": true,
"associateProjects": true
} }
}, },
{ {
"actions": { "actions": {
"edit": true, "edit": true,
"setAsDefault": false, "setAsDefault": false,
"copy": false
"copy": false,
"delete": false,
"associateProjects": false
} }
}, },
{ {
"actions": { "actions": {
"edit": false, "edit": false,
"setAsDefault": false, "setAsDefault": false,
"copy": false
"copy": false,
"delete": false,
"associateProjects": false
} }
} }
], ],

+ 23
- 11
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java View File



assertThat(definition.changelog()) assertThat(definition.changelog())
.extracting(Change::getVersion, Change::getDescription) .extracting(Change::getVersion, Change::getDescription)
.containsExactlyInAnyOrder(tuple("6.5", "The parameters 'defaults', 'project' and 'language' can be combined without any constraint"));
.containsExactlyInAnyOrder(
tuple("6.5", "The parameters 'defaults', 'project' and 'language' can be combined without any constraint"),
tuple("6.6", "Add available actions 'edit', 'copy' and 'setAsDefault' and global action 'create'"),
tuple("7.0", "Add available actions 'delete' and 'associateProjects'"));


WebService.Param organization = definition.param("organization"); WebService.Param organization = definition.param("organization");
assertThat(organization).isNotNull(); assertThat(organization).isNotNull();
OrganizationDto organization = db.organizations().insert(); OrganizationDto organization = db.organizations().insert();
QProfileDto customProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey())); QProfileDto customProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()));
QProfileDto builtInProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()).setIsBuiltIn(true)); QProfileDto builtInProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()).setIsBuiltIn(true));
QProfileDto defaultProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey()));
db.qualityProfiles().setAsDefault(defaultProfile);
UserDto user = db.users().insertUser(); UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); userSession.logIn(user).addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization);


SearchWsResponse result = call(ws.newRequest() SearchWsResponse result = call(ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())); .setParam(PARAM_ORGANIZATION, organization.getKey()));


assertThat(result.getProfilesList()).extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault())
assertThat(result.getProfilesList())
.extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(),
qp -> qp.getActions().getDelete(), qp -> qp.getActions().getAssociateProjects())
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple(customProfile.getKee(), true, true, true),
tuple(builtInProfile.getKee(), false, true, true));
tuple(customProfile.getKee(), true, true, true, true, true),
tuple(builtInProfile.getKee(), false, true, true, false, true),
tuple(defaultProfile.getKee(), true, true, false, false, false));
assertThat(result.getActions().getCreate()).isTrue(); assertThat(result.getActions().getCreate()).isTrue();
} }


SearchWsResponse result = call(ws.newRequest() SearchWsResponse result = call(ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())); .setParam(PARAM_ORGANIZATION, organization.getKey()));


assertThat(result.getProfilesList()).extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault())
assertThat(result.getProfilesList())
.extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(),
qp -> qp.getActions().getDelete(), qp -> qp.getActions().getAssociateProjects())
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple(profile1.getKee(), true, false, false),
tuple(profile2.getKee(), false, false, false),
tuple(profile3.getKee(), true, false, false),
tuple(builtInProfile.getKee(), false, false, false));
tuple(profile1.getKee(), true, false, false, true, true),
tuple(profile2.getKee(), false, false, false, false, false),
tuple(profile3.getKee(), true, false, false, true, true),
tuple(builtInProfile.getKee(), false, false, false, false, false));
assertThat(result.getActions().getCreate()).isFalse(); assertThat(result.getActions().getCreate()).isFalse();
} }


SearchWsResponse result = call(ws.newRequest() SearchWsResponse result = call(ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())); .setParam(PARAM_ORGANIZATION, organization.getKey()));


assertThat(result.getProfilesList()).extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault())
.containsExactlyInAnyOrder(tuple(profile.getKee(), false, false, false));
assertThat(result.getProfilesList())
.extracting(QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(),
qp -> qp.getActions().getDelete(), qp -> qp.getActions().getAssociateProjects())
.containsExactlyInAnyOrder(tuple(profile.getKee(), false, false, false, false, false));
assertThat(result.getActions().getCreate()).isFalse(); assertThat(result.getActions().getCreate()).isFalse();
} }



+ 3
- 1
sonar-ws/src/main/protobuf/ws-qualityprofiles.proto View File

optional bool edit = 1; optional bool edit = 1;
optional bool setAsDefault = 2; optional bool setAsDefault = 2;
optional bool copy = 3; optional bool copy = 3;
}
optional bool associateProjects = 4;
optional bool delete = 5;
}
} }


message Actions { message Actions {

+ 9
- 7
tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesEditTest.java View File

import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.sonarqube.tests.Category6Suite;
import org.sonarqube.qa.util.Tester; import org.sonarqube.qa.util.Tester;
import org.sonarqube.tests.Category6Suite;
import org.sonarqube.ws.Common; import org.sonarqube.ws.Common;
import org.sonarqube.ws.Organizations.Organization; import org.sonarqube.ws.Organizations.Organization;
import org.sonarqube.ws.Qualityprofiles.CreateWsResponse; import org.sonarqube.ws.Qualityprofiles.CreateWsResponse;
.qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey())); .qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey()));
assertThat(result.getActions().getCreate()).isFalse(); assertThat(result.getActions().getCreate()).isFalse();
assertThat(result.getProfilesList()) assertThat(result.getProfilesList())
.extracting(SearchWsResponse.QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault())
.extracting(SearchWsResponse.QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(),
qp -> qp.getActions().getDelete(), qp -> qp.getActions().getAssociateProjects())
.contains( .contains(
tuple(xooProfile1.getKey(), true, false, false),
tuple(xooProfile2.getKey(), true, false, false),
tuple(xooProfile3.getKey(), false, false, false));
tuple(xooProfile1.getKey(), true, false, false, true, true),
tuple(xooProfile2.getKey(), true, false, false, true, true),
tuple(xooProfile3.getKey(), false, false, false, false, false));
} }


@Test @Test
.qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey())); .qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey()));
assertThat(result.getActions().getCreate()).isTrue(); assertThat(result.getActions().getCreate()).isTrue();
assertThat(result.getProfilesList()) assertThat(result.getProfilesList())
.extracting(SearchWsResponse.QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault())
.extracting(SearchWsResponse.QualityProfile::getKey, qp -> qp.getActions().getEdit(), qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(),
qp -> qp.getActions().getDelete(), qp -> qp.getActions().getAssociateProjects())
.contains( .contains(
tuple(xooProfile.getKey(), true, true, true));
tuple(xooProfile.getKey(), true, true, true, true, true));
} }


@Test @Test

Loading…
Cancel
Save