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 edittags/7.0-RC1
.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(); | ||||
} | } | ||||
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; | |||||
} | |||||
} | } |
"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 | |||||
} | } | ||||
} | } | ||||
], | ], |
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(); | ||||
} | } | ||||
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 { |
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 |