package app
import util._
import util.Directory._
import service._
import jp.sf.amateras.scalatra.forms._
import org.eclipse.jgit.treewalk.TreeWalk
import org.eclipse.jgit.revwalk.RevWalk
import scala.collection.mutable.ListBuffer
import org.eclipse.jgit.lib.FileMode
class IndexController extends IndexControllerBase
with RepositoryService with AccountService with SystemSettingsService with ActivityService with IssuesService
with ReferrerAuthenticator
trait IndexControllerBase extends ControllerBase { self: RepositoryService
with SystemSettingsService with ActivityService with IssuesService
with ReferrerAuthenticator =>
val searchForm = mapping(
"query" -> trim(text(required)),
"owner" -> trim(text(required)),
"repository" -> trim(text(required))
)(SearchForm.apply)
case class SearchForm(query: String, owner: String, repository: String)
get("/"){
val loginAccount = context.loginAccount
html.index(getRecentActivities(),
getAccessibleRepositories(loginAccount, baseUrl),
loadSystemSettings(),
loginAccount.map{ account => getRepositoryNamesOfUser(account.userName) }.getOrElse(Nil)
)
}
post("/search", searchForm){ form =>
redirect(s"${form.owner}/${form.repository}/search?q=${StringUtil.urlEncode(form.query)}")
}
get("/:owner/:repository/search")(referrersOnly { repository =>
val query = params("q").trim
val target = params.getOrElse("type", "code")
target.toLowerCase match {
case "issue" => if(query.isEmpty){
search.html.issues(Nil, "", repository)
} else {
search.html.issues(queryIssues(repository.owner, repository.name, query).map { case (issue, commentCount, content) =>
IssueSearchResult(
issue.issueId,
issue.title,
issue.openedUserName,
issue.registeredDate,
commentCount,
getHighlightText(content, query)._1)
}, query, repository)
}
case _ => if(query.isEmpty){
// TODO move to JGitUtil?
search.html.code(Nil, "", repository)
} else {
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)
treeWalk.setRecursive(true)
treeWalk.addTree(revCommit.getTree)
val lowerQueries = StringUtil.splitWords(query.toLowerCase)
val list = new ListBuffer[(String, (String, Int))]
while (treeWalk.next()) {
if(treeWalk.getFileMode(0) != FileMode.TREE){
JGitUtil.getContent(git, treeWalk.getObjectId(0), false).foreach { bytes =>
if(FileUtil.isText(bytes)){
val text = new String(bytes, "UTF-8")
val lowerText = text.toLowerCase
val indices = lowerQueries.map(lowerText.indexOf _)
if(!indices.exists(_ < 0)){
list.append((treeWalk.getPathString, getHighlightText(text, query)))
}
}
}
}
}
treeWalk.release
revWalk.release
val commits = JGitUtil.getLatestCommitFromPaths(git, list.toList.map(_._1), "HEAD")
search.html.code(list.toList.map { case (path, highlightText) =>
FileSearchResult(path, commits(path).getCommitterIdent.getWhen, highlightText._1, highlightText._2)
}, query, repository)
}
}
}
})
private def getHighlightText(content: String, query: String): (String, Int) = {
val lowerQueries = StringUtil.splitWords(query.toLowerCase)
val lowerText = content.toLowerCase
val indices = lowerQueries.map(lowerText.indexOf _)
if(!indices.exists(_ < 0)){
val lineNumber = content.substring(0, indices.min).split("\n").size - 1
val highlightText = 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>")
(highlightText, lineNumber + 1)
} else {
(content.split("\n").take(5).mkString("\n"), 1)
}
}
}
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,
highlightLineNumber: Int)