--- /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;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Date;
+
+public class DefaultIssueFilter {
+
+ public static String SEPARATOR = "|";
+ public static String KEY_VALUE_SEPARATOR = "=";
+ public static String LIST_SEPARATOR = ",";
+
+ private Long id;
+ private String name;
+ private String user;
+ private Boolean shared;
+ private String description;
+ private String data;
+ private Date createdAt;
+ private Date updatedAt;
+
+ public DefaultIssueFilter() {
+
+ }
+
+ public Long id() {
+ return id;
+ }
+
+ public DefaultIssueFilter setId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public DefaultIssueFilter setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @CheckForNull
+ public String user() {
+ return user;
+ }
+
+ public DefaultIssueFilter setUser(String user) {
+ this.user = user;
+ return this;
+ }
+
+ public Boolean shared() {
+ return shared;
+ }
+
+ public DefaultIssueFilter setShared(Boolean shared) {
+ this.shared = shared;
+ return this;
+ }
+
+ public String description() {
+ return description;
+ }
+
+ public DefaultIssueFilter setDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public String data() {
+ return data;
+ }
+
+ public DefaultIssueFilter setData(String data) {
+ this.data = data;
+ return this;
+ }
+
+ public Date createdAt() {
+ return createdAt;
+ }
+
+ public DefaultIssueFilter setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public Date updatedAt() {
+ return updatedAt;
+ }
+
+ public DefaultIssueFilter setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+}
}
@CheckForNull
- public IssueFilterDto selectById(Integer id) {
+ public IssueFilterDto selectById(Long id) {
SqlSession session = mybatis.openSession();
try {
session.getMapper(IssueFilterMapper.class);
}
}
- public List<IssueFilterDto> selectByUser(Integer userId) {
+ public List<IssueFilterDto> selectByUser(String user) {
SqlSession session = mybatis.openSession();
try {
session.getMapper(IssueFilterMapper.class);
- return getMapper(session).selectByUser(userId);
+ return getMapper(session).selectByUser(user);
} finally {
MyBatis.closeQuietly(session);
}
}
}
- public void delete(Integer id) {
+ public void delete(Long id) {
SqlSession session = mybatis.openSession();
try {
getMapper(session).delete(id);
*/
package org.sonar.core.issue.db;
+import org.sonar.core.issue.DefaultIssueFilter;
+
import javax.annotation.Nullable;
import java.util.Date;
private Long id;
private String name;
- private Long userId;
+ private String user;
private Boolean shared;
private String description;
private String data;
return this;
}
- public Long getUserId() {
- return userId;
+ public String getUser() {
+ return user;
}
- public IssueFilterDto setUserId(@Nullable Long userId) {
- this.userId = userId;
+ public IssueFilterDto setUser(@Nullable String user) {
+ this.user = user;
return this;
}
this.updatedAt = updatedAt;
return this;
}
+
+ public DefaultIssueFilter toIssueFilter() {
+ return new DefaultIssueFilter()
+ .setId(id)
+ .setName(name)
+ .setUser(user)
+ .setDescription(description)
+ .setShared(shared)
+ .setData(data)
+ .setCreatedAt(createdAt)
+ .setUpdatedAt(updatedAt);
+ }
+
+ public static IssueFilterDto toIssueFilter(DefaultIssueFilter issueFilter) {
+ return new IssueFilterDto()
+ .setId(issueFilter.id())
+ .setName(issueFilter.name())
+ .setUser(issueFilter.user())
+ .setDescription(issueFilter.description())
+ .setShared(issueFilter.shared())
+ .setData(issueFilter.data())
+ .setCreatedAt(issueFilter.createdAt())
+ .setUpdatedAt(issueFilter.updatedAt());
+ }
}
public interface IssueFilterMapper {
@CheckForNull
- IssueFilterDto selectById(Integer id);
+ IssueFilterDto selectById(Long id);
- List<IssueFilterDto> selectByUser(Integer userId);
+ List<IssueFilterDto> selectByUser(String user);
void insert(IssueFilterDto filter);
void update(IssueFilterDto filter);
- void delete(Integer id);
+ void delete(Long id);
}
<sql id="issueFilterColumns">
if.id,
if.name as name,
- if.user_id as userId,
+ if.user as user,
if.shared as shared,
if.description as description,
if.data as data,
from issue_filters if WHERE id=#{id}
</select>
- <select id="selectByUser" parameterType="int" resultType="IssueFilter">
+ <select id="selectByUser" parameterType="String" resultType="IssueFilter">
select <include refid="issueFilterColumns"/>
- from issue_filters if WHERE user_id=#{userId}
+ from issue_filters if WHERE user=#{user}
</select>
<insert id="insert" parameterType="IssueFilter" useGeneratedKeys="true" keyProperty="id">
- INSERT INTO issue_filters (name, user_id, shared, description, data, created_at, updated_at)
- VALUES (#{name}, #{userId}, #{shared}, #{description}, #{data}, #{createdAt}, #{updatedAt})
+ INSERT INTO issue_filters (name, user, shared, description, data, created_at, updated_at)
+ VALUES (#{name}, #{user}, #{shared}, #{description}, #{data}, #{createdAt}, #{updatedAt})
</insert>
<!-- Oracle -->
<selectKey order="BEFORE" resultType="Long" keyProperty="id">
select issue_filters_seq.NEXTVAL from DUAL
</selectKey>
- INSERT INTO issue_filters (id, name, user_id, shared, description, data, created_at, updated_at)
- VALUES (#{id}, #{name}, #{userId}, #{shared}, #{description}, #{data}, #{createdAt}, #{updatedAt})
+ INSERT INTO issue_filters (id, name, user, shared, description, data, created_at, updated_at)
+ VALUES (#{id}, #{name}, #{user}, #{shared}, #{description}, #{data}, #{createdAt}, #{updatedAt})
</insert>
<update id="update" parameterType="IssueFilter">
update issue_filters set
name=#{name},
- user_id=#{userId},
+ user=#{user},
shared=#{shared},
description=#{description},
data=#{data},
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"NAME" VARCHAR(100) NOT NULL,
"SHARED" BOOLEAN NOT NULL DEFAULT FALSE,
- "USER_ID" INTEGER,
+ "USER" VARCHAR(40),
"DESCRIPTION" VARCHAR(4000),
"DATA" CLOB(2147483647),
"CREATED_AT" TIMESTAMP,
CREATE TABLE "ISSUE_FILTER_FAVOURITES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
- "USER_ID" INTEGER NOT NULL,
+ "USER" VARCHAR(40) NOT NULL,
"ISSUE_FILTER_ID" INTEGER NOT NULL,
"CREATED_AT" TIMESTAMP
);
CREATE INDEX "ISSUE_FILTERS_NAME" ON "ISSUE_FILTERS" ("NAME");
-CREATE INDEX "ISSUE_FILTER_FAVS_USERID" ON "ISSUE_FILTER_FAVOURITES" ("USER_ID");
+CREATE INDEX "ISSUE_FILTER_FAVS_USER" ON "ISSUE_FILTER_FAVOURITES" ("USER");
CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
public void should_select_by_id() {
setupData("shared");
- IssueFilterDto filter = dao.selectById(1);
+ IssueFilterDto filter = dao.selectById(1L);
assertThat(filter.getId()).isEqualTo(1L);
assertThat(filter.getName()).isEqualTo("Sonar Issues");
assertThat(filter.isShared()).isTrue();
- assertThat(dao.selectById(123)).isNull();
+ assertThat(dao.selectById(123L)).isNull();
}
@Test
public void should_select_by_user() {
setupData("should_select_by_user");
- List<IssueFilterDto> results = dao.selectByUser(2);
+ List<IssueFilterDto> results = dao.selectByUser("michael");
assertThat(results).hasSize(2);
}
IssueFilterDto filterDto = new IssueFilterDto();
filterDto.setName("Sonar Open issues");
- filterDto.setUserId(2L);
+ filterDto.setUser("michael");
filterDto.setShared(true);
filterDto.setDescription("All open issues on Sonar");
filterDto.setData("statuses=OPEN|componentRoots=org.codehaus.sonar");
IssueFilterDto filterDto = new IssueFilterDto();
filterDto.setId(2L);
filterDto.setName("Closed issues");
- filterDto.setUserId(3L);
+ filterDto.setUser("henry");
filterDto.setShared(false);
filterDto.setDescription("All closed issues");
filterDto.setData("statuses=CLOSED");
public void should_delete() {
setupData("shared");
- dao.delete(1);
+ dao.delete(1l);
checkTables("should_delete", new String[]{"created_at", "updated_at"}, "issue_filters");
}
<issue_filters
id="1"
name="Sonar Issues"
- user_id="1"
+ user="stephane"
shared="[true]"
description="All issues of Sonar"
data="componentRoots=org.codehaus.sonar"
<issue_filters
id="2"
name="Open issues"
- user_id="2"
+ user="michael"
shared="[false]"
description="All open issues"
data="statuses=OPEN"
<issue_filters
id="2"
name="Open issues"
- user_id="2"
+ user="michael"
shared="[false]"
description="All open issues"
data="statuses=OPEN"
<issue_filters
id="1"
name="Sonar Issues"
- user_id="1"
+ user="stephane"
shared="[true]"
description="All issues of Sonar"
data="componentRoots=org.codehaus.sonar"
<issue_filters
id="2"
name="Open issues"
- user_id="2"
+ user="michael"
shared="[false]"
description="All open issues"
data="statuses=OPEN"
<issue_filters
id="3"
name="Sonar Open issues"
- user_id="2"
+ user="michael"
shared="[true]"
description="All open issues on Sonar"
data="statuses=OPEN|componentRoots=org.codehaus.sonar"
<issue_filters
id="1"
name="Sonar Issues"
- user_id="1"
+ user="stephane"
shared="[true]"
description="All issues of Sonar"
data="componentRoots=org.codehaus.sonar"
<issue_filters
id="2"
name="Open issues"
- user_id="2"
+ user="michael"
shared="[false]"
description="All open issues"
data="statuses=OPEN"
<issue_filters
id="3"
name="Sonar Open issues"
- user_id="2"
+ user="michael"
shared="[true]"
description="All open issues on Sonar"
data="statuses=OPEN|componentRoots=org.codehaus.sonar"
<issue_filters
id="1"
name="Sonar Issues"
- user_id="1"
+ user="stephane"
shared="[true]"
description="All issues of Sonar"
data="componentRoots=org.codehaus.sonar"
<issue_filters
id="2"
name="Closed issues"
- user_id="3"
+ user="henry"
shared="[false]"
description="All closed issues"
data="statuses=CLOSED"
import org.sonar.api.issue.ActionPlan;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueComment;
+import org.sonar.api.issue.IssueQuery;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
return actionService.listAvailableActions(issue);
}
+ public IssueQuery toQuery(Map<String, Object> props) {
+ return PublicRubyIssueService.toQuery(props);
+ }
+
}
\ No newline at end of file
package org.sonar.server.issue;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.api.issue.IssueQuery;
+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.server.user.UserSession;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
public class IssueFilterService implements ServerComponent {
private IssueFilterDao issueFilterDao;
+ private final IssueFinder issueFinder;
- public IssueFilterService(IssueFilterDao issueFilterDao) {
+ public IssueFilterService(IssueFilterDao issueFilterDao, IssueFinder issueFinder) {
this.issueFilterDao = issueFilterDao;
+ this.issueFinder = issueFinder;
+ }
+
+ public DefaultIssueFilter create(DefaultIssueFilter issueFilter, IssueQuery issueQuery, UserSession userSession) {
+ // TODO
+// checkAuthorization(userSession, project, UserRole.ADMIN);
+ issueFilterDao.insert(IssueFilterDto.toIssueFilter(issueFilter));
+ return issueFilter;
+ }
+
+ public DefaultIssueFilter update(DefaultIssueFilter issueFilter, UserSession userSession) {
+ // TODO
+// checkAuthorization(userSession, project, UserRole.ADMIN);
+ issueFilterDao.update(IssueFilterDto.toIssueFilter(issueFilter));
+ return issueFilter;
+ }
+
+ public void delete(Long issueFilterId, UserSession userSession) {
+ // TODO
+ //checkAuthorization(userSession, findActionPlanDto(actionPlanKey).getProjectKey(), UserRole.ADMIN);
+ issueFilterDao.delete(issueFilterId);
+ }
+
+ public IssueQueryResult execute(IssueQuery issueQuery) {
+ return issueFinder.find(issueQuery);
+ }
+
+ public IssueQueryResult execute(Long issueFilterId) {
+ IssueFilterDto issueFilterDto = issueFilterDao.selectById(issueFilterId);
+ if (issueFilterDto == null) {
+ // TODO throw 404
+ throw new IllegalArgumentException("Issue filter " + issueFilterId + " has not been found.");
+ }
+
+ DefaultIssueFilter issueFilter = issueFilterDto.toIssueFilter();
+ // convert data to issue query
+ issueFilter.data();
+
+// return issueFinder.find(issueQuery);
+ return null;
+ }
+
+ @VisibleForTesting
+ Map<String, Object> dataAsMap(String data) {
+ Map<String, Object> props = newHashMap();
+
+ Iterable<String> keyValues = Splitter.on(DefaultIssueFilter.SEPARATOR).split(data);
+ for (String keyValue : keyValues) {
+ String[] keyValueSplit = StringUtils.split(keyValue, DefaultIssueFilter.KEY_VALUE_SEPARATOR);
+ if (keyValueSplit.length != 2) {
+ throw new IllegalArgumentException("Key value should be separate by a '"+ DefaultIssueFilter.KEY_VALUE_SEPARATOR + "'");
+ }
+ String key = keyValueSplit[0];
+ String value = keyValueSplit[1];
+ String[] listValues = StringUtils.split(value, DefaultIssueFilter.LIST_SEPARATOR);
+ if (listValues.length > 1) {
+ props.put(key, newArrayList(listValues));
+ } else {
+ props.put(key, value);
+ }
+ }
+ return props;
+ }
+
+ @VisibleForTesting
+ String mapAsdata(Map<String, Object> props) {
+ StringBuilder stringBuilder = new StringBuilder();
+
+ for (Map.Entry<String, Object> entries : props.entrySet()){
+ String key = entries.getKey();
+ Object value = entries.getValue();
+
+ stringBuilder.append(key);
+ stringBuilder.append(DefaultIssueFilter.KEY_VALUE_SEPARATOR);
+
+ List valuesList = newArrayList();
+ if (value instanceof List) {
+ // assume that it contains only strings
+ valuesList = (List) value;
+ } else if (value instanceof CharSequence) {
+ valuesList = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().split((CharSequence) value));
+ } else {
+ stringBuilder.append(value);
+ }
+ for (Object valueList : valuesList) {
+ stringBuilder.append(valueList);
+ stringBuilder.append(DefaultIssueFilter.LIST_SEPARATOR);
+ }
+
+ stringBuilder.append(DefaultIssueFilter.SEPARATOR);
+ }
+ return stringBuilder.toString();
}
+
}
def self.up
create_table 'issue_filters' do |t|
- t.column 'name', :string, :null => false, :limit => 100
- t.column 'user_id', :integer, :null => true
- t.column 'shared', :boolean, :default => false, :null => false
- t.column 'description', :string, :null => true, :limit => 4000
- t.column 'data', :text, :null => true
+ t.column 'name', :string, :null => false, :limit => 100
+ t.column 'user', :string, :null => true, :limit => 40
+ t.column 'shared', :boolean, :null => false, :default => false
+ t.column 'description', :string, :null => true, :limit => 4000
+ t.column 'data', :text, :null => true
t.timestamps
end
add_index 'issue_filters', 'name', :name => 'issue_filters_name'
def self.up
create_table 'issue_filter_favourites' do |t|
- t.column 'user_id', :integer, :null => false
- t.column 'issue_filter_id', :integer, :null => false
- t.column 'created_at', :datetime
+ t.column 'user', :string, :null => false, :limit => 40
+ t.column 'issue_filter_id', :integer, :null => false
+ t.column 'created_at', :datetime
end
- add_index 'issue_filter_favourites', 'user_id', :name => 'issue_filter_favs_userid'
+ add_index 'issue_filter_favourites', 'user', :name => 'issue_filter_favs_user'
end
end
--- /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.server.issue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.core.issue.db.IssueFilterDao;
+
+import static org.mockito.Mockito.mock;
+
+public class IssueFilterServiceTest {
+
+ IssueFilterService service;
+
+ IssueFilterDao issueFilterDao;
+ IssueFinder issueFinder;
+
+ @Before
+ public void before() {
+ issueFinder = mock(IssueFinder.class);
+ issueFilterDao = mock(IssueFilterDao.class);
+ service = new IssueFilterService(issueFilterDao, issueFinder);
+ }
+
+ @Test
+ public void should_convert_map_to_data() {
+
+ }
+}