diff --git a/src/main/scala/app/IndexController.scala b/src/main/scala/app/IndexController.scala index 7e92f71..427c11f 100644 --- a/src/main/scala/app/IndexController.scala +++ b/src/main/scala/app/IndexController.scala @@ -4,20 +4,18 @@ import util.Directory._ import service._ import jp.sf.amateras.scalatra.forms._ -import org.eclipse.jgit.api.Git import org.apache.commons.io.FileUtils import org.eclipse.jgit.treewalk.TreeWalk import org.eclipse.jgit.revwalk.RevWalk import scala.collection.mutable.ListBuffer import org.eclipse.jgit.lib.FileMode -import java.util.regex.Pattern class IndexController extends IndexControllerBase - with RepositoryService with AccountService with SystemSettingsService with ActivityService + with RepositoryService with AccountService with SystemSettingsService with ActivityService with IssuesService with ReferrerAuthenticator trait IndexControllerBase extends ControllerBase { self: RepositoryService - with SystemSettingsService with ActivityService + with SystemSettingsService with ActivityService with IssuesService with ReferrerAuthenticator => val searchForm = mapping( @@ -44,21 +42,36 @@ // TODO readable only get("/:owner/:repository/search")(referrersOnly { repository => - val owner = params("owner") - val name = params("repository") val query = params("q") val target = params.getOrElse("type", "Code") target.toLowerCase match { case "issue" => { // TODO search issue + val lowerQueries = query.toLowerCase.split("[ \\t ]+") + + search.html.issues(queryIssues(repository.owner, repository.name, query).map { case (issue, commentCount, content) => + val lowerText = content.toLowerCase + val indices = lowerQueries.map { lowerQuery => + lowerText.indexOf(lowerQuery) + } + val highlightText = if(!indices.exists(_ < 0)){ + val lineNumber = content.substring(0, indices.min).split("\n").size - 1 + StringUtil.escapeHtml(content.split("\n").drop(lineNumber).take(5).mkString("\n")) + .replaceAll("(?i)(" + lowerQueries.map("\\Q" + _ + "\\E").mkString("|") + ")", + "$1") + } else content.split("\n").take(5).mkString("\n") + + IssueSearchResult(issue.issueId, issue.title, issue.openedUserName, issue.registeredDate, commentCount, highlightText) + }, query, repository) + } case _ => { - JGitUtil.withGit(getRepositoryDir(owner, name)){ git => - val revWalk = new RevWalk(git.getRepository) - val objectId = git.getRepository.resolve("HEAD") + JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => + val revWalk = new RevWalk(git.getRepository) + val objectId = git.getRepository.resolve("HEAD") val revCommit = revWalk.parseCommit(objectId) - val treeWalk = new TreeWalk(git.getRepository) + val treeWalk = new TreeWalk(git.getRepository) treeWalk.setRecursive(true) treeWalk.addTree(revCommit.getTree) @@ -79,7 +92,7 @@ .replaceAll("(?i)(" + lowerQueries.map("\\Q" + _ + "\\E").mkString("|") + ")", "$1") list.append((treeWalk.getPathString, highlightText)) - } + } } } } @@ -107,4 +120,8 @@ } + +case class IssueSearchResult(issueId: Int, title: String, openedUserName: String, registeredDate: java.util.Date, + commentCount: Int, highlightText: String) + case class FileSearchResult(path: String, lastModified: java.util.Date, highlightText: String) \ No newline at end of file diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala index 17f3c69..037089e 100644 --- a/src/main/scala/service/IssuesService.scala +++ b/src/main/scala/service/IssuesService.scala @@ -8,6 +8,7 @@ import model._ import util.StringUtil._ import util.Implicits._ +import scala.concurrent.duration.durationToPair trait IssuesService { import IssuesService._ @@ -234,6 +235,44 @@ } .update (closed, currentDate) + def queryIssues(owner: String, repository: String, query: String): List[(Issue, Int, String)] = { + val lowerQueries = query.toLowerCase.split("[ \\t ]+") + + val issues = Query(Issues).filter { t => + lowerQueries.map { query => + (t.title.toLowerCase startsWith query) || (t.content.toLowerCase startsWith query) + } .reduceLeft { (a, b) => + a && b + } + }.map { t => (t, 0, t.content) } + + val comments = Query(IssueComments).innerJoin(Issues).on { case (t1, t2) => + t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) + }.filter { case (t1, t2) => + lowerQueries.map { query => + t1.content.toLowerCase startsWith query + }.reduceLeft { (a, b) => + a && b + } + }.map { case (t1, t2) => (t2, t1.commentId, t1.content) } + + def getCommentCount(issue: Issue): Int = { + Query(IssueComments) + .filter(_.byIssue(issue.userName, issue.repositoryName, issue.issueId)) + .map(_.issueId) + .list.length + } + + issues.union(comments).sortBy { case (issue, commentId, _) => + issue.issueId ~ commentId + }.list.splitWith { case ((issue1, _, _), (issue2, _, _)) => + issue1.issueId == issue2.issueId + }.map { result => + val (issue, _, content) = result.head + (issue, getCommentCount(issue) , content) + }.toList + } + } object IssuesService { @@ -279,4 +318,5 @@ param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"), param(request, "direction", Seq("asc", "desc")).getOrElse("desc")) } + } diff --git a/src/main/twirl/search/code.scala.html b/src/main/twirl/search/code.scala.html index 55a7f14..d3c570c 100644 --- a/src/main/twirl/search/code.scala.html +++ b/src/main/twirl/search/code.scala.html @@ -10,7 +10,7 @@ } @files.map { file =>
-
@file.path
+
@file.path
@datetime(file.lastModified)
@Html(file.highlightText)
diff --git a/src/main/twirl/search/issues.scala.html b/src/main/twirl/search/issues.scala.html new file mode 100644 index 0000000..4e47419 --- /dev/null +++ b/src/main/twirl/search/issues.scala.html @@ -0,0 +1,26 @@ +@(issues: List[app.IssueSearchResult], query: String, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) +@import context._ +@import view.helpers._ +@html.main("Search Results", Some(repository)){ + @menu("issue", query, repository){ + @if(issues.isEmpty){ +

We couldn't find any code matching '@query'

+ } else { +

We've found @issues.size code @plural(issues.size, "result")

+ } + @issues.map { issue => +
+
#@issue.issueId
+

@issue.title

+
@Html(issue.highlightText)
+
+ Opened by @issue.openedUserName + at @datetime(issue.registeredDate) + @if(issue.commentCount > 0){ +   @issue.commentCount @plural(issue.commentCount, "comment") + } +
+
+ } + } +} \ No newline at end of file