From a06137eb1111b48e20ccc2f0ac5989e35bd83c55 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Thu, 13 Jun 2013 16:19:11 +0200 Subject: [PATCH] SONAR-4383 Save issue filter --- .../resources/org/sonar/l10n/core.properties | 4 + .../sonar/core/issue/DefaultIssueFilter.java | 85 +++++++----- .../core/issue/DefaultIssueFilterTest.java | 87 +++++++++++++ .../core/issue/db/IssueFilterDaoTest.java | 2 + .../issue/InternalRubyIssueService.java | 122 ++++++++++++------ .../server/issue/IssueFilterService.java | 99 +++++--------- .../app/controllers/issues_controller.rb | 114 +++++++++++++--- .../webapp/WEB-INF/app/models/issue_filter.rb | 79 ------------ .../app/views/issues/_action_links.html.erb | 18 +++ .../WEB-INF/app/views/issues/_list.html.erb | 10 +- .../app/views/issues/_save_as_form.html.erb | 40 ++++++ .../app/views/issues/_sidebar.html.erb | 9 +- .../WEB-INF/app/views/issues/search.html.erb | 12 +- .../issue/InternalRubyIssueServiceTest.java | 33 +++++ .../server/issue/IssueFilterServiceTest.java | 35 ----- .../org/sonar/wsclient/issue/ActionPlan.java | 5 +- .../java/org/sonar/wsclient/issue/Issue.java | 5 +- .../sonar/wsclient/issue/IssueComment.java | 4 +- .../java/org/sonar/wsclient/issue/Issues.java | 5 +- 19 files changed, 479 insertions(+), 289 deletions(-) create mode 100644 sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueFilterTest.java delete mode 100644 sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index ada129c357d..6caab7f672a 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -530,6 +530,10 @@ issue_filter.criteria.severity=Severity issue_filter.criteria.status=Status issue_filter.max_results_reached=Only the first {0} issues matching the search criteria have been retrieved. Add some additional criteria to get fewer results to be able to sort this list. issue_filter.no_result=No matching issues found. +issue_filter.save_filter=Save Filter +issue_filter.form.name=Name +issue_filter.form.description=Description +issue_filter.form.share=Shared with all users #------------------------------------------------------------------------------ diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueFilter.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueFilter.java index e5047917679..020f89b1ae2 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueFilter.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueFilter.java @@ -37,14 +37,14 @@ import static com.google.common.collect.Maps.newHashMap; public class DefaultIssueFilter { - public static String SEPARATOR = "|"; - public static String KEY_VALUE_SEPARATOR = "="; - public static String LIST_SEPARATOR = ","; + public final static String SEPARATOR = "|"; + public final static String KEY_VALUE_SEPARATOR = "="; + public final static String LIST_SEPARATOR = ","; private Long id; private String name; private String user; - private Boolean shared; + private Boolean shared = false; private String description; private String data; private Date createdAt; @@ -54,6 +54,18 @@ public class DefaultIssueFilter { } + public static DefaultIssueFilter create(String name) { + DefaultIssueFilter issueFilter = new DefaultIssueFilter(); + Date now = new Date(); + issueFilter.setName(name); + issueFilter.setCreatedAt(now).setUpdatedAt(now); + return issueFilter; + } + + public DefaultIssueFilter(Map mapData) { + this.data = mapAsdata(mapData); + } + public Long id() { return id; } @@ -127,6 +139,9 @@ public class DefaultIssueFilter { return this; } + /** + * Used by ui + */ public Map dataAsMap(){ return dataAsMap(data); } @@ -138,16 +153,15 @@ public class DefaultIssueFilter { Iterable keyValues = Splitter.on(DefaultIssueFilter.SEPARATOR).split(data); for (String keyValue : keyValues) { String[] keyValueSplit = StringUtils.split(keyValue, DefaultIssueFilter.KEY_VALUE_SEPARATOR); - if (keyValueSplit.length != 2) { - throw new IllegalArgumentException("Key value should be separate by a '"+ DefaultIssueFilter.KEY_VALUE_SEPARATOR + "'"); - } - String key = keyValueSplit[0]; - String value = keyValueSplit[1]; - String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR); - if (listValues.length > 1) { - map.put(key, newArrayList(listValues)); - } else { - map.put(key, value); + if (keyValueSplit.length == 2) { + String key = keyValueSplit[0]; + String value = keyValueSplit[1]; + String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR); + if (listValues.length > 1) { + map.put(key, newArrayList(listValues)); + } else { + map.put(key, value); + } } } return map; @@ -160,27 +174,32 @@ public class DefaultIssueFilter { for (Map.Entry entries : map.entrySet()){ String key = entries.getKey(); Object value = entries.getValue(); - - stringBuilder.append(key); - stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR); - - List valuesList = newArrayList(); - if (value instanceof List) { - // assume that it contains only strings - valuesList = (List) value; - } else if (value instanceof CharSequence) { - valuesList = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) value)); - } else { - stringBuilder.append(value); - } - for (Iterator valueListIter = valuesList.iterator(); valueListIter.hasNext();) { - Object valueList = valueListIter.next(); - stringBuilder.append(valueList); - if (valueListIter.hasNext()) { - stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR); + if (value != null) { + List valuesList = newArrayList(); + if (value instanceof List) { + // assume that it contains only strings + valuesList = (List) value; + } else if (value instanceof CharSequence) { + valuesList = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) value)); + } else { + stringBuilder.append(key); + stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR); + stringBuilder.append(value); + stringBuilder.append(DefaultIssueFilter.SEPARATOR); + } + if (!valuesList.isEmpty()) { + stringBuilder.append(key); + stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR); + for (Iterator valueListIter = valuesList.iterator(); valueListIter.hasNext();) { + Object valueList = valueListIter.next(); + stringBuilder.append(valueList); + if (valueListIter.hasNext()) { + stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR); + } + } + stringBuilder.append(DefaultIssueFilter.SEPARATOR); } } - stringBuilder.append(DefaultIssueFilter.SEPARATOR); } if (stringBuilder.length() > 0) { diff --git a/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueFilterTest.java b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueFilterTest.java new file mode 100644 index 00000000000..4bf9d656f50 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueFilterTest.java @@ -0,0 +1,87 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.issue; + +import org.junit.Test; + +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; + +public class DefaultIssueFilterTest { + + DefaultIssueFilter issueFilter = new DefaultIssueFilter(); + + @Test + public void should_convert_data_to_map() { + String data = "issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50"; + + Map map = issueFilter.dataAsMap(data); + + assertThat(map).hasSize(5); + assertThat(map.get("issues")).isEqualTo("ABCDE1234"); + assertThat(map.get("severities")).isInstanceOf(List.class); + assertThat((List) 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_remove_empty_value_when_converting_data_to_map() { + String data = "issues=ABCDE1234|severities="; + + Map map = issueFilter.dataAsMap(data); + + assertThat(map).hasSize(1); + assertThat(map.get("issues")).isEqualTo("ABCDE1234"); + } + + @Test + public void should_convert_map_to_data() { + Map 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 = issueFilter.mapAsdata(map); + + assertThat(result).isEqualTo("issues=ABCDE1234|severities=MAJOR,MINOR|resolved=true|pageSize=10|pageIndex=50"); + } + + @Test + public void should_remove_empty_value_when_converting_convert_map_to_data() { + Map map = newLinkedHashMap(); + map.put("issues", newArrayList("ABCDE1234")); + map.put("resolved", null); + map.put("pageSize", ""); + + String result = issueFilter.mapAsdata(map); + + assertThat(result).isEqualTo("issues=ABCDE1234"); + } + +} diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterDaoTest.java index b8619fae88b..de841318b98 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterDaoTest.java @@ -72,6 +72,8 @@ public class IssueFilterDaoTest extends AbstractDaoTestCase { dao.insert(filterDto); + assertThat(filterDto.getId()).isNotNull(); + checkTables("should_insert", new String[]{"created_at", "updated_at"}, "issue_filters"); } diff --git a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java index e944d5a325b..c8c2967d2f5 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java @@ -280,41 +280,14 @@ public class InternalRubyIssueService implements ServerComponent { String projectParam = parameters.get("project"); Date deadLine = null; - if (Strings.isNullOrEmpty(name)) { - result.addError(Result.Message.ofL10n("errors.cant_be_empty", "name")); - } else { - if (name.length() > 200) { - result.addError(Result.Message.ofL10n("errors.is_too_long", "name", 200)); - } - } - - if (!Strings.isNullOrEmpty(description) && description.length() > 1000) { - result.addError(Result.Message.ofL10n("errors.is_too_long", "description", 1000)); - } + checkMandatorySizeParameter(name, "name", 200, result); + checkOptionnalSizeParameter(description, "description", 1000, result); // Can only set project on creation if (existingActionPlan == null) { - if (Strings.isNullOrEmpty(projectParam)) { - result.addError(Result.Message.ofL10n("errors.cant_be_empty", "project")); - } else { - ResourceDto project = resourceDao.getResource(ResourceQuery.create().setKey(projectParam)); - if (project == null) { - result.addError(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", projectParam)); - } - } - } - - if (!Strings.isNullOrEmpty(deadLineParam)) { - try { - deadLine = RubyUtils.toDate(deadLineParam); - Date today = new Date(); - if (deadLine != null && deadLine.before(today) && !org.apache.commons.lang.time.DateUtils.isSameDay(deadLine, today)) { - result.addError(Result.Message.ofL10n("action_plans.date_cant_be_in_past")); - } - } catch (SonarException e) { - result.addError(Result.Message.ofL10n("errors.is_not_valid", "date")); - } + checkProject(projectParam, result); } + deadLine = checkAndReturnDeadline(deadLineParam, result); if (!Strings.isNullOrEmpty(projectParam) && !Strings.isNullOrEmpty(name) && (existingActionPlan == null || !name.equals(existingActionPlan.name())) && actionPlanService.isNameAlreadyUsedForProject(name, projectParam)) { @@ -339,6 +312,33 @@ public class InternalRubyIssueService implements ServerComponent { return result; } + private void checkProject(String projectParam, Result result){ + if (Strings.isNullOrEmpty(projectParam)) { + result.addError(Result.Message.ofL10n("errors.cant_be_empty", "project")); + } else { + ResourceDto project = resourceDao.getResource(ResourceQuery.create().setKey(projectParam)); + if (project == null) { + result.addError(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", projectParam)); + } + } + } + + private Date checkAndReturnDeadline(String deadLineParam, Result result){ + Date deadLine = null; + if (!Strings.isNullOrEmpty(deadLineParam)) { + try { + deadLine = RubyUtils.toDate(deadLineParam); + Date today = new Date(); + if (deadLine != null && deadLine.before(today) && !org.apache.commons.lang.time.DateUtils.isSameDay(deadLine, today)) { + result.addError(Result.Message.ofL10n("action_plans.date_cant_be_in_past")); + } + } catch (SonarException e) { + result.addError(Result.Message.ofL10n("errors.is_not_valid", "date")); + } + } + return deadLine; + } + private Result createResultForExistingActionPlan(String actionPlanKey) { Result result = Result.of(); if (findActionPlan(actionPlanKey) == null) { @@ -369,6 +369,14 @@ public class InternalRubyIssueService implements ServerComponent { return PublicRubyIssueService.toQuery(props); } + public DefaultIssueFilter findIssueFilter(Long id) { + return issueFilterService.findById(id, UserSession.get()); + } + + public DefaultIssueFilter createFilterFromMap(Map mapData) { + return issueFilterService.createEmptyFilter(mapData); + } + /** * Execute issue filter */ @@ -379,29 +387,69 @@ public class InternalRubyIssueService implements ServerComponent { /** * Create issue filter */ - public void createIssueFilter(Map params) { + public Result createIssueFilter(Map params) { Result result = Result.of(); try { // mandatory parameters String name = params.get("name"); String description = params.get("description"); String data = params.get("data"); + Boolean shared = RubyUtils.toBoolean(params.get("shared")); if (result.ok()) { - DefaultIssueFilter defaultIssueFilter = new DefaultIssueFilter() - .setName(name) + DefaultIssueFilter defaultIssueFilter = DefaultIssueFilter.create(name) .setDescription(description) - .setData(data) - ; - defaultIssueFilter = issueFilterService.create(defaultIssueFilter, UserSession.get()); + .setShared(shared) + .setData(data); + defaultIssueFilter = issueFilterService.save(defaultIssueFilter, UserSession.get()); result.set(defaultIssueFilter); } } catch (Exception e) { result.addError(e.getMessage()); } + return result; + } + @VisibleForTesting + Result createIssueFilterResult(Map params) { + Result result = Result.of(); + + // mandatory parameters + String name = params.get("name"); + String description = params.get("description"); + String data = params.get("data"); + Boolean shared = RubyUtils.toBoolean(params.get("shared")); + + checkMandatorySizeParameter(name, "name", 100, result); + checkOptionnalSizeParameter(description, "description", 4000, result); + + // TODO check name uniquness + + if (result.ok()) { + DefaultIssueFilter defaultIssueFilter = DefaultIssueFilter.create(name) + .setDescription(description) + .setShared(shared) + .setData(data); + result.set(defaultIssueFilter); + } + return result; } + private void checkMandatorySizeParameter(String value, String paramName, Integer size, Result result){ + if (Strings.isNullOrEmpty(value)) { + result.addError(Result.Message.ofL10n("errors.cant_be_empty", paramName)); + } else { + if (value.length() > size) { + result.addError(Result.Message.ofL10n("errors.is_too_long", paramName, size)); + } + } + } + + private void checkOptionnalSizeParameter(String value, String paramName, Integer size, Result result){ + if (!Strings.isNullOrEmpty(value) && value.length() > size) { + result.addError(Result.Message.ofL10n("errors.is_too_long", paramName, size)); + } + } } \ No newline at end of file diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java index d57b32537eb..61dd367abc3 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueFilterService.java @@ -20,10 +20,6 @@ package org.sonar.server.issue; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import org.apache.commons.lang.StringUtils; import org.sonar.api.ServerComponent; import org.sonar.api.issue.IssueFinder; import org.sonar.api.issue.IssueQuery; @@ -33,12 +29,9 @@ import org.sonar.core.issue.db.IssueFilterDao; 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; +import javax.annotation.CheckForNull; -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; +import java.util.Map; public class IssueFilterService implements ServerComponent { @@ -50,11 +43,32 @@ public class IssueFilterService implements ServerComponent { this.issueFinder = issueFinder; } - public DefaultIssueFilter create(DefaultIssueFilter issueFilter, UserSession userSession) { + @CheckForNull + public DefaultIssueFilter createEmptyFilter(Map mapData) { + return new DefaultIssueFilter(mapData); + } + + @CheckForNull + public DefaultIssueFilter findById(Long id, UserSession userSession) { // TODO // checkAuthorization(userSession, project, UserRole.ADMIN); - issueFilterDao.insert(IssueFilterDto.toIssueFilter(issueFilter)); - return issueFilter; + verifyLoggedIn(userSession); +// access_denied unless filter.shared || filter.owner?(current_user) + + IssueFilterDto issueFilterDto = issueFilterDao.selectById(id); + if (issueFilterDto == null) { + return null; + } + return issueFilterDto.toIssueFilter(); + } + + public DefaultIssueFilter save(DefaultIssueFilter issueFilter, UserSession userSession) { + issueFilter.setUser(userSession.login()); + // TODO +// checkAuthorization(userSession, project, UserRole.ADMIN); + IssueFilterDto issueFilterDto = IssueFilterDto.toIssueFilter(issueFilter); + issueFilterDao.insert(issueFilterDto); + return issueFilterDto.toIssueFilter(); } public DefaultIssueFilter update(DefaultIssueFilter issueFilter, UserSession userSession) { @@ -89,64 +103,11 @@ public class IssueFilterService implements ServerComponent { return null; } - @VisibleForTesting - Map dataAsMap(String data) { - Map map = newHashMap(); - - Iterable keyValues = Splitter.on(DefaultIssueFilter.SEPARATOR).split(data); - for (String keyValue : keyValues) { - String[] keyValueSplit = StringUtils.split(keyValue, DefaultIssueFilter.KEY_VALUE_SEPARATOR); - if (keyValueSplit.length != 2) { - throw new IllegalArgumentException("Key value should be separate by a '"+ DefaultIssueFilter.KEY_VALUE_SEPARATOR + "'"); - } - String key = keyValueSplit[0]; - String value = keyValueSplit[1]; - String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR); - if (listValues.length > 1) { - map.put(key, newArrayList(listValues)); - } else { - map.put(key, value); - } + private void verifyLoggedIn(UserSession userSession) { + if (!userSession.isLoggedIn()) { + // must be logged + throw new IllegalStateException("User is not logged in"); } - return map; - } - - @VisibleForTesting - String mapAsdata(Map map) { - StringBuilder stringBuilder = new StringBuilder(); - - for (Map.Entry entries : map.entrySet()){ - String key = entries.getKey(); - Object value = entries.getValue(); - - stringBuilder.append(key); - stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR); - - List valuesList = newArrayList(); - if (value instanceof List) { - // assume that it contains only strings - valuesList = (List) value; - } else if (value instanceof CharSequence) { - valuesList = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) value)); - } else { - stringBuilder.append(value); - } - for (Iterator valueListIter = valuesList.iterator(); valueListIter.hasNext();) { - Object valueList = valueListIter.next(); - stringBuilder.append(valueList); - 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(); } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb index da523e067fa..cafdd7f75a7 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb @@ -20,36 +20,120 @@ class IssuesController < ApplicationController - before_filter :init + before_filter :init_options + # GET /issues/index def index redirect_to :action => 'search' end + # GET /issues/search def search - init_results + if params[:id] + @filter = find_filter(params[:id].to_i) + else + @filter = Internal.issues.createFilterFromMap(criteria_params) + end - @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) + @issue_query = Internal.issues.toQuery(@filter.dataAsMap) @issues_result = Internal.issues.execute(@issue_query) - @paging = @issues_result.paging - @issues = @issues_result.issues end - private + # Load existing filter + # GET /issues/filter/ + def filter + require_parameters :id + + @filter = find_filter(params[:id].to_i) + @issue_query = Internal.issues.toQuery(@filter.dataAsMap) + + # criteria can be overridden + # TODO ? + #@filter.override_criteria(criteria_params) + + @issues_result = Internal.issues.execute(@issue_query) + @unchanged = true + render :action => 'search' + end - def init_results - @issues_result = nil - @paging = nil - @issues = nil - #criteria['pageSize'] = 100 - self + # GET /issues/save_as_form?[id=][&criteria] + def save_as_form + if params[:id].present? + @filter = find_filter(params[:id]) + else + @filter = Internal.issues.createFilterFromMap(criteria_params) + end + render :partial => 'issues/save_as_form' end - def init + # POST /issues/save_as?[id=]&name=[¶meters] + def save_as + verify_post_request + access_denied unless logged_in? + + options = {'name' => params[:name], 'description' => params[:description], 'data' => URI.unescape(params[:data]), 'shared' => params[:shared]=='true' } + add_to_favourites=false + if params[:id].present? + # TODO + #@filter = Internal.issues.updateIssueFilter(params[:id], options) + else + filter_result = Internal.issues.createIssueFilter(options) + add_to_favourites=true + end + + if filter_result.ok + @filter = filter_result.get() + puts "#### "+ @filter.id.to_s + #current_user.favourited_measure_filters<<@filter if add_to_favourites + render :text => @filter.id.to_s, :status => 200 + else + @errors = filter_result.errors + render :partial => 'issues/save_as_form', :status => 400 + end + end + + # POST /issues/save?id=&[criteria] + # TODO + def save + verify_post_request + require_parameters :id + access_denied unless logged_in? + + @filter = find_filter(params[:id]) + + #@filter = Internal.issues.updateIssueFilter(params[:id], options) + + #@filter.criteria=criteria_params_without_page_id + #@filter.convert_criteria_to_data + #unless @filter.save + # flash[:error]='Error' + #end + redirect_to :action => 'filter', :id => @filter.id + end + + private + + def init_options @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 + # TODO + def find_filter(id) + filter = Internal.issues.findIssueFilter(id) + # TODO + #access_denied unless filter.shared || filter.owner?(current_user) + filter + end + + def criteria_params + criteria = params + criteria.delete('controller') + criteria.delete('action') + criteria.delete('search') + criteria.delete('edit') + criteria.delete('pageSize') + criteria + end + end \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb deleted file mode 100644 index 09423ffc863..00000000000 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/issue_filter.rb +++ /dev/null @@ -1,79 +0,0 @@ -# -# Sonar, entreprise quality control tool. -# Copyright (C) 2008-2013 SonarSource -# mailto:contact AT sonarsource DOT com -# -# SonarQube is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 3 of the License, or (at your option) any later version. -# -# SonarQube is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -require 'set' -class IssueFilter - - attr_reader :paging, :issues, :issues_result - - def criteria(key=nil) - @criteria ||= HashWithIndifferentAccess.new - if key - @criteria[key] - else - @criteria - end - end - - def criteria=(hash) - @criteria = HashWithIndifferentAccess.new - hash.each_pair do |k, v| - set_criteria_value(k, v) - end - end - - def override_criteria(hash) - @criteria ||= HashWithIndifferentAccess.new - hash.each_pair do |k, v| - set_criteria_value(k, v) - end - end - - # API used by Displays - def set_criteria_value(key, value) - @criteria ||= HashWithIndifferentAccess.new - if key - if value!=nil && value!='' && value!=[''] - value = (value.kind_of?(Array) ? value : value.to_s) - @criteria[key]=value - else - @criteria.delete(key) - end - end - end - - def execute - init_results - @issues_result = Api.issues.find(criteria) - @paging = @issues_result.paging - @issues = @issues_result.issues - self - end - - private - - def init_results - @issues_result = nil - @paging = nil - @issues = nil - criteria['pageSize'] = 100 - self - end - -end \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb new file mode 100644 index 00000000000..32cfd27c28b --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_action_links.html.erb @@ -0,0 +1,18 @@ +
    + <% if logged_in? %> + <% if @filter.id %> + + + <% end %> + <% if !defined?(@unchanged) && @filter.id && @filter.user == current_user.login %> +
  • + <%= link_to message('save'), params.merge({:action => 'save', :id => @filter.id}), :class => 'link-action', :id => 'save', :method => :post -%> +
  • + <% end %> + <% unless @filter.id %> +
  • + <%= message('save_as') -%> +
  • + <% end %> +<% end %> +
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb index 9b93373ad25..6f1e0ba429e 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_list.html.erb @@ -18,10 +18,10 @@ <% end %> <% - if @issues && !@issues.empty? + if @issues_result.issues && !@issues_result.issues.empty? colspan = 9 %> -
+
@@ -59,7 +59,7 @@ <% - @issues.each do |issue| + @issues_result.issues.each do |issue| %> <% end %> - <%= paginate_java(@paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id| + <%= paginate_java(@issues_result.paging, :colspan => colspan, :id => 'issue-filter-foot', :include_loading_icon => true) { |label, page_id| link_to(label, params.merge({:pageIndex => page_id})) } -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb new file mode 100644 index 00000000000..10dcaf7a402 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_save_as_form.html.erb @@ -0,0 +1,40 @@ + + + +
+ + + + +
+ + \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb index dc762c5b1f5..01e6a783115 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_sidebar.html.erb @@ -1,6 +1,9 @@
@@ -102,14 +102,14 @@ <% end %> - <% if @issues.empty? %> + <% if @issues_result.issues.empty? %>
<%= message 'no_data' -%>