diff --git a/src/main/scala/app/IndexController.scala b/src/main/scala/app/IndexController.scala index 34631e1..1e71751 100644 --- a/src/main/scala/app/IndexController.scala +++ b/src/main/scala/app/IndexController.scala @@ -47,7 +47,7 @@ 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) => + search.html.issues(searchIssuesByKeyword(repository.owner, repository.name, query).map { case (issue, commentCount, content) => IssueSearchResult( issue.issueId, issue.title, @@ -69,7 +69,7 @@ treeWalk.setRecursive(true) treeWalk.addTree(revCommit.getTree) - val lowerQueries = StringUtil.splitWords(query.toLowerCase) + val keywords = StringUtil.splitWords(query.toLowerCase) val list = new ListBuffer[(String, (String, Int))] while (treeWalk.next()) { if(treeWalk.getFileMode(0) != FileMode.TREE){ @@ -77,7 +77,7 @@ if(FileUtil.isText(bytes)){ val text = new String(bytes, "UTF-8") val lowerText = text.toLowerCase - val indices = lowerQueries.map(lowerText.indexOf _) + val indices = keywords.map(lowerText.indexOf _) if(!indices.exists(_ < 0)){ list.append((treeWalk.getPathString, getHighlightText(text, query))) } @@ -99,14 +99,14 @@ }) 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 _) + val keywords = StringUtil.splitWords(query.toLowerCase) + val lowerText = content.toLowerCase + val indices = keywords.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("|") + ")", + .replaceAll("(?i)(" + keywords.map("\\Q" + _ + "\\E").mkString("|") + ")", "$1") (highlightText, lineNumber + 1) } else { diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala index 3e7ed11..6256f64 100644 --- a/src/main/scala/service/IssuesService.scala +++ b/src/main/scala/service/IssuesService.scala @@ -236,13 +236,22 @@ } .update (closed, currentDate) - def queryIssues(owner: String, repository: String, query: String): List[(Issue, Int, String)] = { - val lowerQueries = StringUtil.splitWords(query.toLowerCase) + /** + * Search issues by keyword. + * + * @param owner the repository owner + * @param repository the repository name + * @param query the keywords separated by whitespace. + * @return issues with comment count and matched content of issue or comment + */ + def searchIssuesByKeyword(owner: String, repository: String, query: String): List[(Issue, Int, String)] = { + import scala.slick.driver.H2Driver.likeEncode + val keywords = StringUtil.splitWords(query.toLowerCase) // Search Issue val issues = Query(Issues).filter { t => - lowerQueries.map { query => - (t.title.toLowerCase like '%' + query + '%') || (t.content.toLowerCase like '%' + query + '%') // TODO escape!!!! + keywords.map { keyword => + (t.title.toLowerCase like (s"%${likeEncode(keyword)}%", '^')) || (t.content.toLowerCase like (s"%${likeEncode(keyword)}%", '^')) } .reduceLeft { (a, b) => a && b } @@ -252,8 +261,8 @@ 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 like '%' + query + '%' // TODO escape!!!! + keywords.map { query => + t1.content.toLowerCase like (s"%${likeEncode(query)}%", '^') }.reduceLeft { (a, b) => a && b }