(refs #3)Issue search is temporary available.

This commit is contained in:
takezoe
2013-07-17 16:47:43 +09:00
parent d06a986293
commit 512e59193d
4 changed files with 95 additions and 12 deletions

View File

@@ -4,20 +4,18 @@ import util._
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 @@ trait IndexControllerBase extends ControllerBase { self: RepositoryService
// 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("|") + ")",
"<span style=\"background-color: yellow;\">$1</span>")
} 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 @@ trait IndexControllerBase extends ControllerBase { self: RepositoryService
.replaceAll("(?i)(" + lowerQueries.map("\\Q" + _ + "\\E").mkString("|") + ")",
"<span style=\"background-color: yellow;\">$1</span>")
list.append((treeWalk.getPathString, highlightText))
}
}
}
}
}
@@ -107,4 +120,8 @@ trait IndexControllerBase extends ControllerBase { self: RepositoryService
}
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)

View File

@@ -8,6 +8,7 @@ import Q.interpolation
import model._
import util.StringUtil._
import util.Implicits._
import scala.concurrent.duration.durationToPair
trait IssuesService {
import IssuesService._
@@ -234,6 +235,44 @@ trait IssuesService {
}
.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 @@ object IssuesService {
param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"),
param(request, "direction", Seq("asc", "desc")).getOrElse("desc"))
}
}

View File

@@ -10,7 +10,7 @@
}
@files.map { file =>
<div>
<div><a href="@url(repository)/blob/@repository.repository.defaultBranch/@file.path">@file.path</a></div>
<h5><a href="@url(repository)/blob/@repository.repository.defaultBranch/@file.path">@file.path</a></h5>
<div class="muted">@datetime(file.lastModified)</div>
<pre>@Html(file.highlightText)</pre>
</div>

View File

@@ -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){
<h4>We couldn't find any code matching '@query'</h4>
} else {
<h4>We've found @issues.size code @plural(issues.size, "result")</h4>
}
@issues.map { issue =>
<div class="block">
<div class="pull-right muted">#@issue.issueId</div>
<h4><a href="@url(repository)/issues/@issue.issueId">@issue.title</a></h4>
<pre>@Html(issue.highlightText)</pre>
<div class="small muted">
Opened by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a>
at @datetime(issue.registeredDate)
@if(issue.commentCount > 0){
&nbsp;&nbsp;<i class="icon-comment"></i><strong>@issue.commentCount</strong> @plural(issue.commentCount, "comment")
}
</div>
</div>
}
}
}