diff options
author | Julien Lancelot <julien.lancelot@gmail.com> | 2013-06-18 16:22:09 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@gmail.com> | 2013-06-18 16:22:21 +0200 |
commit | fa2fcc0312a3c22a03e1c28bdd42ab4e45249c45 (patch) | |
tree | 6f84fca2da2a698cab5aee4f0a4b61e33ab98175 | |
parent | 85143f236cb74df69d55214b3d62a8c7f2398c7f (diff) | |
download | sonarqube-fa2fcc0312a3c22a03e1c28bdd42ab4e45249c45.tar.gz sonarqube-fa2fcc0312a3c22a03e1c28bdd42ab4e45249c45.zip |
SONAR-4393 Manage favourite issue filters
24 files changed, 704 insertions, 56 deletions
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<IssueFilterDto> selectByUser(String user) { SqlSession session = mybatis.openSession(); try { - session.getMapper(IssueFilterMapper.class); return getMapper(session).selectByUser(user); } finally { MyBatis.closeQuietly(session); } } + public List<IssueFilterDto> 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<IssueFilterDto> selectByUser(String user); + List<IssueFilterDto> 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 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="org.sonar.core.issue.db.IssueFilterFavouriteMapper"> + + <sql id="issueFilterFavouriteColumns"> + filter_favourites.id as id, + filter_favourites.user_login as userLogin, + filter_favourites.issue_filter_id as issueFilterId, + filter_favourites.created_at as createdAt + </sql> + + <select id="selectById" parameterType="long" resultType="issueFilterFavourite"> + select <include refid="issueFilterFavouriteColumns"/> + from issue_filter_favourites filter_favourites + <where> + filter_favourites.id=#{id} + </where> + </select> + + <select id="selectByIssueFilterId" parameterType="long" resultType="issueFilterFavourite"> + select <include refid="issueFilterFavouriteColumns"/> + from issue_filter_favourites filter_favourites + <where> + filter_favourites.issue_filter_id=#{issueFilterId} + and filter_favourites.user_login=#{userLogin} + </where> + </select> + + <insert id="insert" parameterType="issueFilterFavourite" useGeneratedKeys="true" keyProperty="id"> + INSERT INTO issue_filter_favourites (user_login, issue_filter_id, created_at) + VALUES (#{userLogin}, #{issueFilterId}, current_timestamp) + </insert> + + <!-- Oracle --> + <insert id="insert" databaseId="oracle" parameterType="issueFilterFavourite" keyColumn="id" useGeneratedKeys="true" keyProperty="id"> + <selectKey order="BEFORE" resultType="Long" keyProperty="id"> + select issue_filter_favourites_seq.NEXTVAL from DUAL + </selectKey> + INSERT INTO issue_filter_favourites (id, user_login, issue_filter_id, created_at) + VALUES (#{id},#{userLogin}, #{issueFilterId}, current_timestamp) + </insert> + + <delete id="delete" parameterType="int"> + delete from issue_filter_favourites where id=#{id} + </delete> + +</mapper> 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 @@ </where> </select> + <select id="selectByUserWithOnlyFavoriteFilters" parameterType="String" resultType="IssueFilter"> + select <include refid="issueFilterColumns"/> + from issue_filters filters + inner join issue_filter_favourites fav on fav.issue_filter_id = filters.id + <where> + fav.user_login=#{user} + </where> + </select> + <insert id="insert" parameterType="IssueFilter" useGeneratedKeys="true" keyProperty="id"> 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 @@ -71,6 +71,17 @@ public class IssueFilterDaoTest extends AbstractDaoTestCase { } @Test + public void should_select_by_user_with_only_favorite_filters() { + setupData("should_select_by_user_with_only_favorite_filters"); + + List<IssueFilterDto> 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 @@ +<dataset> + + <issue_filters + id="1" + name="Sonar Issues" + user_login="stephane" + shared="[true]" + description="All issues of Sonar" + data="componentRoots=org.codehaus.sonar" + created_at="2013-06-10" + updated_at="2013-06-10" /> + + <issue_filters + id="2" + name="Open issues" + user_login="michael" + shared="[false]" + description="All open issues" + data="statuses=OPEN" + created_at="2013-06-10" + updated_at="2013-06-10" /> + + <issue_filters + id="3" + name="Sonar Open issues" + user_login="michael" + shared="[true]" + description="All open issues on Sonar" + data="statuses=OPEN|componentRoots=org.codehaus.sonar" + created_at="2013-06-10" + updated_at="2013-06-10" /> + + <issue_filter_favourites + id="10" + user_login="michael" + issue_filter_id="2" + created_at="2013-06-10"/> + +</dataset> 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 @@ +<dataset> + + <issue_filter_favourites + id="1" + user_login="stephane" + issue_filter_id="10" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="2" + user_login="stephane" + issue_filter_id="11" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="3" + user_login="arthur" + issue_filter_id="10" + created_at="2013-06-10"/> + +</dataset> 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 @@ +<dataset> + + <issue_filter_favourites + id="1" + user_login="stephane" + issue_filter_id="10" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="2" + user_login="stephane" + issue_filter_id="11" + created_at="2013-06-10"/> + +</dataset> 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 @@ +<dataset> + + <issue_filter_favourites + id="1" + user_login="stephane" + issue_filter_id="10" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="2" + user_login="stephane" + issue_filter_id="11" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="3" + user_login="arthur" + issue_filter_id="10" + created_at="2013-06-10"/> + + <issue_filter_favourites + id="4" + user_login="arthur" + issue_filter_id="11" + created_at="2013-06-18"/> + +</dataset> 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<DefaultIssueFilter> findIssueFiltersForUser() { + public List<DefaultIssueFilter> findIssueFiltersForCurrentUser() { return issueFilterService.findByUser(UserSession.get()); } @@ -450,10 +450,10 @@ public class InternalRubyIssueService implements ServerComponent { public Result<DefaultIssueFilter> deleteIssueFilter(Long issueFilterId) { Result<DefaultIssueFilter> 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<DefaultIssueFilter> 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<DefaultIssueFilter> findByUser(UserSession userSession) { - if (userSession.isLoggedIn()) { + if (userSession.isLoggedIn() && userSession.login() != null) { List<IssueFilterDto> issueFilterDtoList = issueFilterDao.selectByUser(userSession.login()); return newArrayList(Iterables.transform(issueFilterDtoList, new Function<IssueFilterDto, DefaultIssueFilter>() { @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<String, Object> 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<DefaultIssueFilter> findFavoriteFilters(UserSession userSession) { + if (userSession.isLoggedIn() && userSession.login() != null) { + List<IssueFilterDto> issueFilterDtoList = issueFilterDao.selectByUserWithOnlyFavoriteFilters(userSession.login()); + return newArrayList(Iterables.transform(issueFilterDtoList, new Function<IssueFilterDto, DefaultIssueFilter>() { + @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/<filter id> + 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 + + "<a href='#' class='issue-filter-star #{style}' filter-id='#{filter.id.to_s}' title='#{title}'></a>" + 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 @@ <div id="sidebar-favourites"> <% if logged_in? %> <li class="sidebar-title"><%= message('issue_filter.favourite_filters') -%></li> + <% @favourite_filters.each do |filter| %> + <li <%= "class='active'" if @filter && filter.id==@filter.id -%>> + <a href="<%= ApplicationController.root_context -%>/issues/filter/<%= filter.id -%>"><%= h filter.name -%></a> + </li> + <% end %> + <li><a href="<%= ApplicationController.root_context -%>/issues/manage" class="link-action"><%= message('manage') %></a></li> <li class="spacer"></li> <% end %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/manage.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/manage.html.erb index 0f95f2ae53a..9c2baa799bc 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues/manage.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues/manage.html.erb @@ -1,26 +1,48 @@ +<% content_for :script do %> + <script> + $j(document).ready(function () { + $j(".issue-filter-star").click(function () { + var filterId = $j(this).attr('filter-id'); + $j.ajax({ + type: 'POST', + url: baseUrl + "/issues/toggle_fav", + data: {id: filterId}, + success: function (data) { + window.location = baseUrl + '/issues/manage'; + } + }); + }); + }); + </script> +<% end %> <div> <div class="page-split-left"> <%= render :partial => 'issues/sidebar' -%> </div> <div class="page-split-right"> <div id="content"> + <%= render :partial => 'display_errors' %> <h1><%= message 'issue_filter.manage.my_filters' -%></h1> <table class="data marginbottom10" id="my-issue-filters"> <thead> <tr> + <th class="thin"></th> <th><%= message('name') -%></th> <th class="right"><%= message('operations') -%></th> </tr> </thead> <tbody> - <% if @my_filters.empty? %> + <% if @filters.empty? %> <tr class="even"> <td colspan="4"><%= message('issue_filter.no_filters') -%></td> </tr> <% else %> - <% @my_filters.each do |filter| %> + <% @filters.each do |filter| %> <tr id="my-issue-filter-<%= filter.name.parameterize -%>" class="<%= cycle('even', 'odd', :name => 'my-filters') -%>"> <td> + <%= issue_filter_star(filter, @favourite_filter_ids.include?(filter.id)) -%> + </td> + <td> <%= link_to h(filter.name), :action => 'filter', :id => filter.id -%> <% if filter.description %> <div class="note"><%= h filter.description -%></div> diff --git a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java index a8113367b0c..8f82db7347a 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java @@ -403,7 +403,7 @@ public class InternalRubyIssueServiceTest { @Test public void should_find_user_issue_filters() { - service.findIssueFiltersForUser(); + service.findIssueFiltersForCurrentUser(); verify(issueFilterService).findByUser(any(UserSession.class)); } @@ -414,6 +414,18 @@ public class InternalRubyIssueServiceTest { verify(issueFilterService).updateData(eq(10L), eq(data), any(UserSession.class)); } + @Test + public void should_find_favourite_issue_filters() { + service.findFavouriteIssueFiltersForCurrentUser(); + verify(issueFilterService).findFavoriteFilters(any(UserSession.class)); + } + + @Test + public void should_toggle_favourite_issue_filter() { + service.toggleFavouriteIssueFilter(10L); + verify(issueFilterService).toggleFavouriteIssueFilter(eq(10L), any(UserSession.class)); + } + private String createLongString(int size) { String result = ""; for (int i = 0; i < size; i++) { diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java index 429322c1fa8..a1e1aa0e179 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueFilterServiceTest.java @@ -28,6 +28,8 @@ import org.sonar.api.issue.IssueQuery; 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 java.util.List; @@ -45,6 +47,7 @@ public class IssueFilterServiceTest { private IssueFilterService service; private IssueFilterDao issueFilterDao; + private IssueFilterFavouriteDao issueFilterFavouriteDao; private IssueFinder issueFinder; private UserSession userSession; @@ -57,9 +60,10 @@ public class IssueFilterServiceTest { when(userSession.login()).thenReturn("john"); issueFilterDao = mock(IssueFilterDao.class); + issueFilterFavouriteDao = mock(IssueFilterFavouriteDao.class); issueFinder = mock(IssueFinder.class); - service = new IssueFilterService(issueFilterDao, issueFinder); + service = new IssueFilterService(issueFilterDao, issueFilterFavouriteDao, issueFinder); } @Test @@ -136,6 +140,15 @@ public class IssueFilterServiceTest { } @Test + public void should_add_favorite_on_save() { + DefaultIssueFilter issueFilter = new DefaultIssueFilter().setName("My Issue"); + service.save(issueFilter, userSession); + + verify(issueFilterDao).insert(any(IssueFilterDto.class)); + verify(issueFilterFavouriteDao).insert(any(IssueFilterFavouriteDto.class)); + } + + @Test public void should_not_save_if_not_logged() { when(userSession.isLoggedIn()).thenReturn(false); try { @@ -221,6 +234,17 @@ public class IssueFilterServiceTest { } @Test + public void should_delete_favorite_filter_on_delete() { + when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john")); + when(issueFilterFavouriteDao.selectByUserAndIssueFilterId("john", 1L)).thenReturn(new IssueFilterFavouriteDto().setId(10L).setUserLogin("john").setIssueFilterId(1L)); + + service.delete(1L, userSession); + + verify(issueFilterDao).delete(1L); + verify(issueFilterFavouriteDao).delete(10L); + } + + @Test public void should_not_delete_if_filter_not_found() { when(issueFilterDao.selectById(1L)).thenReturn(null); @@ -235,7 +259,7 @@ public class IssueFilterServiceTest { @Test public void should_copy() { - when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("perceval").setData("componentRoots=struts")); + when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john").setData("componentRoots=struts")); DefaultIssueFilter issueFilter = new DefaultIssueFilter().setName("Copy Of My Issue"); DefaultIssueFilter result = service.copy(1L, issueFilter, userSession); @@ -268,4 +292,57 @@ public class IssueFilterServiceTest { assertThat(issueQuery.componentRoots()).contains("struts"); } + @Test + public void should_find_favourite_issue_filter() { + when(issueFilterDao.selectByUserWithOnlyFavoriteFilters("john")).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john"))); + + List<DefaultIssueFilter> results = service.findFavoriteFilters(userSession); + assertThat(results).hasSize(1); + } + + @Test + public void should_not_find_favourite_issue_filter_if_not_logged() { + when(userSession.isLoggedIn()).thenReturn(false); + + List<DefaultIssueFilter> results = service.findFavoriteFilters(userSession); + assertThat(results).isEmpty(); + } + + @Test + public void should_add_favourite_issue_filter_id() { + when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john").setData("componentRoots=struts")); + // The filter is not in the favorite list --> add to favorite + when(issueFilterFavouriteDao.selectByUserAndIssueFilterId("john", 1L)).thenReturn(null); + + ArgumentCaptor<IssueFilterFavouriteDto> issueFilterFavouriteDtoCaptor = ArgumentCaptor.forClass(IssueFilterFavouriteDto.class); + service.toggleFavouriteIssueFilter(1L, userSession); + verify(issueFilterFavouriteDao).insert(issueFilterFavouriteDtoCaptor.capture()); + + IssueFilterFavouriteDto issueFilterFavouriteDto = issueFilterFavouriteDtoCaptor.getValue(); + assertThat(issueFilterFavouriteDto.getIssueFilterId()).isEqualTo(1L); + assertThat(issueFilterFavouriteDto.getUserLogin()).isEqualTo("john"); + } + + @Test + public void should_delete_favourite_issue_filter_id() { + when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john").setData("componentRoots=struts")); + // The filter is in the favorite list --> remove favorite + when(issueFilterFavouriteDao.selectByUserAndIssueFilterId("john", 1L)).thenReturn(new IssueFilterFavouriteDto().setId(10L).setUserLogin("john").setIssueFilterId(1L)); + + service.toggleFavouriteIssueFilter(1L, userSession); + verify(issueFilterFavouriteDao).delete(10L); + } + + @Test + public void should_not_toggle_favourite_filter_if_filter_not_found() { + when(issueFilterDao.selectById(1L)).thenReturn(null); + try { + service.toggleFavouriteIssueFilter(1L, userSession); + fail(); + } catch (Exception e) { + assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Filter not found: 1"); + } + verify(issueFilterFavouriteDao, never()).delete(anyLong()); + } + } |