import java.util.List;
/**
- * @since 3.6
+ * @since 3.7
*/
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);
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 {
import java.util.Date;
/**
- * @since 3.6
+ * @since 3.7
*/
public class IssueFilterDto {
return userLogin;
}
- public IssueFilterDto setUserLogin(@Nullable String userLogin) {
+ public IssueFilterDto setUserLogin(String userLogin) {
this.userLogin = userLogin;
return this;
}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+}
import java.util.List;
/**
- * @since 3.6
+ * @since 3.7
*/
public interface IssueFilterMapper {
List<IssueFilterDto> selectByUser(String user);
+ List<IssueFilterDto> selectByUserWithOnlyFavoriteFilters(String user);
+
void insert(IssueFilterDto filter);
void update(IssueFilterDto filter);
IssueStatsDao.class,
IssueChangeDao.class,
IssueFilterDao.class,
+ IssueFilterFavouriteDao.class,
LoadedTemplateDao.class,
MeasureFilterDao.class,
PropertiesDao.class,
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);
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,
--- /dev/null
+<?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>
</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})
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<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");
dao.insert(filterDto);
- assertThat(filterDto.getId()).isNotNull();
-
checkTables("should_insert", new String[]{"created_at", "updated_at"}, "issue_filters");
}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<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>
/**
* List user issue filter
*/
- public List<DefaultIssueFilter> findIssueFiltersForUser() {
+ public List<DefaultIssueFilter> findIssueFiltersForCurrentUser() {
return issueFilterService.findByUser(UserSession.get());
}
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;
}
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));
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;
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
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));
}
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));
}
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);
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;
}
}
}
+ 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);
+ }
+
}
# 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
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
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
# 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]
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
@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)
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
<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 %>
+<% 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 %>
@Test
public void should_find_user_issue_filters() {
- service.findIssueFiltersForUser();
+ service.findIssueFiltersForCurrentUser();
verify(issueFilterService).findByUser(any(UserSession.class));
}
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++) {
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;
private IssueFilterService service;
private IssueFilterDao issueFilterDao;
+ private IssueFilterFavouriteDao issueFilterFavouriteDao;
private IssueFinder issueFinder;
private UserSession userSession;
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
verify(issueFilterDao).insert(any(IssueFilterDto.class));
}
+ @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);
verify(issueFilterDao).delete(1L);
}
+ @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);
@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);
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());
+ }
+
}