From: Julien Lancelot Date: Tue, 18 Jun 2013 14:22:09 +0000 (+0200) Subject: SONAR-4393 Manage favourite issue filters X-Git-Tag: 3.7~452 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fa2fcc0312a3c22a03e1c28bdd42ab4e45249c45;p=sonarqube.git SONAR-4393 Manage favourite issue filters --- diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDao.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDao.java index 679b02e7915..d74fafd02ae 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDao.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDao.java @@ -31,7 +31,7 @@ import javax.annotation.Nullable; import java.util.List; /** - * @since 3.6 + * @since 3.7 */ public class IssueFilterDao implements BatchComponent, ServerComponent { @@ -56,7 +56,6 @@ public class IssueFilterDao implements BatchComponent, ServerComponent { public IssueFilterDto selectByNameAndUser(String name, String user, @Nullable Long existingId) { SqlSession session = mybatis.openSession(); try { - session.getMapper(IssueFilterMapper.class); return getMapper(session).selectByNameAndUser(name, user, existingId); } finally { MyBatis.closeQuietly(session); @@ -66,13 +65,21 @@ public class IssueFilterDao implements BatchComponent, ServerComponent { public List selectByUser(String user) { SqlSession session = mybatis.openSession(); try { - session.getMapper(IssueFilterMapper.class); return getMapper(session).selectByUser(user); } finally { MyBatis.closeQuietly(session); } } + public List selectByUserWithOnlyFavoriteFilters(String user) { + SqlSession session = mybatis.openSession(); + try { + return getMapper(session).selectByUserWithOnlyFavoriteFilters(user); + } finally { + MyBatis.closeQuietly(session); + } + } + public void insert(IssueFilterDto filter) { SqlSession session = mybatis.openSession(); try { diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDto.java index 9fe5c1e6291..ac366e66a1f 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDto.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterDto.java @@ -26,7 +26,7 @@ import javax.annotation.Nullable; import java.util.Date; /** - * @since 3.6 + * @since 3.7 */ public class IssueFilterDto { @@ -61,7 +61,7 @@ public class IssueFilterDto { return userLogin; } - public IssueFilterDto setUserLogin(@Nullable String userLogin) { + public IssueFilterDto setUserLogin(String userLogin) { this.userLogin = userLogin; return this; } diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDao.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDao.java new file mode 100644 index 00000000000..2f692c1b967 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDao.java @@ -0,0 +1,80 @@ +/* + * 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.db; + +import org.apache.ibatis.session.SqlSession; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; +import org.sonar.core.persistence.MyBatis; + +/** + * @since 3.7 + */ +public class IssueFilterFavouriteDao implements BatchComponent, ServerComponent { + + private final MyBatis mybatis; + + public IssueFilterFavouriteDao(MyBatis mybatis) { + this.mybatis = mybatis; + } + + public IssueFilterFavouriteDto selectById(Long id) { + SqlSession session = mybatis.openSession(); + try { + return getMapper(session).selectById(id); + } finally { + MyBatis.closeQuietly(session); + } + } + + public IssueFilterFavouriteDto selectByUserAndIssueFilterId(String user, Long issueFilterId) { + SqlSession session = mybatis.openSession(); + try { + return getMapper(session).selectByIssueFilterId(user, issueFilterId); + } finally { + MyBatis.closeQuietly(session); + } + } + + public void insert(IssueFilterFavouriteDto filter) { + SqlSession session = mybatis.openSession(); + try { + getMapper(session).insert(filter); + session.commit(); + } finally { + MyBatis.closeQuietly(session); + } + } + + public void delete(Long id) { + SqlSession session = mybatis.openSession(); + try { + getMapper(session).delete(id); + session.commit(); + } finally { + MyBatis.closeQuietly(session); + } + } + + private IssueFilterFavouriteMapper getMapper(SqlSession session) { + return session.getMapper(IssueFilterFavouriteMapper.class); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDto.java new file mode 100644 index 00000000000..b59dcbf4e4b --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteDto.java @@ -0,0 +1,70 @@ +/* + * 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.db; + +import java.util.Date; + +/** + * @since 3.7 + */ +public class IssueFilterFavouriteDto { + + private Long id; + private String userLogin; + private Long issueFilterId; + private Date createdAt; + + public Long getId() { + return id; + } + + public IssueFilterFavouriteDto setId(Long id) { + this.id = id; + return this; + } + + public String getUserLogin() { + return userLogin; + } + + public IssueFilterFavouriteDto setUserLogin(String userLogin) { + this.userLogin = userLogin; + return this; + } + + public Long getIssueFilterId() { + return issueFilterId; + } + + public IssueFilterFavouriteDto setIssueFilterId(Long issueFilterId) { + this.issueFilterId = issueFilterId; + return this; + } + + public Date getCreatedAt() { + return createdAt; + } + + public IssueFilterFavouriteDto setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + return this; + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteMapper.java new file mode 100644 index 00000000000..03986f82118 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterFavouriteMapper.java @@ -0,0 +1,40 @@ +/* + * 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.db; + +import org.apache.ibatis.annotations.Param; + +import javax.annotation.CheckForNull; + +/** + * @since 3.7 + */ +public interface IssueFilterFavouriteMapper { + + @CheckForNull + IssueFilterFavouriteDto selectById(Long id); + + @CheckForNull + IssueFilterFavouriteDto selectByIssueFilterId(@Param("userLogin") String userLogin, @Param("issueFilterId") Long issueFilterId); + + void insert(IssueFilterFavouriteDto filterFavourite); + + void delete(Long id); +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterMapper.java index 86f10e01c7b..f07316f07a1 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueFilterMapper.java @@ -27,7 +27,7 @@ import javax.annotation.Nullable; import java.util.List; /** - * @since 3.6 + * @since 3.7 */ public interface IssueFilterMapper { @@ -39,6 +39,8 @@ public interface IssueFilterMapper { List selectByUser(String user); + List selectByUserWithOnlyFavoriteFilters(String user); + void insert(IssueFilterDto filter); void update(IssueFilterDto filter); diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java index db936c44976..6cbb0c6e736 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java @@ -60,6 +60,7 @@ public final class DaoUtils { IssueStatsDao.class, IssueChangeDao.class, IssueFilterDao.class, + IssueFilterFavouriteDao.class, LoadedTemplateDao.class, MeasureFilterDao.class, PropertiesDao.class, diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java index 90b83920742..59959a44502 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java @@ -116,6 +116,7 @@ public class MyBatis implements BatchComponent, ServerComponent { loadAlias(conf, "Issue", IssueDto.class); loadAlias(conf, "IssueChange", IssueChangeDto.class); loadAlias(conf, "IssueFilter", IssueFilterDto.class); + loadAlias(conf, "IssueFilterFavourite", IssueFilterFavouriteDto.class); loadAlias(conf, "SnapshotData", SnapshotDataDto.class); loadAlias(conf, "ActionPlanIssue", ActionPlanDto.class); loadAlias(conf, "ActionPlanStats", ActionPlanStatsDto.class); @@ -127,7 +128,7 @@ public class MyBatis implements BatchComponent, ServerComponent { Class[] mappers = {ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class, DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, - IssueMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, + IssueMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class, LoadedTemplateMapper.class, MeasureFilterMapper.class, PropertiesMapper.class, PurgeMapper.class, ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceSnapshotMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class, MeasureMapper.class, SnapshotDataMapper.class, diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterFavouriteMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterFavouriteMapper.xml new file mode 100644 index 00000000000..3c8d2db4718 --- /dev/null +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterFavouriteMapper.xml @@ -0,0 +1,49 @@ + + + + + + + + filter_favourites.id as id, + filter_favourites.user_login as userLogin, + filter_favourites.issue_filter_id as issueFilterId, + filter_favourites.created_at as createdAt + + + + + + + + INSERT INTO issue_filter_favourites (user_login, issue_filter_id, created_at) + VALUES (#{userLogin}, #{issueFilterId}, current_timestamp) + + + + + + select issue_filter_favourites_seq.NEXTVAL from DUAL + + INSERT INTO issue_filter_favourites (id, user_login, issue_filter_id, created_at) + VALUES (#{id},#{userLogin}, #{issueFilterId}, current_timestamp) + + + + delete from issue_filter_favourites where id=#{id} + + + diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterMapper.xml index 291f90db47f..2d62e89af3d 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueFilterMapper.xml @@ -43,6 +43,15 @@ + + INSERT INTO issue_filters (name, user_login, shared, description, data, created_at, updated_at) VALUES (#{name}, #{userLogin}, #{shared}, #{description}, #{data}, #{createdAt}, #{updatedAt}) 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 4f6b9001a0d..514a7b29d7c 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 @@ -70,6 +70,17 @@ public class IssueFilterDaoTest extends AbstractDaoTestCase { assertThat(results).hasSize(2); } + @Test + public void should_select_by_user_with_only_favorite_filters() { + setupData("should_select_by_user_with_only_favorite_filters"); + + List results = dao.selectByUserWithOnlyFavoriteFilters("michael"); + + assertThat(results).hasSize(1); + IssueFilterDto issueFilterDto = results.get(0); + assertThat(issueFilterDto.getId()).isEqualTo(2L); + } + @Test public void should_insert() { setupData("shared"); @@ -83,8 +94,6 @@ 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-core/src/test/java/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest.java new file mode 100644 index 00000000000..4cdaa9de69e --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest.java @@ -0,0 +1,86 @@ +/* + * 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.db; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.core.persistence.AbstractDaoTestCase; + +import static org.fest.assertions.Assertions.assertThat; + +public class IssueFilterFavouriteDaoTest extends AbstractDaoTestCase { + + IssueFilterFavouriteDao dao; + + @Before + public void createDao() { + dao = new IssueFilterFavouriteDao(getMyBatis()); + } + + @Test + public void should_select_by_id() { + setupData("shared"); + + IssueFilterFavouriteDto issueFilterFavouriteDto = dao.selectById(1L); + assertThat(issueFilterFavouriteDto.getId()).isEqualTo(1L); + assertThat(issueFilterFavouriteDto.getUserLogin()).isEqualTo("stephane"); + assertThat(issueFilterFavouriteDto.getIssueFilterId()).isEqualTo(10L); + assertThat(issueFilterFavouriteDto.getCreatedAt()).isNotNull(); + + assertThat(dao.selectById(999L)).isNull(); + } + + @Test + public void should_select_by_issue_filter_id() { + setupData("shared"); + + IssueFilterFavouriteDto issueFilterFavouriteDto = dao.selectByUserAndIssueFilterId("stephane", 10L); + assertThat(issueFilterFavouriteDto.getId()).isEqualTo(1L); + assertThat(issueFilterFavouriteDto.getUserLogin()).isEqualTo("stephane"); + assertThat(issueFilterFavouriteDto.getIssueFilterId()).isEqualTo(10L); + assertThat(issueFilterFavouriteDto.getCreatedAt()).isNotNull(); + + assertThat(dao.selectByUserAndIssueFilterId("stephane", 999L)).isNull(); + } + + @Test + public void should_insert() { + setupData("shared"); + + IssueFilterFavouriteDto issueFilterFavouriteDto = new IssueFilterFavouriteDto(); + issueFilterFavouriteDto.setUserLogin("arthur"); + issueFilterFavouriteDto.setIssueFilterId(11L); + + dao.insert(issueFilterFavouriteDto); + + checkTables("should_insert", new String[]{"created_at"}, "issue_filter_favourites"); + } + + @Test + public void should_delete() { + setupData("shared"); + + dao.delete(3l); + + checkTables("should_delete", new String[]{"created_at"}, "issue_filter_favourites"); + } + +} diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterDaoTest/should_select_by_user_with_only_favorite_filters.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterDaoTest/should_select_by_user_with_only_favorite_filters.xml new file mode 100644 index 00000000000..f378fb9b8e8 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterDaoTest/should_select_by_user_with_only_favorite_filters.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/shared.xml new file mode 100644 index 00000000000..e963d10483d --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/shared.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_delete-result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_delete-result.xml new file mode 100644 index 00000000000..03670a10ba0 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_delete-result.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_insert-result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_insert-result.xml new file mode 100644 index 00000000000..7fa5aff1c21 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueFilterFavouriteDaoTest/should_insert-result.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + 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 8cdbd1166e8..e44e0bffd6c 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 @@ -397,7 +397,7 @@ public class InternalRubyIssueService implements ServerComponent { /** * List user issue filter */ - public List findIssueFiltersForUser() { + public List findIssueFiltersForCurrentUser() { return issueFilterService.findByUser(UserSession.get()); } @@ -450,10 +450,10 @@ public class InternalRubyIssueService implements ServerComponent { public Result deleteIssueFilter(Long issueFilterId) { Result result = Result.of(); try { - issueFilterService.delete(issueFilterId, UserSession.get()); - } catch (Exception e) { - result.addError(e.getMessage()); - } + issueFilterService.delete(issueFilterId, UserSession.get()); + } catch (Exception e) { + result.addError(e.getMessage()); + } return result; } @@ -502,6 +502,20 @@ public class InternalRubyIssueService implements ServerComponent { return result; } + public List findFavouriteIssueFiltersForCurrentUser() { + return issueFilterService.findFavoriteFilters(UserSession.get()); + } + + public Result toggleFavouriteIssueFilter(Long issueFilterId) { + Result result = Result.of(); + try { + issueFilterService.toggleFavouriteIssueFilter(issueFilterId, UserSession.get()); + } catch (Exception e) { + result.addError(e.getMessage()); + } + return result; + } + private void checkMandatoryParameter(String value, String paramName, Result result) { if (Strings.isNullOrEmpty(value)) { result.addError(Result.Message.ofL10n("errors.cant_be_empty", paramName)); 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 02c0ca17ed2..8de1a6da836 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 @@ -29,6 +29,8 @@ import org.sonar.api.issue.IssueQueryResult; import org.sonar.core.issue.DefaultIssueFilter; import org.sonar.core.issue.db.IssueFilterDao; import org.sonar.core.issue.db.IssueFilterDto; +import org.sonar.core.issue.db.IssueFilterFavouriteDao; +import org.sonar.core.issue.db.IssueFilterFavouriteDto; import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; @@ -41,24 +43,36 @@ import static com.google.common.collect.Lists.newArrayList; public class IssueFilterService implements ServerComponent { - private IssueFilterDao issueFilterDao; + private final IssueFilterDao issueFilterDao; + private final IssueFilterFavouriteDao issueFilterFavouriteDao; private final IssueFinder issueFinder; - public IssueFilterService(IssueFilterDao issueFilterDao, IssueFinder issueFinder) { + public IssueFilterService(IssueFilterDao issueFilterDao, IssueFilterFavouriteDao issueFilterFavouriteDao, IssueFinder issueFinder) { this.issueFilterDao = issueFilterDao; + this.issueFilterFavouriteDao = issueFilterFavouriteDao; this.issueFinder = issueFinder; } + public IssueQueryResult execute(IssueQuery issueQuery) { + return issueFinder.find(issueQuery); + } + + public IssueQueryResult execute(Long issueFilterId, UserSession userSession) { + IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId, userSession); + + DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter(); + IssueQuery issueQuery = PublicRubyIssueService.toQuery(issueFilter.dataAsMap()); + return issueFinder.find(issueQuery); + } + @CheckForNull public DefaultIssueFilter findById(Long id, UserSession userSession) { - verifyLoggedIn(userSession); - IssueFilterDto issueFilterDto = findIssueFilter(id); - verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); + IssueFilterDto issueFilterDto = findIssueFilter(id, userSession); return issueFilterDto.toIssueFilter(); } public List findByUser(UserSession userSession) { - if (userSession.isLoggedIn()) { + if (userSession.isLoggedIn() && userSession.login() != null) { List issueFilterDtoList = issueFilterDao.selectByUser(userSession.login()); return newArrayList(Iterables.transform(issueFilterDtoList, new Function() { @Override @@ -77,13 +91,12 @@ public class IssueFilterService implements ServerComponent { IssueFilterDto issueFilterDto = IssueFilterDto.toIssueFilter(issueFilter); issueFilterDao.insert(issueFilterDto); + addFavouriteIssueFilter(issueFilterDto.getId(), userSession.login()); return issueFilterDto.toIssueFilter(); } public DefaultIssueFilter update(DefaultIssueFilter issueFilter, UserSession userSession) { - verifyLoggedIn(userSession); - IssueFilterDto issueFilterDto = findIssueFilter(issueFilter.id()); - verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); + findIssueFilter(issueFilter.id(), userSession); verifyNameIsNotAlreadyUsed(issueFilter, userSession); issueFilterDao.update(IssueFilterDto.toIssueFilter(issueFilter)); @@ -91,9 +104,7 @@ public class IssueFilterService implements ServerComponent { } public DefaultIssueFilter updateData(Long issueFilterId, Map mapData, UserSession userSession) { - verifyLoggedIn(userSession); - IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId); - verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); + IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId, userSession); DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter(); issueFilter.setData(mapData); issueFilterDao.update(IssueFilterDto.toIssueFilter(issueFilter)); @@ -101,15 +112,16 @@ public class IssueFilterService implements ServerComponent { } public void delete(Long issueFilterId, UserSession userSession) { - verifyLoggedIn(userSession); - IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId); - verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); + findIssueFilter(issueFilterId, userSession); + IssueFilterFavouriteDto issueFilterFavouriteDto = findFavouriteIssueFilter(userSession.login(), issueFilterId); + if (issueFilterFavouriteDto != null) { + deleteFavouriteIssueFilter(issueFilterFavouriteDto.getId()); + } issueFilterDao.delete(issueFilterId); } public DefaultIssueFilter copy(Long issueFilterIdToCopy, DefaultIssueFilter issueFilter, UserSession userSession) { - verifyLoggedIn(userSession); - IssueFilterDto issueFilterDtoToCopy = findIssueFilter(issueFilterIdToCopy); + IssueFilterDto issueFilterDtoToCopy = findIssueFilter(issueFilterIdToCopy, userSession); issueFilter.setUser(userSession.login()); issueFilter.setData(issueFilterDtoToCopy.getData()); verifyNameIsNotAlreadyUsed(issueFilter, userSession); @@ -119,25 +131,37 @@ public class IssueFilterService implements ServerComponent { return issueFilterDto.toIssueFilter(); } - public IssueQueryResult execute(IssueQuery issueQuery) { - return issueFinder.find(issueQuery); + public List findFavoriteFilters(UserSession userSession) { + if (userSession.isLoggedIn() && userSession.login() != null) { + List issueFilterDtoList = issueFilterDao.selectByUserWithOnlyFavoriteFilters(userSession.login()); + return newArrayList(Iterables.transform(issueFilterDtoList, new Function() { + @Override + public DefaultIssueFilter apply(IssueFilterDto issueFilterDto) { + return issueFilterDto.toIssueFilter(); + } + })); + } + return Collections.emptyList(); } - public IssueQueryResult execute(Long issueFilterId, UserSession userSession) { - IssueFilterDto issueFilterDto = findIssueFilter(issueFilterId); - verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); - - DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter(); - IssueQuery issueQuery = PublicRubyIssueService.toQuery(issueFilter.dataAsMap()); - return issueFinder.find(issueQuery); + public void toggleFavouriteIssueFilter(Long issueFilterId, UserSession userSession) { + findIssueFilter(issueFilterId, userSession); + IssueFilterFavouriteDto issueFilterFavouriteDto = findFavouriteIssueFilter(userSession.login(), issueFilterId); + if (issueFilterFavouriteDto == null) { + addFavouriteIssueFilter(issueFilterId, userSession.login()); + } else { + deleteFavouriteIssueFilter(issueFilterFavouriteDto.getId()); + } } - public IssueFilterDto findIssueFilter(Long id){ + public IssueFilterDto findIssueFilter(Long id, UserSession userSession){ + verifyLoggedIn(userSession); IssueFilterDto issueFilterDto = issueFilterDao.selectById(id); if (issueFilterDto == null) { // TODO throw 404 throw new IllegalArgumentException("Filter not found: " + id); } + verifyCurrentUserIsOwnerOfFilter(issueFilterDto, userSession); return issueFilterDto; } @@ -160,4 +184,19 @@ public class IssueFilterService implements ServerComponent { } } + private IssueFilterFavouriteDto findFavouriteIssueFilter(String user, Long issueFilterId) { + return issueFilterFavouriteDao.selectByUserAndIssueFilterId(user, issueFilterId); + } + + private void addFavouriteIssueFilter(Long issueFilterId, String user) { + IssueFilterFavouriteDto issueFilterFavouriteDto = new IssueFilterFavouriteDto() + .setIssueFilterId(issueFilterId) + .setUserLogin(user); + issueFilterFavouriteDao.insert(issueFilterFavouriteDto); + } + + private void deleteFavouriteIssueFilter(Long issueFilterFavoriteId) { + issueFilterFavouriteDao.delete(issueFilterFavoriteId); + } + } 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 55ed4e34a82..d3d4500aed8 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 @@ -17,11 +17,10 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # - class IssuesController < ApplicationController before_filter :init_options - before_filter :load_user_filters, :only => [:index, :search, :filter, :manage] + before_filter :load_filters, :only => [:index, :search, :filter, :manage, :toggle_fav] # GET /issues/index def index @@ -35,8 +34,7 @@ class IssuesController < ApplicationController else @filter = Internal.issues.createFilterFromMap(criteria_params) end - - @criteria_params = criteria_params + @criteria_params = Hash[@filter.dataAsMap] @issue_query = Internal.issues.toQuery(criteria_params) @issues_result = Internal.issues.execute(@issue_query) end @@ -46,11 +44,8 @@ class IssuesController < ApplicationController def filter require_parameters :id - # criteria can be overridden - # TODO ? - #@filter.override_criteria(criteria_params) - @filter = find_filter(params[:id].to_i) + @criteria_params = Hash[@filter.dataAsMap] @issue_query = Internal.issues.toQuery(@filter.dataAsMap) @issues_result = Internal.issues.execute(@issue_query) @unchanged = true @@ -61,6 +56,8 @@ class IssuesController < ApplicationController # GET /issues/manage def manage @issue_query = Internal.issues.toQuery({}) + @filters = Internal.issues.findIssueFiltersForCurrentUser() + @favourite_filter_ids = @favourite_filters.map { |filter| filter.id } end # GET /issues/save_as_form?[&criteria] @@ -159,6 +156,19 @@ class IssuesController < ApplicationController redirect_to :action => 'manage' end + # POST /issues/toggle_fav/ + def toggle_fav + verify_ajax_request + require_parameters :id + result = Internal.issues.toggleFavouriteIssueFilter(params[:id].to_i) + if result.ok + render :text => '', :status => 200 + else + @errors = result.errors + render :action => 'manage' + end + end + private @@ -167,8 +177,8 @@ class IssuesController < ApplicationController @options_for_resolutions = Internal.issues.listResolutions().map {|s| [message('issue.resolution.' + s), s]} end - def load_user_filters - @my_filters = Internal.issues.findIssueFiltersForUser() + def load_filters + @favourite_filters = Internal.issues.findFavouriteIssueFiltersForCurrentUser() end def find_filter(id) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb index 5e70609414c..62abbc88488 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/issues_helper.rb @@ -32,4 +32,16 @@ module IssuesHelper html end + def issue_filter_star(filter, is_favourite) + if is_favourite + style='fav' + title=message('click_to_remove_from_favourites') + else + style='notfav' + title=message('click_to_add_to_favourites') + end + + "" + end + end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_favourites.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_favourites.html.erb index 0a288c80ae2..397aecff874 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_favourites.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/_favourites.html.erb @@ -1,6 +1,12 @@