From 57109dd72eb578d3ca21c0dac5997e17cd979102 Mon Sep 17 00:00:00 2001 From: takezoe Date: Mon, 29 Jul 2013 13:24:01 +0900 Subject: [PATCH 01/21] Add init-param 'webAllowOthers' to web.xml. --- src/main/webapp/WEB-INF/web.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 1f509d511..65863eb73 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -81,16 +81,16 @@ H2Console org.h2.server.web.WebServlet - + 1 From 045b7cf019551016b539a5ed47b307b9e7007064 Mon Sep 17 00:00:00 2001 From: takezoe Date: Mon, 29 Jul 2013 17:10:45 +0900 Subject: [PATCH 02/21] Fix avatar problem. --- src/main/scala/view/AvatarImageProvider.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/scala/view/AvatarImageProvider.scala b/src/main/scala/view/AvatarImageProvider.scala index bd1703d24..28cf7f3a6 100644 --- a/src/main/scala/view/AvatarImageProvider.scala +++ b/src/main/scala/view/AvatarImageProvider.scala @@ -12,8 +12,13 @@ trait AvatarImageProvider { self: RequestCache => */ protected def getAvatarImageHtml(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(implicit context: app.Context): Html = { - val src = getAccountByUserName(userName).collect { case account if(account.image.isEmpty) => - s"""http://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress)}?s=${size}""" + + val src = getAccountByUserName(userName).map { account => + if(account.image.isEmpty){ + s"""http://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress)}?s=${size}""" + } else { + s"""${context.path}/${userName}/_avatar""" + } } getOrElse { if(mailAddress.nonEmpty){ s"""http://www.gravatar.com/avatar/${StringUtil.md5(mailAddress)}?s=${size}""" From 25d402c9d1336b82a7d08209934ee1d342586dad Mon Sep 17 00:00:00 2001 From: takezoe Date: Mon, 29 Jul 2013 22:57:57 +0900 Subject: [PATCH 03/21] (refs #53)Fix path extraction for branch which contains '/'. --- .../app/RepositoryViewerController.scala | 58 ++++++++----------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 43cb126b3..e1935a3c4 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -37,49 +37,29 @@ trait RepositoryViewerControllerBase extends ControllerBase { fileList(_) }) - /** - * Displays the file list of the repository root and the specified branch. - */ - get("/:owner/:repository/tree/:id")(referrersOnly { - fileList(_, params("id")) - }) - /** * Displays the file list of the specified path and branch. */ - get("/:owner/:repository/tree/:id/*")(referrersOnly { - fileList(_, params("id"), multiParams("splat").head) - }) - - /** - * Displays the commit list of the specified branch. - */ - get("/:owner/:repository/commits/:branch")(referrersOnly { repository => - val branchName = params("branch") - val page = params.getOrElse("page", "1").toInt - JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => - JGitUtil.getCommitLog(git, branchName, page, 30) match { - case Right((logs, hasNext)) => - repo.html.commits(Nil, branchName, repository, logs.splitWith{ (commit1, commit2) => - view.helpers.date(commit1.time) == view.helpers.date(commit2.time) - }, page, hasNext) - case Left(_) => NotFound - } + get("/:owner/:repository/tree/*")(referrersOnly { repository => + val (id, path) = splitPath(repository, multiParams("splat").head) + if(path.isEmpty){ + fileList(repository, id) + } else { + fileList(repository, id, path) } }) /** * Displays the commit list of the specified resource. */ - get("/:owner/:repository/commits/:branch/*")(referrersOnly { repository => - val branchName = params("branch") - val path = multiParams("splat").head //.replaceFirst("^tree/.+?/", "") - val page = params.getOrElse("page", "1").toInt + get("/:owner/:repository/commits/*")(referrersOnly { repository => + val (branchName, path) = splitPath(repository, multiParams("splat").head) + val page = params.getOrElse("page", "1").toInt JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => JGitUtil.getCommitLog(git, branchName, page, 30, path) match { case Right((logs, hasNext)) => - repo.html.commits(path.split("/").toList, branchName, repository, + repo.html.commits(if(path.isEmpty) Nil else path.split("/").toList, branchName, repository, logs.splitWith{ (commit1, commit2) => view.helpers.date(commit1.time) == view.helpers.date(commit2.time) }, page, hasNext) @@ -88,13 +68,23 @@ trait RepositoryViewerControllerBase extends ControllerBase { } }) + private def splitPath(repository: service.RepositoryService.RepositoryInfo, path: String): (String, String) = { + val id = repository.branchList.collectFirst { + case branch if(path == branch || path.startsWith(branch + "/")) => branch + } orElse repository.tags.collectFirst { + case tag if(path == tag.name || path.startsWith(tag.name + "/")) => tag.name + } orElse Some(path) get + + (id, path.substring(id.length).replaceFirst("^/", "")) + } + + /** * Displays the file content of the specified branch or commit. */ - get("/:owner/:repository/blob/:id/*")(referrersOnly { repository => - val id = params("id") // branch name or commit id - val raw = params.get("raw").getOrElse("false").toBoolean - val path = multiParams("splat").head //.replaceFirst("^tree/.+?/", "") + get("/:owner/:repository/blob/*")(referrersOnly { repository => + val (id, path) = splitPath(repository, multiParams("splat").head) + val raw = params.get("raw").getOrElse("false").toBoolean JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id)) From 1f2b6a0acccc7b7106a683091f10c5d6fd5a3ede Mon Sep 17 00:00:00 2001 From: takezoe Date: Mon, 29 Jul 2013 22:58:30 +0900 Subject: [PATCH 04/21] Adjust whitespaces. --- src/main/twirl/repo/tab.scala.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/twirl/repo/tab.scala.html b/src/main/twirl/repo/tab.scala.html index 01b2ada36..0587e862b 100644 --- a/src/main/twirl/repo/tab.scala.html +++ b/src/main/twirl/repo/tab.scala.html @@ -26,9 +26,9 @@ } - Files + Files Commits - Tags@if(repository.tags.length > 0){ @repository.tags.length} + Tags@if(repository.tags.length > 0){ @repository.tags.length}
  • From 41a613e1515fdfe7d8c4c11695f8501323e52e04 Mon Sep 17 00:00:00 2001 From: takezoe Date: Tue, 30 Jul 2013 02:45:14 +0900 Subject: [PATCH 05/21] Move private method. --- .../app/RepositoryViewerController.scala | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index e1935a3c4..3a510c81f 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -68,17 +68,6 @@ trait RepositoryViewerControllerBase extends ControllerBase { } }) - private def splitPath(repository: service.RepositoryService.RepositoryInfo, path: String): (String, String) = { - val id = repository.branchList.collectFirst { - case branch if(path == branch || path.startsWith(branch + "/")) => branch - } orElse repository.tags.collectFirst { - case tag if(path == tag.name || path.startsWith(tag.name + "/")) => tag.name - } orElse Some(path) get - - (id, path.substring(id.length).replaceFirst("^/", "")) - } - - /** * Displays the file content of the specified branch or commit. */ @@ -192,7 +181,17 @@ trait RepositoryViewerControllerBase extends ControllerBase { BadRequest } }) - + + private def splitPath(repository: service.RepositoryService.RepositoryInfo, path: String): (String, String) = { + val id = repository.branchList.collectFirst { + case branch if(path == branch || path.startsWith(branch + "/")) => branch + } orElse repository.tags.collectFirst { + case tag if(path == tag.name || path.startsWith(tag.name + "/")) => tag.name + } orElse Some(path) get + + (id, path.substring(id.length).replaceFirst("^/", "")) + } + /** * Provides HTML of the file list. * From 7079d50fdf1bb3b7a46928e3ba8036564df14bbe Mon Sep 17 00:00:00 2001 From: Tomofumi Tanaka Date: Tue, 30 Jul 2013 03:26:36 +0900 Subject: [PATCH 06/21] Make more fast and github-like repository viewer --- src/main/scala/util/JGitUtil.scala | 50 +++--------------------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/src/main/scala/util/JGitUtil.scala b/src/main/scala/util/JGitUtil.scala index f42c68d5b..f54b9c093 100644 --- a/src/main/scala/util/JGitUtil.scala +++ b/src/main/scala/util/JGitUtil.scala @@ -348,51 +348,11 @@ object JGitUtil { * @return the list of latest commit */ def getLatestCommitFromPaths(git: Git, paths: List[String], revision: String): Map[String, RevCommit] = { - - val map = new scala.collection.mutable.HashMap[String, RevCommit] - - val revWalk = new RevWalk(git.getRepository) - revWalk.markStart(revWalk.parseCommit(git.getRepository.resolve(revision))) - //revWalk.sort(RevSort.REVERSE); - val i = revWalk.iterator - - while(i.hasNext && map.size != paths.length){ - val commit = i.next - if(commit.getParentCount == 0){ - // Initial commit - val treeWalk = new TreeWalk(git.getRepository) - treeWalk.reset() - treeWalk.setRecursive(true) - treeWalk.addTree(commit.getTree) - while (treeWalk.next) { - paths.foreach { path => - if(treeWalk.getPathString.startsWith(path) && !map.contains(path)){ - map.put(path, commit) - } - } - } - treeWalk.release - } else { - (0 to commit.getParentCount - 1).foreach { i => - val parent = revWalk.parseCommit(commit.getParent(i).getId()) - val df = new DiffFormatter(DisabledOutputStream.INSTANCE) - df.setRepository(git.getRepository) - df.setDiffComparator(RawTextComparator.DEFAULT) - df.setDetectRenames(true) - val diffs = df.scan(parent.getTree(), commit.getTree) - diffs.asScala.foreach { diff => - paths.foreach { path => - if(diff.getChangeType != ChangeType.DELETE && diff.getNewPath.startsWith(path) && !map.contains(path)){ - map.put(path, commit) - } - } - } - } - } - - revWalk.release - } - map.toMap + val start = git.getRepository.resolve(revision) + paths.map { path => + val commit = git.log.add(start).addPath(path).setMaxCount(1).call.iterator.next + (path, commit) + }.toMap } /** From 7d6571778402cc8222a97d9977ed228c9c01c964 Mon Sep 17 00:00:00 2001 From: takezoe Date: Tue, 30 Jul 2013 03:41:47 +0900 Subject: [PATCH 07/21] The method of RepositoryService was cleaned up. --- src/main/scala/app/AccountController.scala | 2 +- src/main/scala/app/DashboardController.scala | 2 +- src/main/scala/app/IndexController.scala | 11 +-- .../scala/service/RepositoryService.scala | 72 ++++++++----------- src/main/twirl/index.scala.html | 18 +++-- 5 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/main/scala/app/AccountController.scala b/src/main/scala/app/AccountController.scala index acf066fde..48b649b30 100644 --- a/src/main/scala/app/AccountController.scala +++ b/src/main/scala/app/AccountController.scala @@ -58,7 +58,7 @@ trait AccountControllerBase extends AccountManagementControllerBase with FlashMa case _ => _root_.account.html.repositories(account, if(account.isGroupAccount) Nil else getGroupsByUserName(userName), - getVisibleRepositories(userName, baseUrl, context.loginAccount.map(_.userName))) + getVisibleRepositories(context.loginAccount, baseUrl, Some(userName))) } } getOrElse NotFound } diff --git a/src/main/scala/app/DashboardController.scala b/src/main/scala/app/DashboardController.scala index 02e1668cc..f3558ab1e 100644 --- a/src/main/scala/app/DashboardController.scala +++ b/src/main/scala/app/DashboardController.scala @@ -33,7 +33,7 @@ trait DashboardControllerBase extends ControllerBase { session.put(sessionKey, condition) - val repositories = getAccessibleRepositories(context.loginAccount, baseUrl) + val repositories = getUserRepositories(context.loginAccount.get.userName, baseUrl) // dashboard.html.issues( issues.html.listparts(Nil, 0, 0, 0, condition), diff --git a/src/main/scala/app/IndexController.scala b/src/main/scala/app/IndexController.scala index 5612f9be3..f82749246 100644 --- a/src/main/scala/app/IndexController.scala +++ b/src/main/scala/app/IndexController.scala @@ -16,19 +16,22 @@ trait IndexControllerBase extends ControllerBase { val loginAccount = context.loginAccount html.index(getRecentActivities(), - getAccessibleRepositories(loginAccount, baseUrl), + getVisibleRepositories(loginAccount, baseUrl), loadSystemSettings(), - loginAccount.map{ account => getRepositoryNamesOfUser(account.userName) }.getOrElse(Nil) + loginAccount.map{ account => getUserRepositories(account.userName, baseUrl) }.getOrElse(Nil) ) } /** * JSON API for collaborator completion. + * + * TODO Move to other controller? */ - // TODO Move to other controller? get("/_user/proposals")(usersOnly { contentType = formats("json") - org.json4s.jackson.Serialization.write(Map("options" -> getAllUsers.filter(!_.isGroupAccount).map(_.userName).toArray)) + org.json4s.jackson.Serialization.write( + Map("options" -> getAllUsers.filter(!_.isGroupAccount).map(_.userName).toArray) + ) }) diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala index b8c75961f..ce86ffd3a 100644 --- a/src/main/scala/service/RepositoryService.scala +++ b/src/main/scala/service/RepositoryService.scala @@ -53,39 +53,6 @@ trait RepositoryService { self: AccountService => def getRepositoryNamesOfUser(userName: String): List[String] = Query(Repositories) filter(_.userName is userName.bind) map (_.repositoryName) list - /** - * Returns the list of specified user's repositories information. - * - * @param userName the user name - * @param baseUrl the base url of this application - * @param loginUserName the logged in user name - * @return the list of repository information which is sorted in descending order of lastActivityDate. - */ - def getVisibleRepositories(userName: String, baseUrl: String, loginUserName: Option[String]): List[RepositoryInfo] = { - val q1 = Repositories - .filter { t => t.userName is userName.bind } - .map { r => r } - - val q2 = Collaborators - .innerJoin(Repositories).on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName)) - .filter{ case (t1, t2) => t1.collaboratorName is userName.bind} - .map { case (t1, t2) => t2 } - - def visibleFor(t: Repositories.type, loginUserName: Option[String]) = { - loginUserName match { - case Some(x) => (t.isPrivate is false.bind) || ( - (t.isPrivate is true.bind) && ((t.userName is x.bind) || (Collaborators.filter { c => - c.byRepository(t.userName, t.repositoryName) && (c.collaboratorName is x.bind) - }.exists))) - case None => (t.isPrivate is false.bind) - } - } - - q1.union(q2).filter(visibleFor(_, loginUserName)).sortBy(_.lastActivityDate desc).list map { repository => - new RepositoryInfo(JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl), repository) - } - } - /** * Returns the specified repository information. * @@ -101,29 +68,46 @@ trait RepositoryService { self: AccountService => } /** - * Returns the list of accessible repositories information for the specified account user. - * - * @param account the account - * @param baseUrl the base url of this application - * @return the repository informations which is sorted in descending order of lastActivityDate. + * Returns the list of specified user's repositories. + * It contains own repositories and collaboration repositories. */ - def getAccessibleRepositories(account: Option[Account], baseUrl: String): List[RepositoryInfo] = { - - def newRepositoryInfo(repository: Repository): RepositoryInfo = { + def getUserRepositories(userName: String, baseUrl: String): List[RepositoryInfo] = { + Query(Repositories).filter { t1 => + (t1.userName is userName.bind) || + (Query(Collaborators).filter { t2 => t2.byRepository(t1.userName, t1.repositoryName) && (t2.collaboratorName is userName.bind)} exists) + }.sortBy(_.lastActivityDate desc).list.map{ repository => new RepositoryInfo(JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl), repository) } + } - (account match { + /** + * Returns the list of visible repositories for the specified user. + * If repositoryUserName is given then filters results by repository owner. + * + * @param loginAccount the logged in account + * @param baseUrl the base url of this application + * @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user) + * @return the repository information which is sorted in descending order of lastActivityDate. + */ + def getVisibleRepositories(loginAccount: Option[Account], baseUrl: String, repositoryUserName: Option[String] = None): List[RepositoryInfo] = { + + val query = loginAccount match { // for Administrators case Some(x) if(x.isAdmin) => Query(Repositories) // for Normal Users case Some(x) if(!x.isAdmin) => Query(Repositories) filter { t => (t.isPrivate is false.bind) || - (Query(Collaborators).filter(t2 => t2.byRepository(t.userName, t.repositoryName) && (t2.collaboratorName is x.userName.bind)) exists) + (Query(Collaborators).filter { t2 => t2.byRepository(t.userName, t.repositoryName) && (t2.collaboratorName is x.userName.bind)} exists) } // for Guests case None => Query(Repositories) filter(_.isPrivate is false.bind) - }).sortBy(_.lastActivityDate desc).list.map(newRepositoryInfo _) + } + + val filtered = repositoryUserName.map { userName => query.filter(_.userName is userName.bind) } getOrElse query + + filtered.sortBy(_.lastActivityDate desc).list.map{ repository => + new RepositoryInfo(JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl), repository) + } } /** diff --git a/src/main/twirl/index.scala.html b/src/main/twirl/index.scala.html index c15f05740..d62da6f51 100644 --- a/src/main/twirl/index.scala.html +++ b/src/main/twirl/index.scala.html @@ -1,7 +1,7 @@ @(activities: List[model.Activity], - repositories: List[service.RepositoryService.RepositoryInfo], + recentRepositories: List[service.RepositoryService.RepositoryInfo], systemSettings: service.SystemSettingsService.SystemSettings, - userRepositories: List[String])(implicit context: app.Context) + userRepositories: List[service.RepositoryService.RepositoryInfo])(implicit context: app.Context) @import context._ @import view.helpers._ @main("GitBucket"){ @@ -28,9 +28,15 @@ No repositories } else { - @userRepositories.map { repositoryName => + @userRepositories.map { repository => - @repositoryName + + @if(repository.owner == loginAccount.get.userName){ + @repository.name + } else { + @repository.owner/@repository.name + } + } } @@ -43,12 +49,12 @@ Recent updated repositories - @if(repositories.isEmpty){ + @if(recentRepositories.isEmpty){ No repositories } else { - @repositories.map { repository => + @recentRepositories.map { repository => @repository.owner/@repository.name From 8409384232f3fdcea8dfe1cfa364c336c1eb1b40 Mon Sep 17 00:00:00 2001 From: shimamoto Date: Tue, 30 Jul 2013 10:47:46 +0900 Subject: [PATCH 08/21] (refs #26) Implements the dashboard issue display. --- src/main/scala/app/DashboardController.scala | 18 +++++--- src/main/scala/app/IssuesController.scala | 24 ++++------ src/main/scala/service/IssuesService.scala | 46 ++++++++++---------- src/main/twirl/dashboard/issues.scala.html | 8 ++-- src/main/twirl/issues/listparts.scala.html | 2 +- 5 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/main/scala/app/DashboardController.scala b/src/main/scala/app/DashboardController.scala index 02e1668cc..9a2fcb9e5 100644 --- a/src/main/scala/app/DashboardController.scala +++ b/src/main/scala/app/DashboardController.scala @@ -33,13 +33,21 @@ trait DashboardControllerBase extends ControllerBase { session.put(sessionKey, condition) - val repositories = getAccessibleRepositories(context.loginAccount, baseUrl) + val userName = context.loginAccount.get.userName + val repositories = getUserRepositories(userName, baseUrl).map(repo => repo.owner -> repo.name) + val filterUser = Map(filter -> userName) + val page = IssueSearchCondition.page(request) // dashboard.html.issues( - issues.html.listparts(Nil, 0, 0, 0, condition), - 0, - 0, - 0, + issues.html.listparts( + searchIssue(condition, filterUser, (page - 1) * IssueLimit, IssueLimit, repositories: _*), + page, + countIssue(condition.copy(state = "open"), filterUser, repositories: _*), + countIssue(condition.copy(state = "closed"), filterUser, repositories: _*), + condition), + countIssue(condition, Map.empty, repositories: _*), + countIssue(condition, Map("assigned" -> userName), repositories: _*), + countIssue(condition, Map("created_by" -> userName), repositories: _*), repositories, condition, filter) diff --git a/src/main/scala/app/IssuesController.scala b/src/main/scala/app/IssuesController.scala index 0c8b35f25..af8da84a5 100644 --- a/src/main/scala/app/IssuesController.scala +++ b/src/main/scala/app/IssuesController.scala @@ -301,16 +301,10 @@ trait IssuesControllerBase extends ControllerBase { private def searchIssues(filter: String, repository: RepositoryService.RepositoryInfo) = { val owner = repository.owner val repoName = repository.name - val userName = if(filter != "all") Some(params("userName")) else None + val filterUser = Map(filter -> params.getOrElse("userName", "")) + val page = IssueSearchCondition.page(request) val sessionKey = s"${owner}/${repoName}/issues" - val page = try { - val i = params.getOrElse("page", "1").toInt - if(i <= 0) 1 else i - } catch { - case e: NumberFormatException => 1 - } - // retrieve search condition val condition = if(request.getQueryString == null){ session.get(sessionKey).getOrElse(IssueSearchCondition()).asInstanceOf[IssueSearchCondition] @@ -319,17 +313,17 @@ trait IssuesControllerBase extends ControllerBase { session.put(sessionKey, condition) issues.html.list( - searchIssue(owner, repoName, condition, filter, userName, (page - 1) * IssueLimit, IssueLimit), + searchIssue(condition, filterUser, (page - 1) * IssueLimit, IssueLimit, owner -> repoName), page, (getCollaborators(owner, repoName) :+ owner).sorted, getMilestones(owner, repoName), getLabels(owner, repoName), - countIssue(owner, repoName, condition.copy(state = "open"), filter, userName), - countIssue(owner, repoName, condition.copy(state = "closed"), filter, userName), - countIssue(owner, repoName, condition, "all", None), - context.loginAccount.map(x => countIssue(owner, repoName, condition, "assigned", Some(x.userName))), - context.loginAccount.map(x => countIssue(owner, repoName, condition, "created_by", Some(x.userName))), - countIssueGroupByLabels(owner, repoName, condition, filter, userName), + countIssue(condition.copy(state = "open"), filterUser, owner -> repoName), + countIssue(condition.copy(state = "closed"), filterUser, owner -> repoName), + countIssue(condition, Map.empty, owner -> repoName), + context.loginAccount.map(x => countIssue(condition, Map("assigned" -> x.userName), owner -> repoName)), + context.loginAccount.map(x => countIssue(condition, Map("created_by" -> x.userName), owner -> repoName)), + countIssueGroupByLabels(owner, repoName, condition, filterUser), condition, filter, repository, diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala index ac1ca2b78..74dc9cde6 100644 --- a/src/main/scala/service/IssuesService.scala +++ b/src/main/scala/service/IssuesService.scala @@ -42,18 +42,16 @@ trait IssuesService { /** * Returns the count of the search result against issues. * - * @param owner the repository owner - * @param repository the repository name * @param condition the search condition - * @param filter the filter type ("all", "assigned" or "created_by") - * @param userName the filter user name required for "assigned" and "created_by" + * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name) + * @param repos Tuple of the repository owner and the repository name * @return the count of the search result */ - def countIssue(owner: String, repository: String, condition: IssueSearchCondition, filter: String, userName: Option[String]): Int = { + def countIssue(condition: IssueSearchCondition, filterUser: Map[String, String], repos: (String, String)*): Int = { // TODO It must be _.length instead of map (_.issueId) list).length. // But it does not work on Slick 1.0.1 (worked on Slick 1.0.0). // https://github.com/slick/slick/issues/170 - (searchIssueQuery(owner, repository, condition, filter, userName) map (_.issueId) list).length + (searchIssueQuery(repos, condition, filterUser) map (_.issueId) list).length } /** * Returns the Map which contains issue count for each labels. @@ -61,14 +59,13 @@ trait IssuesService { * @param owner the repository owner * @param repository the repository name * @param condition the search condition - * @param filter the filter type ("all", "assigned" or "created_by") - * @param userName the filter user name required for "assigned" and "created_by" - * @return the Map which contains issue count for each labels (key is label name, value is issue count), + * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name) + * @return the Map which contains issue count for each labels (key is label name, value is issue count) */ def countIssueGroupByLabels(owner: String, repository: String, condition: IssueSearchCondition, - filter: String, userName: Option[String]): Map[String, Int] = { + filterUser: Map[String, String]): Map[String, Int] = { - searchIssueQuery(owner, repository, condition.copy(labels = Set.empty), filter, userName) + searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), filterUser) .innerJoin(IssueLabels).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) } @@ -87,20 +84,18 @@ trait IssuesService { /** * Returns the search result against issues. * - * @param owner the repository owner - * @param repository the repository name * @param condition the search condition - * @param filter the filter type ("all", "assigned" or "created_by") - * @param userName the filter user name required for "assigned" and "created_by" + * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name) * @param offset the offset for pagination * @param limit the limit for pagination + * @param repos Tuple of the repository owner and the repository name * @return the search result (list of tuples which contain issue, labels and comment count) */ - def searchIssue(owner: String, repository: String, condition: IssueSearchCondition, - filter: String, userName: Option[String], offset: Int, limit: Int): List[(Issue, List[Label], Int)] = { + def searchIssue(condition: IssueSearchCondition, filterUser: Map[String, String], + offset: Int, limit: Int, repos: (String, String)*): List[(Issue, List[Label], Int)] = { // get issues and comment count and labels - searchIssueQuery(owner, repository, condition, filter, userName) + searchIssueQuery(repos, condition, filterUser) .innerJoin(IssueOutline).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) } .leftJoin (IssueLabels) .on { case ((t1, t2), t3) => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) } .leftJoin (Labels) .on { case (((t1, t2), t3), t4) => t3.byLabel(t4.userName, t4.repositoryName, t4.labelId) } @@ -136,14 +131,14 @@ trait IssuesService { /** * Assembles query for conditional issue searching. */ - private def searchIssueQuery(owner: String, repository: String, condition: IssueSearchCondition, filter: String, userName: Option[String]) = + private def searchIssueQuery(repos: Seq[(String, String)], condition: IssueSearchCondition, filterUser: Map[String, String]) = Query(Issues) filter { t1 => - (t1.byRepository(owner, repository)) && + (repos.map { case (owner, repository) => t1.byRepository(owner, repository) } reduceLeft ( _ || _ ) ) && (t1.closed is (condition.state == "closed").bind) && (t1.milestoneId is condition.milestoneId.get.get.bind, condition.milestoneId.flatten.isDefined) && (t1.milestoneId isNull, condition.milestoneId == Some(None)) && - (t1.assignedUserName is userName.get.bind, filter == "assigned") && - (t1.openedUserName is userName.get.bind, filter == "created_by") && + (t1.assignedUserName is filterUser("assigned").bind, filterUser.get("assigned").isDefined) && + (t1.openedUserName is filterUser("created_by").bind, filterUser.get("created_by").isDefined) && (IssueLabels filter { t2 => (t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) && (t2.labelId in @@ -329,6 +324,13 @@ object IssuesService { param(request, "state", Seq("open", "closed")).getOrElse("open"), param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"), param(request, "direction", Seq("asc", "desc")).getOrElse("desc")) + + def page(request: HttpServletRequest) = try { + val i = param(request, "page").getOrElse("1").toInt + if(i <= 0) 1 else i + } catch { + case e: NumberFormatException => 1 + } } } diff --git a/src/main/twirl/dashboard/issues.scala.html b/src/main/twirl/dashboard/issues.scala.html index b1839ab77..5434bc3df 100644 --- a/src/main/twirl/dashboard/issues.scala.html +++ b/src/main/twirl/dashboard/issues.scala.html @@ -2,7 +2,7 @@ allCount: Int, assignedCount: Int, createdByCount: Int, - repositories: List[service.RepositoryService.RepositoryInfo], + repositories: List[(String, String)], condition: service.IssuesService.IssueSearchCondition, filter: String)(implicit context: app.Context) @import context._ @@ -33,11 +33,11 @@