diff --git a/src/main/scala/app/WikiController.scala b/src/main/scala/app/WikiController.scala index bf88879..7fcd705 100644 --- a/src/main/scala/app/WikiController.scala +++ b/src/main/scala/app/WikiController.scala @@ -6,12 +6,14 @@ import util.ControlUtil._ import jp.sf.amateras.scalatra.forms._ import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.errors.PatchApplyException +import org.scalatra.FlashMapSupport class WikiController extends WikiControllerBase with WikiService with RepositoryService with AccountService with ActivityService with CollaboratorsAuthenticator with ReferrerAuthenticator -trait WikiControllerBase extends ControllerBase { +trait WikiControllerBase extends ControllerBase with FlashMapSupport { self: WikiService with RepositoryService with ActivityService with CollaboratorsAuthenticator with ReferrerAuthenticator => @@ -58,21 +60,48 @@ get("/:owner/:repository/wiki/:page/_compare/:commitId")(referrersOnly { repository => val pageName = StringUtil.urlDecode(params("page")) - val commitId = params("commitId").split("\\.\\.\\.") - using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git => - wiki.html.compare(Some(pageName), JGitUtil.getDiffs(git, commitId(0), commitId(1), true), repository) + defining(params("commitId").split("\\.\\.\\.")){ case Array(from, to) => + using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git => + wiki.html.compare(Some(pageName), from, to, JGitUtil.getDiffs(git, from, to, true), repository, + hasWritePermission(repository.owner, repository.name, context.loginAccount), flash.get("info")) + } } }) get("/:owner/:repository/wiki/_compare/:commitId")(referrersOnly { repository => - val commitId = params("commitId").split("\\.\\.\\.") - - using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git => - wiki.html.compare(None, JGitUtil.getDiffs(git, commitId(0), commitId(1), true), repository) + defining(params("commitId").split("\\.\\.\\.")){ case Array(from, to) => + using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git => + wiki.html.compare(None, from, to, JGitUtil.getDiffs(git, from, to, true), repository, + hasWritePermission(repository.owner, repository.name, context.loginAccount), flash.get("info")) + } } }) - + + get("/:owner/:repository/wiki/:page/_revert/:commitId")(collaboratorsOnly { repository => + val pageName = StringUtil.urlDecode(params("page")) + + defining(params("commitId").split("\\.\\.\\.")){ case Array(from, to) => + if(revertWikiPage(repository.owner, repository.name, from, to, context.loginAccount.get, Some(pageName))){ + redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}") + } else { + flash += "info" -> "This patch was not able to be reversed." + redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_compare/${from}...${to}") + } + } + }) + + get("/:owner/:repository/wiki/_revert/:commitId")(collaboratorsOnly { repository => + defining(params("commitId").split("\\.\\.\\.")){ case Array(from, to) => + if(revertWikiPage(repository.owner, repository.name, from, to, context.loginAccount.get, None)){ + redirect(s"/${repository.owner}/${repository.name}/wiki/}") + } else { + flash += "info" -> "This patch was not able to be reversed." + redirect(s"/${repository.owner}/${repository.name}/wiki/_compare/${from}...${to}") + } + } + }) + get("/:owner/:repository/wiki/:page/_edit")(collaboratorsOnly { repository => val pageName = StringUtil.urlDecode(params("page")) wiki.html.edit(pageName, getWikiPage(repository.owner, repository.name, pageName), repository) diff --git a/src/main/scala/service/WikiService.scala b/src/main/scala/service/WikiService.scala index 774cfc7..f495aea 100644 --- a/src/main/scala/service/WikiService.scala +++ b/src/main/scala/service/WikiService.scala @@ -4,8 +4,11 @@ import java.util.Date import org.eclipse.jgit.api.Git import org.apache.commons.io.FileUtils -import util.{Directory, JGitUtil, LockUtil} +import util.{StringUtil, Directory, JGitUtil, LockUtil} import util.ControlUtil._ +import org.eclipse.jgit.treewalk.CanonicalTreeParser +import org.eclipse.jgit.diff.DiffFormatter +import org.eclipse.jgit.api.errors.PatchApplyException object WikiService { @@ -89,7 +92,53 @@ .sortBy(x => x) } } - + + /** + * Reverts specified changes. + */ + def revertWikiPage(owner: String, repository: String, from: String, to: String, + committer: model.Account, pageName: Option[String]): Boolean = { + LockUtil.lock(s"${owner}/${repository}/wiki"){ + using(Git.open(Directory.getWikiWorkDir(owner, repository))){ git => + val reader = git.getRepository.newObjectReader + val oldTreeIter = new CanonicalTreeParser + oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}")) + + val newTreeIter = new CanonicalTreeParser + newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}")) + + import scala.collection.JavaConverters._ + val diffs = git.diff.setNewTree(oldTreeIter).setOldTree(newTreeIter).call.asScala.filter { diff => + pageName match { + case Some(x) => diff.getNewPath == x + ".md" + case None => true + } + } + + val patch = using(new java.io.ByteArrayOutputStream()){ out => + val formatter = new DiffFormatter(out) + formatter.setRepository(git.getRepository) + formatter.format(diffs.asJava) + new String(out.toByteArray, "UTF-8") + } + + try { + git.apply.setPatch(new java.io.ByteArrayInputStream(patch.getBytes("UTF-8"))).call + git.add.addFilepattern(".").call + git.commit.setCommitter(committer.userName, committer.mailAddress).setMessage(pageName match { + case Some(x) => s"Revert ${from} ... ${to} on ${x}" + case None => s"Revert ${from} ... ${to}" + }).call + git.push.call + true + } catch { + case ex: PatchApplyException => false + } + } + } + } + + /** * Save the wiki page. */ diff --git a/src/main/twirl/wiki/compare.scala.html b/src/main/twirl/wiki/compare.scala.html index f03cdfb..2e52027 100644 --- a/src/main/twirl/wiki/compare.scala.html +++ b/src/main/twirl/wiki/compare.scala.html @@ -1,10 +1,15 @@ @(pageName: Option[String], + from: String, + to: String, diffs: Seq[util.JGitUtil.DiffInfo], - repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) + repository: service.RepositoryService.RepositoryInfo, + hasWritePermission: Boolean, + info: Option[Any])(implicit context: app.Context) @import context._ @import view.helpers._ @import org.eclipse.jgit.diff.DiffEntry.ChangeType @html.main(s"Compare Revisions - ${repository.owner}/${repository.name}", Some(repository)){ + @helper.html.information(info) @html.header("wiki", repository) @tab("history", repository)
@helper.html.diff(diffs, repository, None, None, false) + @if(hasWritePermission){ +