From f25ece8fe820b708f08aac652cdda94183bcb2df Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 29 Nov 2017 15:07:50 +0100 Subject: [PATCH] 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 --- .../qualityprofile/ws/SearchAction.java | 36 ++++++++++--------- .../server/qualityprofile/ws/SearchData.java | 11 +----- .../qualityprofile/ws/search-example.json | 16 ++++++--- .../qualityprofile/ws/SearchActionTest.java | 34 ++++++++++++------ .../main/protobuf/ws-qualityprofiles.proto | 4 ++- .../QualityProfilesEditTest.java | 16 +++++---- 6 files changed, 67 insertions(+), 50 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java index cd83b7f721f..d3b5ce0d12b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java @@ -96,11 +96,14 @@ public class SearchAction implements QProfileWsAction { .setSince("5.2") .setDescription("Search quality profiles") .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")); - QProfileWsSupport.createOrganizationParam(action - ) + QProfileWsSupport.createOrganizationParam(action) .setSince("6.4"); action @@ -165,8 +168,7 @@ public class SearchAction implements QProfileWsAction { dbClient.activeRuleDao().countActiveRulesByQuery(dbSession, builder.setProfiles(profiles).setRuleStatus(DEPRECATED).build())) .setProjectCountByProfileKey(dbClient.qualityProfileDao().countProjectsByOrganizationAndProfiles(dbSession, organization, profiles)) .setDefaultProfileKeys(defaultProfiles) - .setEditableProfileKeys(editableProfiles) - .setGlobalQProfileAdmin(userSession.hasPermission(ADMINISTER_QUALITY_PROFILES, organization)); + .setEditableProfileKeys(editableProfiles); } } @@ -197,15 +199,14 @@ public class SearchAction implements QProfileWsAction { UserDto user = dbClient.userDao().selectActiveUserByLogin(dbSession, 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 searchProfiles(DbSession dbSession, SearchRequest request, OrganizationDto organization, List defaultProfiles, - @Nullable ComponentDto project) { + @Nullable ComponentDto project) { Collection profiles = selectAllProfiles(dbSession, organization); return profiles.stream() @@ -256,10 +257,10 @@ public class SearchAction implements QProfileWsAction { private SearchWsResponse buildResponse(SearchData data) { List profiles = data.getProfiles(); Map profilesByKey = profiles.stream().collect(Collectors.toMap(QProfileDto::getKee, identity())); + boolean isGlobalQProfileAdmin = userSession.hasPermission(ADMINISTER_QUALITY_PROFILES, data.getOrganization()); SearchWsResponse.Builder response = SearchWsResponse.newBuilder(); - response.setActions(SearchWsResponse.Actions.newBuilder().setCreate(data.isGlobalQProfileAdmin())); - + response.setActions(SearchWsResponse.Actions.newBuilder().setCreate(isGlobalQProfileAdmin)); for (QProfileDto profile : profiles) { QualityProfile.Builder profileBuilder = response.addProfilesBuilder(); @@ -284,11 +285,12 @@ public class SearchAction implements QProfileWsAction { profileBuilder.setIsBuiltIn(profile.isBuiltIn()); 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(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchData.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchData.java index d07bfcb13d3..20e4a7ad793 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchData.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchData.java @@ -39,7 +39,6 @@ class SearchData { private Map projectCountByProfileKey; private Set defaultProfileKeys; private Set editableProfileKeys; - private boolean isGlobalQProfileAdmin; SearchData setOrganization(OrganizationDto organization) { this.organization = organization; @@ -96,7 +95,7 @@ class SearchData { } boolean isEditable(QProfileDto profile) { - return !profile.isBuiltIn() && (isGlobalQProfileAdmin || editableProfileKeys.contains(profile.getKee())); + return editableProfileKeys.contains(profile.getKee()); } SearchData setEditableProfileKeys(List editableProfileKeys) { @@ -104,12 +103,4 @@ class SearchData { return this; } - boolean isGlobalQProfileAdmin() { - return isGlobalQProfileAdmin; - } - - SearchData setGlobalQProfileAdmin(boolean globalQProfileAdmin) { - isGlobalQProfileAdmin = globalQProfileAdmin; - return this; - } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/search-example.json index 7c3eabe8acc..eb13119b881 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/search-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/search-example.json @@ -15,7 +15,9 @@ "actions": { "edit": false, "setAsDefault": false, - "copy": false + "copy": false, + "delete": false, + "associateProjects": false } }, { @@ -37,7 +39,9 @@ "actions": { "edit": true, "setAsDefault": false, - "copy": false + "copy": false, + "delete": true, + "associateProjects": true } }, { @@ -55,7 +59,9 @@ "actions": { "edit": true, "setAsDefault": false, - "copy": false + "copy": false, + "delete": false, + "associateProjects": false } }, { @@ -72,7 +78,9 @@ "actions": { "edit": false, "setAsDefault": false, - "copy": false + "copy": false, + "delete": false, + "associateProjects": false } } ], diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java index 289ec3904f6..7beee7087de 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java @@ -97,7 +97,10 @@ public class SearchActionTest { assertThat(definition.changelog()) .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"); assertThat(organization).isNotNull(); @@ -328,16 +331,21 @@ public class SearchActionTest { OrganizationDto organization = db.organizations().insert(); 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 defaultProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO1.getKey())); + db.qualityProfiles().setAsDefault(defaultProfile); UserDto user = db.users().insertUser(); userSession.logIn(user).addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); SearchWsResponse result = call(ws.newRequest() .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( - 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(); } @@ -357,12 +365,14 @@ public class SearchActionTest { SearchWsResponse result = call(ws.newRequest() .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( - 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(); } @@ -375,8 +385,10 @@ public class SearchActionTest { SearchWsResponse result = call(ws.newRequest() .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(); } diff --git a/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto b/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto index 0b0039a2506..ddb6ebbe8ff 100644 --- a/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto +++ b/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto @@ -54,7 +54,9 @@ message SearchWsResponse { optional bool edit = 1; optional bool setAsDefault = 2; optional bool copy = 3; - } + optional bool associateProjects = 4; + optional bool delete = 5; + } } message Actions { diff --git a/tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesEditTest.java b/tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesEditTest.java index 6b6ed149993..9598bb0432f 100644 --- a/tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesEditTest.java +++ b/tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesEditTest.java @@ -24,8 +24,8 @@ import java.util.function.Predicate; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.sonarqube.tests.Category6Suite; import org.sonarqube.qa.util.Tester; +import org.sonarqube.tests.Category6Suite; import org.sonarqube.ws.Common; import org.sonarqube.ws.Organizations.Organization; import org.sonarqube.ws.Qualityprofiles.CreateWsResponse; @@ -213,11 +213,12 @@ public class QualityProfilesEditTest { .qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey())); assertThat(result.getActions().getCreate()).isFalse(); 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( - 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 @@ -231,9 +232,10 @@ public class QualityProfilesEditTest { .qProfiles().service().search(new SearchRequest().setOrganizationKey(organization.getKey())); assertThat(result.getActions().getCreate()).isTrue(); 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( - tuple(xooProfile.getKey(), true, true, true)); + tuple(xooProfile.getKey(), true, true, true, true, true)); } @Test -- 2.39.5