diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-03-05 18:24:19 +0100 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-03-09 15:24:56 +0100 |
commit | b90281447330980f6311c00f05c4da093b0bad5b (patch) | |
tree | 5c8fa78b813360f1137b660c53fe53fdb543b0ad | |
parent | 89c59ab53561a47b5067668829bb19e7067cd3be (diff) | |
download | sonarqube-b90281447330980f6311c00f05c4da093b0bad5b.tar.gz sonarqube-b90281447330980f6311c00f05c4da093b0bad5b.zip |
SONAR-6244 Add parameter and facet for issues assigned to authenticated user
8 files changed, 162 insertions, 28 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java index 9eb2a6277d6..6d819a69b26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java @@ -82,7 +82,9 @@ public class IssueQueryService implements ServerComponent { .rules(toRules(params.get(IssueFilterParameters.RULES))) .actionPlans(RubyUtils.toStrings(params.get(IssueFilterParameters.ACTION_PLANS))) .reporters(RubyUtils.toStrings(params.get(IssueFilterParameters.REPORTERS))) - .assignees(RubyUtils.toStrings(params.get(IssueFilterParameters.ASSIGNEES))) + .assignees(buildAssignees( + RubyUtils.toStrings(params.get(IssueFilterParameters.ASSIGNEES)), + RubyUtils.toBoolean(params.get(IssueFilterParameters.ASSIGNED_TO_ME)))) .languages(RubyUtils.toStrings(params.get(IssueFilterParameters.LANGUAGES))) .tags(RubyUtils.toStrings(params.get(IssueFilterParameters.TAGS))) .assigned(RubyUtils.toBoolean(params.get(IssueFilterParameters.ASSIGNED))) @@ -145,7 +147,9 @@ public class IssueQueryService implements ServerComponent { .rules(stringsToRules(request.paramAsStrings(IssueFilterParameters.RULES))) .actionPlans(request.paramAsStrings(IssueFilterParameters.ACTION_PLANS)) .reporters(request.paramAsStrings(IssueFilterParameters.REPORTERS)) - .assignees(request.paramAsStrings(IssueFilterParameters.ASSIGNEES)) + .assignees(buildAssignees( + request.paramAsStrings(IssueFilterParameters.ASSIGNEES), + request.paramAsBoolean(IssueFilterParameters.ASSIGNED_TO_ME))) .languages(request.paramAsStrings(IssueFilterParameters.LANGUAGES)) .tags(request.paramAsStrings(IssueFilterParameters.TAGS)) .assigned(request.paramAsBoolean(IssueFilterParameters.ASSIGNED)) @@ -186,6 +190,22 @@ public class IssueQueryService implements ServerComponent { } } + private List<String> buildAssignees(@Nullable List<String> assigneesFromParams, @Nullable Boolean assignedToMe) { + List<String> assignees = Lists.newArrayList(); + if (assigneesFromParams != null) { + assignees.addAll(assigneesFromParams); + } + if (BooleanUtils.isTrue(assignedToMe)) { + String login = UserSession.get().login(); + if (login == null) { + assignees.add(UNKNOWN); + } else { + assignees.add(login); + } + } + return assignees; + } + private boolean mergeDeprecatedComponentParameters(DbSession session, Boolean onComponentOnly, @Nullable Collection<String> components, @Nullable Collection<String> componentUuids, diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterParameters.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterParameters.java index b63bce55ead..8be25e80768 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterParameters.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterParameters.java @@ -58,6 +58,7 @@ public class IssueFilterParameters { public static final String LANGUAGES = "languages"; public static final String TAGS = "tags"; public static final String ASSIGNED = "assigned"; + public static final String ASSIGNED_TO_ME = "assigned_to_me"; public static final String PLANNED = "planned"; public static final String HIDE_RULES = "hideRules"; public static final String HIDE_COMMENTS = "hideComments"; @@ -72,7 +73,7 @@ public class IssueFilterParameters { public static final List<String> ALL = ImmutableList.of(ISSUES, SEVERITIES, STATUSES, RESOLUTIONS, RESOLVED, COMPONENTS, COMPONENT_ROOTS, RULES, ACTION_PLANS, REPORTERS, TAGS, ASSIGNEES, LANGUAGES, ASSIGNED, PLANNED, HIDE_RULES, CREATED_AT, CREATED_AFTER, CREATED_BEFORE, PAGE_SIZE, PAGE_INDEX, SORT, ASC, COMPONENT_UUIDS, COMPONENT_ROOT_UUIDS, - PROJECTS, PROJECT_UUIDS, IGNORE_PAGING, PROJECT_KEYS, COMPONENT_KEYS, MODULE_UUIDS, DIRECTORIES, FILE_UUIDS, AUTHORS, HIDE_COMMENTS); + PROJECTS, PROJECT_UUIDS, IGNORE_PAGING, PROJECT_KEYS, COMPONENT_KEYS, MODULE_UUIDS, DIRECTORIES, FILE_UUIDS, AUTHORS, HIDE_COMMENTS, ASSIGNED_TO_ME); public static final List<String> ALL_WITHOUT_PAGINATION = newArrayList(Iterables.filter(ALL, new Predicate<String>() { @Override diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 927cd512148..0339359c085 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -26,6 +26,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.StringUtils; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequestBuilder; @@ -87,6 +88,7 @@ public class IssueIndex extends BaseIndex { IssueFilterParameters.PROJECT_UUIDS, IssueFilterParameters.RULES, IssueFilterParameters.ASSIGNEES, + IssueFilterParameters.ASSIGNED_TO_ME, IssueFilterParameters.REPORTERS, IssueFilterParameters.AUTHORS, IssueFilterParameters.MODULE_UUIDS, @@ -390,6 +392,7 @@ public class IssueIndex extends BaseIndex { if (options.getFacets().contains(IssueFilterParameters.ASSIGNEES)) { esSearch.addAggregation(createAssigneesFacet(query, filters, esQuery)); } + addAssignedToMeFacetIfNeeded(esSearch, options, query, filters, esQuery); if (options.getFacets().contains(IssueFilterParameters.ACTION_PLANS)) { esSearch.addAggregation(createActionPlansFacet(query, filters, esQuery)); } @@ -473,16 +476,13 @@ public class IssueIndex extends BaseIndex { Map<String, FilterBuilder> assigneeFilters = Maps.newHashMap(filters); assigneeFilters.remove("__isAssigned"); assigneeFilters.remove(fieldName); + assigneeFilters.remove(IssueFilterParameters.ASSIGNED_TO_ME); StickyFacetBuilder assigneeFacetBuilder = new StickyFacetBuilder(queryBuilder, assigneeFilters); BoolFilterBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName); FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE); - List<String> assignees = Lists.newArrayList(query.assignees()); - - UserSession session = UserSession.get(); - if (session.isLoggedIn()) { - assignees.add(session.login()); + if (!query.assignees().isEmpty()) { + facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, query.assignees()); } - facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, assignees.toArray()); // Add missing facet for unassigned issues facetTopAggregation.subAggregation( @@ -496,6 +496,30 @@ public class IssueIndex extends BaseIndex { .subAggregation(facetTopAggregation); } + private void addAssignedToMeFacetIfNeeded(SearchRequestBuilder builder, SearchOptions options, IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder queryBuilder) { + if (!options.getFacets().contains(IssueFilterParameters.ASSIGNED_TO_ME)) { + return; + } + + String login = UserSession.get().login(); + if (StringUtils.isEmpty(login)) { + return; + } + + String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE; + String facetName = IssueFilterParameters.ASSIGNED_TO_ME; + + // Same as in super.stickyFacetBuilder + Map<String, FilterBuilder> assigneeFilters = Maps.newHashMap(filters); + StickyFacetBuilder assignedToMeFacetBuilder = new StickyFacetBuilder(queryBuilder, assigneeFilters); + BoolFilterBuilder facetFilter = assignedToMeFacetBuilder.getStickyFacetFilter("__assigned_to_me"); + + builder.addAggregation(AggregationBuilders + .filter(facetName) + .filter(facetFilter) + .subAggregation(AggregationBuilders.terms(facetName + "__terms").field(fieldName).include(login))); + } + private AggregationBuilder createResolutionFacet(Map<String, FilterBuilder> filters, QueryBuilder esQuery) { String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION; String facetName = IssueFilterParameters.RESOLUTIONS; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java index 9898640cb76..0cb1635ce86 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -63,13 +63,7 @@ import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; @@ -183,6 +177,9 @@ public class SearchAction implements BaseIssuesWsAction { action.createParam(IssueFilterParameters.ASSIGNED) .setDescription("To retrieve assigned or unassigned issues") .setBooleanPossibleValues(); + action.createParam(IssueFilterParameters.ASSIGNED_TO_ME) + .setDescription("To retrieve issues assigned to the authenticating user. Only valid when providing user credentials") + .setBooleanPossibleValues(); action.createParam(IssueFilterParameters.LANGUAGES) .setDescription("Comma-separated list of languages. Available since 4.4") .setExampleValue("java,js"); @@ -400,11 +397,8 @@ public class SearchAction implements BaseIssuesWsAction { if (assigneesFromRequest != null) { assignees.addAll(assigneesFromRequest); } - UserSession userSession = UserSession.get(); - if (userSession.isLoggedIn()) { - assignees.add(userSession.login()); - } addMandatoryFacetValues(results, IssueFilterParameters.ASSIGNEES, assignees); + addMandatoryFacetValues(results, IssueFilterParameters.ASSIGNED_TO_ME, Arrays.asList(UserSession.get().login())); addMandatoryFacetValues(results, IssueFilterParameters.REPORTERS, request.paramAsStrings(IssueFilterParameters.REPORTERS)); addMandatoryFacetValues(results, IssueFilterParameters.RULES, request.paramAsStrings(IssueFilterParameters.RULES)); addMandatoryFacetValues(results, IssueFilterParameters.LANGUAGES, request.paramAsStrings(IssueFilterParameters.LANGUAGES)); @@ -432,7 +426,10 @@ public class SearchAction implements BaseIssuesWsAction { json.prop("count", bucket.getValue()); json.endObject(); } - addZeroFacetsForSelectedItems(request, facetName, itemsFromFacets, json); + // Prevent appearance of a glitch value due to dedicated parameter for this facet + if (!IssueFilterParameters.ASSIGNED_TO_ME.equals(facetName)) { + addZeroFacetsForSelectedItems(request, facetName, itemsFromFacets, json); + } } json.endArray().endObject(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java index 2c00d1216ce..8b597b89e13 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java @@ -88,7 +88,7 @@ public class SearchActionMediumTest { assertThat(show.isPost()).isFalse(); assertThat(show.isInternal()).isFalse(); assertThat(show.responseExampleAsString()).isNotEmpty(); - assertThat(show.params()).hasSize(39); + assertThat(show.params()).hasSize(40); } @Test @@ -428,12 +428,61 @@ public class SearchActionMediumTest { .setParam("resolved", "false") .setParam("severities", "MAJOR,MINOR") .setParam("languages", "xoo,polop,palap") - .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans") + .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,assigned_to_me,languages,actionPlans") .execute(); result.assertJson(this.getClass(), "display_zero_facets.json", false); } @Test + public void filter_by_assigned_to_me() throws Exception { + ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); + setDefaultProjectPermission(project); + ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); + RuleDto rule = newRule(); + IssueDto issue1 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) + .setStatus("OPEN") + .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") + .setSeverity("MAJOR") + .setAssignee("john"); + IssueDto issue2 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) + .setStatus("OPEN") + .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2") + .setSeverity("MAJOR") + .setAssignee("alice"); + IssueDto issue3 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) + .setStatus("OPEN") + .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2") + .setSeverity("MAJOR"); + db.issueDao().insert(session, issue1, issue2, issue3); + session.commit(); + tester.get(IssueIndexer.class).indexAll(); + + MockUserSession.set().setLogin("john"); + wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) + .setParam("resolved", "false") + .setParam("assigned_to_me", "true") + .setParam(WebService.Param.FACETS, "assignees,assigned_to_me") + .execute() + .assertJson(this.getClass(), "filter_by_assigned_to_me.json", false); + + MockUserSession.set(); + wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) + .setParam("resolved", "false") + .setParam("assigned_to_me", "true") + .execute() + .assertJson(this.getClass(), "empty_result.json", false); + } + + @Test public void hide_rules() throws Exception { ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); setDefaultProjectPermission(project); diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_facets.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_facets.json index c6f088839e6..88f059cb366 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_facets.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_facets.json @@ -120,10 +120,6 @@ { "val": "", "count": 1 - }, - { - "val": "john", - "count": 0 } ] }, diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_zero_facets.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_zero_facets.json index 5869e5b15c7..0cfa8bb25e2 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_zero_facets.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_zero_facets.json @@ -120,7 +120,12 @@ { "val": "", "count": 1 - }, + } + ] + }, + { + "property": "assigned_to_me", + "values": [ { "val": "john", "count": 0 diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/filter_by_assigned_to_me.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/filter_by_assigned_to_me.json new file mode 100644 index 00000000000..013ff81376e --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/filter_by_assigned_to_me.json @@ -0,0 +1,42 @@ +{ + "issues": [ + { + "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", + "component": "MyComponent", + "project": "MyProject", + "rule": "xoo:x1", + "status": "OPEN", + "severity": "MAJOR", + "debt": "10min", + "fUpdateAge": "less than a minute", + "assignee": "john" + } + ], + "facets": [ + { + "property": "assignees", + "values": [ + { + "val": "john", + "count": 1 + }, + { + "val": "alice", + "count": 1 + }, + { + "val": "", + "count": 1 + } + ] + }, + { + "property": "assigned_to_me", + "values": [ + { + "val": "john", + "count": 1 + } + ] + } + ]} |