r.plugin_name=#{rule.repository} and r.plugin_rule_key=#{rule.rule}</foreach>)
</if>
<where>
- <if test="query.issueKeys() != null">
+ <if test="query.issueKeys() != null and query.issueKeys().size() > 0">
and i.kee in
<foreach item="key" index="index" collection="query.issueKeys()" open="(" separator="," close=")">#{key}
</foreach>
</if>
- <if test="query.severities() != null">
+ <if test="query.severities() != null and query.severities().size() > 0">
and i.severity in
<foreach item="severity" index="index" collection="query.severities()" open="(" separator="," close=")">#{severity}
</foreach>
</if>
- <if test="query.statuses() != null">
+ <if test="query.statuses() != null and query.statuses().size() > 0">
and i.status in
<foreach item="status" index="index" collection="query.statuses()" open="(" separator="," close=")">#{status}
</foreach>
</if>
- <if test="query.resolutions() != null">
+ <if test="query.resolutions() != null and query.resolutions().size() > 0">
and i.resolution in
<foreach item="resolution" index="index" collection="query.resolutions()" open="(" separator="," close=")">#{resolution}
</foreach>
and i.resolution is null
</if>
</if>
- <if test="query.reporters() != null">
+ <if test="query.reporters() != null and query.reporters().size() > 0">
and i.reporter in
<foreach item="reporter" index="index" collection="query.reporters()" open="(" separator="," close=")">#{reporter}
</foreach>
</if>
- <if test="query.assignees() != null">
+ <if test="query.assignees() != null and query.assignees().size() > 0">
and i.assignee in
<foreach item="assignee" index="index" collection="query.assignees()" open="(" separator="," close=")">#{assignee}
</foreach>
and i.action_plan_key is null
</if>
</if>
- <if test="query.actionPlans() != null">
+ <if test="query.actionPlans() != null and query.actionPlans().size() > 0">
and i.action_plan_key in
<foreach item="action_plan" index="index" collection="query.actionPlans()" open="(" separator="," close=")">
#{action_plan}
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
-import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.issue.*;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.ActionPlanStats;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssueBuilder;
+import org.sonar.core.issue.DefaultIssueFilter;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
private final IssueStatsFinder issueStatsFinder;
private final ResourceDao resourceDao;
private final ActionService actionService;
+ private final IssueFilterService issueFilterService;
public InternalRubyIssueService(IssueService issueService,
IssueCommentService commentService,
IssueChangelogService changelogService, ActionPlanService actionPlanService,
- IssueStatsFinder issueStatsFinder, ResourceDao resourceDao, ActionService actionService) {
+ IssueStatsFinder issueStatsFinder, ResourceDao resourceDao, ActionService actionService,
+ IssueFilterService issueFilterService) {
this.issueService = issueService;
this.commentService = commentService;
this.changelogService = changelogService;
this.issueStatsFinder = issueStatsFinder;
this.resourceDao = resourceDao;
this.actionService = actionService;
+ this.issueFilterService = issueFilterService;
}
public IssueStatsFinder.IssueStatsResult findIssueAssignees(Map<String, Object> params) {
}
public Result<Issue> executeAction(String issueKey, String actionKey) {
- // TODO verify authorization
-
Result<Issue> result = Result.of();
try {
result.set(actionService.execute(issueKey, actionKey, UserSession.get()));
return PublicRubyIssueService.toQuery(props);
}
+ /**
+ * Execute issue filter
+ */
+ public IssueQueryResult execute(IssueQuery issueQuery) {
+ return issueFilterService.execute(issueQuery);
+ }
+
+ /**
+ * Create issue filter
+ */
+ public void createIssueFilter(Map<String, String> params) {
+ Result<DefaultIssueFilter> result = Result.of();
+ try {
+ // mandatory parameters
+ String name = params.get("name");
+ String description = params.get("description");
+ String data = params.get("data");
+
+ if (result.ok()) {
+ DefaultIssueFilter defaultIssueFilter = new DefaultIssueFilter()
+ .setName(name)
+ .setDescription(description)
+ .setData(data)
+ ;
+ defaultIssueFilter = issueFilterService.create(defaultIssueFilter, UserSession.get());
+ result.set(defaultIssueFilter);
+ }
+
+ } catch (Exception e) {
+ result.addError(e.getMessage());
+ }
+
+ }
+
+
}
\ No newline at end of file
import org.sonar.core.issue.db.IssueFilterDto;
import org.sonar.server.user.UserSession;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
this.issueFinder = issueFinder;
}
- public DefaultIssueFilter create(DefaultIssueFilter issueFilter, IssueQuery issueQuery, UserSession userSession) {
+ public DefaultIssueFilter create(DefaultIssueFilter issueFilter, UserSession userSession) {
// TODO
// checkAuthorization(userSession, project, UserRole.ADMIN);
issueFilterDao.insert(IssueFilterDto.toIssueFilter(issueFilter));
@VisibleForTesting
Map<String, Object> dataAsMap(String data) {
- Map<String, Object> props = newHashMap();
+ Map<String, Object> map = newHashMap();
Iterable<String> keyValues = Splitter.on(DefaultIssueFilter.SEPARATOR).split(data);
for (String keyValue : keyValues) {
String value = keyValueSplit[1];
String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR);
if (listValues.length > 1) {
- props.put(key, newArrayList(listValues));
+ map.put(key, newArrayList(listValues));
} else {
- props.put(key, value);
+ map.put(key, value);
}
}
- return props;
+ return map;
}
@VisibleForTesting
- String mapAsdata(Map<String, Object> props) {
+ String mapAsdata(Map<String, Object> map) {
StringBuilder stringBuilder = new StringBuilder();
- for (Map.Entry<String, Object> entries : props.entrySet()){
+ for (Map.Entry<String, Object> entries : map.entrySet()){
String key = entries.getKey();
Object value = entries.getValue();
} else {
stringBuilder.append(value);
}
- for (Object valueList : valuesList) {
+ for (Iterator<Object> valueListIter = valuesList.iterator(); valueListIter.hasNext();) {
+ Object valueList = valueListIter.next();
stringBuilder.append(valueList);
- stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR);
+ if (valueListIter.hasNext()) {
+ stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR);
+ }
}
-
stringBuilder.append(DefaultIssueFilter.SEPARATOR);
}
+
+ if (stringBuilder.length() > 0) {
+ // Delete useless last separator character
+ stringBuilder.deleteCharAt(stringBuilder.length() - 1);
+ }
+
return stringBuilder.toString();
}
import com.google.common.base.Function;
import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import org.sonar.api.issue.IssueFinder;
.pageSize(RubyUtils.toInteger(props.get("pageSize")))
.pageIndex(RubyUtils.toInteger(props.get("pageIndex")));
String sort = (String) props.get("sort");
- if (sort != null) {
+ if (!Strings.isNullOrEmpty(sort)) {
builder.sort(sort);
builder.asc(RubyUtils.toBoolean(props.get("asc")));
}
end
def search
- @filter = IssueFilter.new
- @filter.criteria=criteria_params
- @filter.execute
+ init_results
+
+ @criteria_params = params.merge({:controller => nil, :action => nil, :search => nil, :widget_id => nil, :edit => nil})
+ @criteria_params['pageSize'] = 100
+ @issue_query = Internal.issues.toQuery(@criteria_params)
+ @issues_result = Internal.issues.execute(@issue_query)
+ @paging = @issues_result.paging
+ @issues = @issues_result.issues
end
-
private
+ def init_results
+ @issues_result = nil
+ @paging = nil
+ @issues = nil
+ #criteria['pageSize'] = 100
+ self
+ end
+
def init
@options_for_statuses = Internal.issues.listStatus().map {|s| [message('issue.status.' + s), s]}
@options_for_resolutions = Internal.issues.listResolutions().map {|s| [message('issue.resolution.' + s), s]}
end
- def criteria_params
- params.merge({:controller => nil, :action => nil, :search => nil, :widget_id => nil, :edit => nil})
- end
-
end
\ No newline at end of file
#
module IssuesHelper
- def column_html(filter, column_label, column_tooltip, sort)
- filter_sort = filter.criteria[:sort]
- filter_asc = filter.criteria[:asc] == 'true' ? true : false
+ def column_html(issue_query, issues_result, column_label, column_tooltip, sort)
+ filter_sort = issue_query.sort
+ filter_asc = issue_query.asc
html = h(column_label)
- unless filter.issues_result.maxResultsReached()
- html = link_to_function(h(column_label), "refreshList('#{escape_javascript sort}',#{!filter_asc}, #{filter.criteria[:page]||1})", :title => h(column_tooltip))
+ unless issues_result.maxResultsReached()
+ html = link_to_function(h(column_label), "refreshList('#{escape_javascript sort}',#{!filter_asc}, #{issue_query.pageIndex||1})", :title => h(column_tooltip))
if sort == filter_sort
html << (filter_asc ? image_tag("asc12.png") : image_tag("desc12.png"))
end
<% content_for :script do %>
<script>
- var filterCriteria = <%= @filter.criteria.to_json -%>;
+ var filterCriteria = <%= @criteria_params.to_json -%>;
function refreshList(sort, asc, page) {
$j('#issue-filter-foot_pages').hide();
<% end %>
<%
- if @filter.issues && !@filter.issues.empty?
+ if @issues && !@issues.empty?
colspan = 9
%>
<div>
<thead>
<tr>
<th width="1%" nowrap class="column-severity">
- <%= column_html(@filter, message('severity_abbreviated'), message('severity'), 'SEVERITY') %>
+ <%= column_html(@issue_query, @issues_result, message('severity_abbreviated'), message('severity'), 'SEVERITY') %>
</th>
<th width="1%" nowrap class="column-status">
- <%= column_html(@filter, message('status'), message('status'), 'STATUS') %>
+ <%= column_html(@issue_query, @issues_result, message('status'), message('status'), 'STATUS') %>
</th>
<th width="1%" nowrap>
<%= message('issue_filter.header.resolution') -%>
<%= message('component') -%>
</th>
<th class="column-assignee">
- <%= column_html(@filter, message('issue_filter.header.assignee'), message('issue_filter.header.assignee'), 'ASSIGNEE') %>
+ <%= column_html(@issue_query, @issues_result, message('issue_filter.header.assignee'), message('issue_filter.header.assignee'), 'ASSIGNEE') %>
</th>
<th width="1%" nowrap>
<%= message('issue_filter.header.action_plan') -%>
</th>
<th width="1%" nowrap class="column-creation-date">
- <%= column_html(@filter, message('issue_filter.header.creation_date'), message('issue_filter.header.creation_date'), 'CREATION_DATE') %>
+ <%= column_html(@issue_query, @issues_result, message('issue_filter.header.creation_date'), message('issue_filter.header.creation_date'), 'CREATION_DATE') %>
</th>
<th width="1%" nowrap class="column-update-date">
- <%= column_html(@filter, message('issue_filter.header.update_date'), message('issue_filter.header.update_date'), 'UPDATE_DATE') %>
+ <%= column_html(@issue_query, @issues_result, message('issue_filter.header.update_date'), message('issue_filter.header.update_date'), 'UPDATE_DATE') %>
</th>
</tr>
</thead>
<tbody>
<%
- @filter.issues.each do |issue|
+ @issues.each do |issue|
%>
<tr class="<%= cycle('even', 'odd') -%>">
<td width="1%" nowrap>
<%= h truncate(issue.message, :length => 100) -%></a>
</td>
<td>
- <%= h (truncate(@filter.issues_result.project(issue).name, :length => 100)) -%>
+ <%= h (truncate(@issues_result.project(issue).name, :length => 100)) -%>
</td>
<td>
- <% component = @filter.issues_result.component(issue) %>
+ <% component = @issues_result.component(issue) %>
<% if component %>
<%= h component.longName() -%>
<% else %>
<% end %>
</td>
<td>
- <%= h @filter.issues_result.user(issue.assignee).name if issue.assignee -%>
+ <%= h @issues_result.user(issue.assignee).name if issue.assignee -%>
</td>
<td>
- <%= h @filter.issues_result.actionPlan(issue).name if issue.actionPlanKey() -%>
+ <%= h @issues_result.actionPlan(issue).name if issue.actionPlanKey() -%>
</td>
<td width="1%" nowrap>
<%= human_short_date(Api::Utils.java_to_ruby_datetime(issue.creationDate())) -%>
<%
end
%>
- <% if @filter.issues.empty? %>
+ <% if @issues.empty? %>
<tr class="even">
<td colspan="<%= colspan -%>"><%= message 'no_data' -%></td>
</tr>
<% end %>
</tbody>
- <%= paginate_java(@filter.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id|
- link_to(label, @filter.criteria.merge({:pageIndex => page_id}))
+ <%= paginate_java(@paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id|
+ link_to(label, params.merge({:pageIndex => page_id}))
} -%>
</table>
</div>
<%
- elsif @filter.issues
+ elsif @issues
%>
<p><%= message('issue_filter.no_result') -%></p>
<%
<ul class="sidebar gray-sidebar">
<form method="GET" action="<%= ApplicationController.root_context -%>/issues/search" >
- <input type="hidden" name="sort" value="<%= @filter.criteria('sort')-%>"/>
- <input type="hidden" name="asc" value="<%= @filter.criteria('asc') -%>"/>
+ <input type="hidden" name="sort" value="<%= @issue_query.sort -%>"/>
+ <input type="hidden" name="asc" value="<%= @issue_query.asc -%>"/>
<li class="sidebar-title">
<%= message('issue_filter.new_search') -%>
</li>
<li id="criteria-project" class="marginbottom5">
<%= message 'issue_filter.criteria.project' -%>:
- <% selected_componentRoot = Internal.component_api.findByKey(@filter.criteria('componentRoots')) if @filter.criteria('componentRoots') %>
+ <% selected_componentRoot = Internal.component_api.findByKey(@issue_query.componentRoots.get(0)) if @issue_query.componentRoots and @issue_query.componentRoots.size == 1 %>
<%= component_select_tag 'componentRoots', :resource_type_property => 'supportsGlobalDashboards', :width => '100%',
:selected_resource => selected_componentRoot,
:display_key => true,
</li>
<li id="criteria-severity" class="marginbottom5">
<%= message 'issue_filter.criteria.severity' -%>:
- <%= dropdown_tag 'severities[]', options_for_select(RulesConfigurationController::RULE_PRIORITIES, @filter.criteria('severities')),
+ <%= dropdown_tag 'severities[]', options_for_select(RulesConfigurationController::RULE_PRIORITIES, @issue_query.severities),
{:width => '100%', :placeholder => message('issue_filter.criteria.severity')},
{:id => 'select-severities', :multiple => true}-%>
</li>
<li id="criteria-status" class="marginbottom5">
<%= message 'issue_filter.criteria.status' -%>:
- <%= dropdown_tag 'statuses[]', options_for_select(@options_for_statuses, @filter.criteria('statuses')),
+ <%= dropdown_tag 'statuses[]', options_for_select(@options_for_statuses, @issue_query.statuses),
{:width => '100%', :placeholder => message('issue_filter.criteria.status')},
{:id => 'select-status', :multiple => true}-%>
</li>
<li id="criteria-resolution" class="marginbottom5">
<%= message 'issue_filter.criteria.resolution' -%>:
- <%= dropdown_tag 'resolutions[]', options_for_select(@options_for_resolutions, @filter.criteria('resolutions')),
+ <%= dropdown_tag 'resolutions[]', options_for_select(@options_for_resolutions, @issue_query.resolutions),
{:width => '100%', :placeholder => message('issue_filter.criteria.resolution')},
{:id => 'select-resolution', :multiple => true}-%>
</li>
<li id="criteria-assignee" class="marginbottom5">
<%= message 'issue_filter.criteria.assignee' -%>:
- <% selected_assignee = Api.users.findByLogin(@filter.criteria('assignees')) if @filter.criteria('assignees') %>
+ <% selected_assignee = Api.users.findByLogin(@issue_query.assignees.get(0)) if @issue_query.assignees && @issue_query.assignees.size == 1 %>
<%= user_select_tag('assignees', {:selected_user => selected_assignee, :width => '100%', :placeholder => message('issue_filter.criteria.assignee'),
:html_id => 'select-assignee', :open => false, :allow_clear => true}) -%>
</li>
<li id="criteria-reporter" class="marginbottom5">
<%= message 'issue_filter.criteria.reporter' -%>:
- <% selected_reporter = Api.users.findByLogin(@filter.criteria('reporters')) if @filter.criteria('reporters') %>
+ <% selected_reporter = Api.users.findByLogin(@issue_query.reporters.get(0)) if @issue_query.reporters && @issue_query.reporters.size == 1 %>
<%= user_select_tag('reporters', {:selected_user => selected_reporter, :width => '100%', :placeholder => message('issue_filter.criteria.reporter'),
:html_id => 'select-reporter', :open => false, :allow_clear => true}) -%>
</li>
<li id="criteria-created" class="marginbottom5">
<%= message('issue_filter.criteria.created_after') -%>:<br>
- <input type="text" id="select-created-after" name="createdAfter" value="<%= @filter.criteria['createdAfter'] -%>" size="10" maxlength="10" class="marginbottom5">
+ <input type="text" id="select-created-after" name="createdAfter" value="<%= @issue_query.createdAfter -%>" size="10" maxlength="10" class="marginbottom5">
<br>
<%= message 'issue_filter.criteria.created_before' -%>:<br>
- <input type="text" id="select-created-before" name="createdBefore" value="<%= @filter.criteria['createdBefore'] -%>" size="10" maxlength="10"><br>
+ <input type="text" id="select-created-before" name="createdBefore" value="<%= @issue_query.createdBefore -%>" size="10" maxlength="10"><br>
<span class="small gray"><%= message 'issue_filter.criteria.date_format' -%></span>
</li>
<li>
<div class="page-split-right">
<div id="content">
<div class="marginbottom10">
- <% if @filter.issues_result && @filter.issues_result.maxResultsReached() %>
- <p class="notes"><%= message('issue_filter.max_results_reached', :params => @filter.paging.total()) -%></p>
+ <% if @issues_result && @issues_result.maxResultsReached() %>
+ <p class="notes"><%= message('issue_filter.max_results_reached', :params => @paging.total()) -%></p>
<% end %>
<%= render :partial => 'list' -%>
</div>
ResourceDao resourceDao = mock(ResourceDao.class);
IssueStatsFinder issueStatsFinder = mock(IssueStatsFinder.class);
ActionService actionService = mock(ActionService.class);
+ IssueFilterService issueFilterService = mock(IssueFilterService.class);
@Before
public void setUp() {
ResourceDto project = new ResourceDto().setKey("org.sonar.Sample");
when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(project);
- service = new InternalRubyIssueService(issueService, commentService, changelogService, actionPlanService, issueStatsFinder, resourceDao, actionService);
+ service = new InternalRubyIssueService(issueService, commentService, changelogService, actionPlanService, issueStatsFinder, resourceDao, actionService, issueFilterService);
}
@Test
import org.sonar.api.issue.IssueFinder;
import org.sonar.core.issue.db.IssueFilterDao;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newLinkedHashMap;
+import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public class IssueFilterServiceTest {
service = new IssueFilterService(issueFilterDao, issueFinder);
}
+ @Test
+ public void should_convert_data_to_map() {
+ String data = "issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50";
+
+ Map<String, Object> map = service.dataAsMap(data);
+
+ assertThat(map).hasSize(5);
+ assertThat(map.get("issues")).isEqualTo("ABCDE1234");
+ assertThat(map.get("severities")).isInstanceOf(List.class);
+ assertThat((List<String>) map.get("severities")).contains("MAJOR", "MINOR");
+ assertThat(map.get("resolved")).isEqualTo("true");
+ assertThat(map.get("pageSize")).isEqualTo("10");
+ assertThat(map.get("pageIndex")).isEqualTo("50");
+ }
+
@Test
public void should_convert_map_to_data() {
+ Map<String, Object> map = newLinkedHashMap();
+ map.put("issues", newArrayList("ABCDE1234"));
+ map.put("severities", newArrayList("MAJOR", "MINOR"));
+ map.put("resolved", true);
+ map.put("pageSize", 10l);
+ map.put("pageIndex", 50);
+
+ String result = service.mapAsdata(map);
+ assertThat(result).isEqualTo("issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50");
}
}