diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 285c50e..120081c 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -2,7 +2,7 @@ import util.Directory._ import util.Implicits._ -import util.{JGitUtil, FileTypeUtil, CompressUtil} +import _root_.util.{ReadableRepositoryAuthenticator, JGitUtil, FileTypeUtil, CompressUtil} import service._ import org.scalatra._ import java.io.File @@ -12,13 +12,13 @@ import org.eclipse.jgit.treewalk._ class RepositoryViewerController extends RepositoryViewerControllerBase - with RepositoryService with AccountService + with RepositoryService with AccountService with ReadableRepositoryAuthenticator /** * The repository viewer. */ trait RepositoryViewerControllerBase extends ControllerBase { - self: RepositoryService with AccountService => + self: RepositoryService with AccountService with ReadableRepositoryAuthenticator => // TODO separate to AccountController? /** @@ -33,37 +33,37 @@ /** * Displays the file list of the repository root and the default branch. */ - get("/:owner/:repository") { + get("/:owner/:repository")(readableRepository { val owner = params("owner") val repository = params("repository") fileList(owner, repository) - } + }) /** * Displays the file list of the repository root and the specified branch. */ - get("/:owner/:repository/tree/:id") { + get("/:owner/:repository/tree/:id")(readableRepository { val owner = params("owner") val repository = params("repository") fileList(owner, repository, params("id")) - } + }) /** * Displays the file list of the specified path and branch. */ - get("/:owner/:repository/tree/:id/*") { + get("/:owner/:repository/tree/:id/*")(readableRepository { val owner = params("owner") val repository = params("repository") fileList(owner, repository, params("id"), multiParams("splat").head) - } + }) /** * Displays the commit list of the specified branch. */ - get("/:owner/:repository/commits/:branch"){ + get("/:owner/:repository/commits/:branch")(readableRepository { val owner = params("owner") val repository = params("repository") val branchName = params("branch") @@ -77,12 +77,12 @@ view.helpers.date(commit1.time) == view.helpers.date(commit2.time) }, page, hasNext) } - } + }) /** * Displays the commit list of the specified resource. */ - get("/:owner/:repository/commits/:branch/*"){ + get("/:owner/:repository/commits/:branch/*")(readableRepository { val owner = params("owner") val repository = params("repository") val branchName = params("branch") @@ -97,13 +97,13 @@ view.helpers.date(commit1.time) == view.helpers.date(commit2.time) }, page, hasNext) } - } + }) /** * Displays the file content of the specified branch or commit. */ - get("/:owner/:repository/blob/:id/*"){ + get("/:owner/:repository/blob/:id/*")(readableRepository { val owner = params("owner") val repository = params("repository") val id = params("id") // branch name or commit id @@ -140,12 +140,12 @@ repo.html.blob(id, repositoryInfo, path.split("/").toList, content, new JGitUtil.CommitInfo(revCommit)) } } - } + }) /** * Displays details of the specified commit. */ - get("/:owner/:repository/commit/:id"){ + get("/:owner/:repository/commit/:id")(readableRepository { val owner = params("owner") val repository = params("repository") val id = params("id") @@ -155,22 +155,22 @@ repo.html.commit(id, new JGitUtil.CommitInfo(revCommit), getRepository(owner, repository, servletContext).get, JGitUtil.getDiffs(git, id)) } - } + }) /** * Displays tags. */ - get("/:owner/:repository/tags"){ + get("/:owner/:repository/tags")(readableRepository { val owner = params("owner") val repository = params("repository") repo.html.tags(getRepository(owner, repository, servletContext).get) - } + }) /** * Download repository contents as an archive. */ - get("/:owner/:repository/archive/:name"){ + get("/:owner/:repository/archive/:name")(readableRepository { val owner = params("owner") val repository = params("repository") val name = params("name") @@ -206,7 +206,7 @@ } else { BadRequest } - } + }) /** * Provides HTML of the file list. diff --git a/src/main/scala/app/SettingsController.scala b/src/main/scala/app/SettingsController.scala index 460f95e..32f54d0 100644 --- a/src/main/scala/app/SettingsController.scala +++ b/src/main/scala/app/SettingsController.scala @@ -46,7 +46,7 @@ /** * Save the repository options. */ - post("/:owner/:repository/settings/options", optionsForm){ form => + post("/:owner/:repository/settings/options", optionsForm)(ownerOnly { form => val owner = params("owner") val repository = params("repository") @@ -54,7 +54,7 @@ saveRepositoryOptions(owner, repository, form.description, form.defaultBranch, form.repositoryType) redirect("%s/%s/settings/options".format(owner, repository)) - } + }) /** * Display the Collaborators page. diff --git a/src/main/scala/app/UsersController.scala b/src/main/scala/app/UsersController.scala index 3ca0075..92aceeb 100644 --- a/src/main/scala/app/UsersController.scala +++ b/src/main/scala/app/UsersController.scala @@ -2,11 +2,12 @@ import model._ import service._ +import util.AdminOnlyAuthenticator import jp.sf.amateras.scalatra.forms._ -class UsersController extends UsersControllerBase with AccountService +class UsersController extends UsersControllerBase with AccountService with AdminOnlyAuthenticator -trait UsersControllerBase extends ControllerBase { self: AccountService => +trait UsersControllerBase extends ControllerBase { self: AccountService with AdminOnlyAuthenticator => // TODO ユーザ名の先頭に_は使えないようにする&利用可能文字チェック case class UserForm(userName: String, password: String, mailAddress: String, userType: Int, url: Option[String]) @@ -27,15 +28,15 @@ "url" -> trim(label("URL" , optional(text(maxlength(200))))) )(UserForm.apply) - get("/admin/users"){ + get("/admin/users")(adminOnly { admin.html.userlist(getAllUsers()) - } + }) - get("/admin/users/_new"){ + get("/admin/users/_new")(adminOnly { admin.html.useredit(None) - } + }) - post("/admin/users/_new", newForm){ form => + post("/admin/users/_new", newForm)(adminOnly { form => val currentDate = new java.sql.Date(System.currentTimeMillis) createAccount(Account( userName = form.userName, @@ -48,14 +49,14 @@ lastLoginDate = None)) redirect("/admin/users") - } + }) - get("/admin/users/:userName/_edit"){ + get("/admin/users/:userName/_edit")(adminOnly { val userName = params("userName") admin.html.useredit(getAccountByUserName(userName)) - } + }) - post("/admin/users/:name/_edit", editForm){ form => + post("/admin/users/:name/_edit", editForm)(adminOnly { form => val userName = params("userName") val currentDate = new java.sql.Date(System.currentTimeMillis) updateAccount(getAccountByUserName(userName).get.copy( @@ -66,7 +67,7 @@ updatedDate = currentDate)) redirect("/admin/users") - } + }) def unique: Constraint = new Constraint(){ def validate(name: String, value: String): Option[String] = diff --git a/src/main/scala/app/WikiController.scala b/src/main/scala/app/WikiController.scala index d9ed92b..b6d62e0 100644 --- a/src/main/scala/app/WikiController.scala +++ b/src/main/scala/app/WikiController.scala @@ -1,15 +1,15 @@ package app import service._ -import util.{CollaboratorsOnlyAuthenticator, JGitUtil} +import util.{WritableRepositoryAuthenticator, ReadableRepositoryAuthenticator, JGitUtil} import util.Directory._ import jp.sf.amateras.scalatra.forms._ class WikiController extends WikiControllerBase - with WikiService with RepositoryService with AccountService with CollaboratorsOnlyAuthenticator + with WikiService with RepositoryService with AccountService with WritableRepositoryAuthenticator with ReadableRepositoryAuthenticator trait WikiControllerBase extends ControllerBase { - self: WikiService with RepositoryService with CollaboratorsOnlyAuthenticator => + self: WikiService with RepositoryService with WritableRepositoryAuthenticator with ReadableRepositoryAuthenticator => // TODO ユーザ名の先頭に_は使えないようにする case class WikiPageEditForm(pageName: String, content: String, message: Option[String], currentPageName: String) @@ -28,7 +28,7 @@ "currentPageName" -> trim(label("Current page name" , text(required))) )(WikiPageEditForm.apply) - get("/:owner/:repository/wiki"){ + get("/:owner/:repository/wiki")(readableRepository { val owner = params("owner") val repository = params("repository") @@ -36,9 +36,9 @@ case Some(page) => wiki.html.wiki("Home", page, getRepository(owner, repository, servletContext).get, isWritable(owner, repository)) case None => redirect("/%s/%s/wiki/Home/_edit".format(owner, repository)) } - } + }) - get("/:owner/:repository/wiki/:page"){ + get("/:owner/:repository/wiki/:page")(readableRepository { val owner = params("owner") val repository = params("repository") val pageName = params("page") @@ -47,9 +47,9 @@ case Some(page) => wiki.html.wiki(pageName, page, getRepository(owner, repository, servletContext).get, isWritable(owner, repository)) case None => redirect("/%s/%s/wiki/%s/_edit".format(owner, repository, pageName)) // TODO URLEncode } - } + }) - get("/:owner/:repository/wiki/:page/_history"){ + get("/:owner/:repository/wiki/:page/_history")(readableRepository { val owner = params("owner") val repository = params("repository") val page = params("page") @@ -58,9 +58,9 @@ wiki.html.wikihistory(Some(page), JGitUtil.getCommitLog(git, "master", path = page + ".md")._1, getRepository(owner, repository, servletContext).get) } - } + }) - get("/:owner/:repository/wiki/:page/_compare/:commitId"){ + get("/:owner/:repository/wiki/:page/_compare/:commitId")(readableRepository { val owner = params("owner") val repository = params("repository") val page = params("page") @@ -70,9 +70,9 @@ wiki.html.wikicompare(Some(page), getWikiDiffs(git, commitId(0), commitId(1)), getRepository(owner, repository, servletContext).get) } - } + }) - get("/:owner/:repository/wiki/_compare/:commitId"){ + get("/:owner/:repository/wiki/_compare/:commitId")(readableRepository { val owner = params("owner") val repository = params("repository") val commitId = params("commitId").split("\\.\\.\\.") @@ -81,9 +81,9 @@ wiki.html.wikicompare(None, getWikiDiffs(git, commitId(0), commitId(1)), getRepository(owner, repository, servletContext).get) } - } + }) - get("/:owner/:repository/wiki/:page/_edit")(collaboratorsOnly { + get("/:owner/:repository/wiki/:page/_edit")(writableRepository { val owner = params("owner") val repository = params("repository") val page = params("page") @@ -92,7 +92,7 @@ getWikiPage(owner, repository, page), getRepository(owner, repository, servletContext).get) }) - post("/:owner/:repository/wiki/_edit", editForm)(collaboratorsOnly { form => + post("/:owner/:repository/wiki/_edit", editForm)(writableRepository { form => val owner = params("owner") val repository = params("repository") @@ -102,14 +102,14 @@ redirect("%s/%s/wiki/%s".format(owner, repository, form.pageName)) }) - get("/:owner/:repository/wiki/_new")(collaboratorsOnly { + get("/:owner/:repository/wiki/_new")(writableRepository { val owner = params("owner") val repository = params("repository") wiki.html.wikiedit("", None, getRepository(owner, repository, servletContext).get) }) - post("/:owner/:repository/wiki/_new", newForm)(collaboratorsOnly { form => + post("/:owner/:repository/wiki/_new", newForm)(writableRepository { form => val owner = params("owner") val repository = params("repository") @@ -119,7 +119,7 @@ redirect("%s/%s/wiki/%s".format(owner, repository, form.pageName)) }) - get("/:owner/:repository/wiki/:page/_delete")(collaboratorsOnly { + get("/:owner/:repository/wiki/:page/_delete")(writableRepository { val owner = params("owner") val repository = params("repository") val page = params("page") @@ -129,14 +129,14 @@ redirect("%s/%s/wiki".format(owner, repository)) }) - get("/:owner/:repository/wiki/_pages"){ + get("/:owner/:repository/wiki/_pages")(readableRepository { val owner = params("owner") val repository = params("repository") wiki.html.wikipages(getWikiPageList(owner, repository), getRepository(owner, repository, servletContext).get, isWritable(owner, repository)) - } + }) - get("/:owner/:repository/wiki/_history"){ + get("/:owner/:repository/wiki/_history")(readableRepository { val owner = params("owner") val repository = params("repository") @@ -144,15 +144,15 @@ wiki.html.wikihistory(None, JGitUtil.getCommitLog(git, "master")._1, getRepository(owner, repository, servletContext).get) } - } + }) - post("/:owner/:repository/wiki/_preview"){ + post("/:owner/:repository/wiki/_preview")(writableRepository { val owner = params("owner") val repository = params("repository") val content = params("content") contentType = "text/html" view.helpers.markdown(content, getRepository(owner, repository, servletContext).get, true) - } + }) /** * Constraint for the wiki page name. diff --git a/src/main/scala/util/Authenticator.scala b/src/main/scala/util/Authenticator.scala index e2749bf..2696869 100644 --- a/src/main/scala/util/Authenticator.scala +++ b/src/main/scala/util/Authenticator.scala @@ -8,7 +8,10 @@ */ trait OwnerOnlyAuthenticator { self: ControllerBase => - protected def ownerOnly(action: => Any) = { + protected def ownerOnly(action: => Any) = { authenticate(action) } + protected def ownerOnly[T](action: T => Any) = (form: T) => authenticate({action(form)}) + + private def authenticate(action: => Any) = { { context.loginAccount match { case Some(x) if(x.userType == AccountService.Administrator) => action @@ -17,16 +20,6 @@ } } } - - protected def ownerOnly[T](action: T => Any) = { - (form: T) => { - context.loginAccount match { - case Some(x) if(x.userType == AccountService.Administrator) => action(form) - case Some(x) if(request.getRequestURI.split("/")(1) == x.userName) => action(form) - case _ => redirect("/signin") - } - } - } } /** @@ -34,7 +27,10 @@ */ trait UsersOnlyAuthenticator { self: ControllerBase => - protected def usersOnly(action: => Any) = { + protected def usersOnly(action: => Any) = { authenticate(action) } + protected def usersOnly[T](action: T => Any) = (form: T) => authenticate({action(form)}) + + private def authenticate(action: => Any) = { { context.loginAccount match { case Some(x) => action @@ -42,12 +38,21 @@ } } } +} - protected def usersOnly[T](action: T => Any) = { - (form: T) => { +/** + * Allows only administrators. + */ +trait AdminOnlyAuthenticator { self: ControllerBase => + + protected def adminOnly(action: => Any) = { authenticate(action) } + protected def adminOnly[T](action: T => Any) = (form: T) => authenticate({action(form)}) + + private def authenticate(action: => Any) = { + { context.loginAccount match { - case Some(x) => action(form) - case None => redirect("/signin") + case Some(x) if(x.userType == AccountService.Administrator) => action + case _ => redirect("/signin") } } } @@ -56,41 +61,44 @@ /** * Allows only collaborators and administrators. */ -trait CollaboratorsOnlyAuthenticator { self: ControllerBase with RepositoryService => +trait WritableRepositoryAuthenticator { self: ControllerBase with RepositoryService => - protected def collaboratorsOnly(action: => Any) = { - { + protected def writableRepository(action: => Any) = { authenticate(action) } + protected def writableRepository[T](action: T => Any) = (form: T) => authenticate({action(form)}) + + private def authenticate(action: => Any) = { + val paths = request.getRequestURI.split("/") context.loginAccount match { case Some(x) if(x.userType == AccountService.Administrator) => action - case Some(x) if(request.getRequestURI.split("/")(1) == x.userName) => action - case Some(x) => { - val paths = request.getRequestURI.split("/") - if(getCollaborators(paths(1), paths(2)).contains(x.userName)){ - action - } else { - redirect("/signin") - } - } - case None => redirect("/signin") + case Some(x) if(paths(1) == x.userName) => action + case Some(x) if(getCollaborators(paths(1), paths(2)).contains(x.userName)) => action + case _ => redirect("/signin") } - } } +} - protected def collaboratorsOnly[T](action: T => Any) = { - (form: T) => { - context.loginAccount match { - case Some(x) if(x.userType == AccountService.Administrator) => action(form) - case Some(x) if(request.getRequestURI.split("/")(1) == x.userName) => action(form) - case Some(x) => { - val paths = request.getRequestURI.split("/") - if(getCollaborators(paths(1), paths(2)).contains(x.userName)){ - action(form) - } else { - redirect("/signin") - } +/** + * Allows only the repository owner and administrators. + */ +trait ReadableRepositoryAuthenticator { self: ControllerBase with RepositoryService => + + protected def readableRepository(action: => Any) = { authenticate(action) } + protected def readableRepository[T](action: T => Any) = (form: T) => authenticate({action(form)}) + + private def authenticate(action: => Any) = { + { + val paths = request.getRequestURI.split("/") + val repository = getRepository(paths(1), paths(2), servletContext) + if(repository.get.repository.repositoryType == RepositoryService.Public){ + action + } else { + context.loginAccount match { + case Some(x) if(x.userType == AccountService.Administrator) => action + case Some(x) if(paths(1) == x.userName) => action + case Some(x) if(getCollaborators(paths(1), paths(2)).contains(x.userName)) => action + case _ => redirect("/") } - case None => redirect("/signin") } } } -} \ No newline at end of file +}