diff --git a/src/main/scala/gitbucket/core/api/JsonFormat.scala b/src/main/scala/gitbucket/core/api/JsonFormat.scala index fe9e3e5..bd9c3bf 100644 --- a/src/main/scala/gitbucket/core/api/JsonFormat.scala +++ b/src/main/scala/gitbucket/core/api/JsonFormat.scala @@ -5,40 +5,48 @@ import org.joda.time.format._ import org.json4s._ import org.json4s.jackson.Serialization - import java.util.Date - import scala.util.Try - object JsonFormat { - case class Context(baseUrl:String) + + case class Context(baseUrl: String) + val parserISO = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'") + val jsonFormats = Serialization.formats(NoTypeHints) + new CustomSerializer[Date](format => ( - { case JString(s) => Try(parserISO.parseDateTime(s)).toOption.map(_.toDate) - .getOrElse(throw new MappingException("Can't convert " + s + " to Date")) }, + { case JString(s) => Try(parserISO.parseDateTime(s)).toOption.map(_.toDate).getOrElse(throw new MappingException("Can't convert " + s + " to Date")) }, { case x: Date => JString(parserISO.print(new DateTime(x).withZone(DateTimeZone.UTC))) } ) - ) + FieldSerializer[ApiUser]() + FieldSerializer[ApiPullRequest]() + FieldSerializer[ApiRepository]() + - FieldSerializer[ApiCommitListItem.Parent]() + FieldSerializer[ApiCommitListItem]() + FieldSerializer[ApiCommitListItem.Commit]() + - FieldSerializer[ApiCommitStatus]() + FieldSerializer[FieldSerializable]() + FieldSerializer[ApiCombinedCommitStatus]() + - FieldSerializer[ApiPullRequest.Commit]() + FieldSerializer[ApiIssue]() + FieldSerializer[ApiComment]() - + ) + FieldSerializer[ApiUser]() + + FieldSerializer[ApiPullRequest]() + + FieldSerializer[ApiRepository]() + + FieldSerializer[ApiCommitListItem.Parent]() + + FieldSerializer[ApiCommitListItem]() + + FieldSerializer[ApiCommitListItem.Commit]() + + FieldSerializer[ApiCommitStatus]() + + FieldSerializer[FieldSerializable]() + + FieldSerializer[ApiCombinedCommitStatus]() + + FieldSerializer[ApiPullRequest.Commit]() + + FieldSerializer[ApiIssue]() + + FieldSerializer[ApiComment]() def apiPathSerializer(c: Context) = new CustomSerializer[ApiPath](format => - ( - { - case JString(s) if s.startsWith(c.baseUrl) => ApiPath(s.substring(c.baseUrl.length)) - case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath") - }, - { - case ApiPath(path) => JString(c.baseUrl+path) - } - ) + ( + { + case JString(s) if s.startsWith(c.baseUrl) => ApiPath(s.substring(c.baseUrl.length)) + case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath") + }, + { + case ApiPath(path) => JString(c.baseUrl + path) + } ) + ) + /** * convert object to json string */ def apply(obj: AnyRef)(implicit c: Context): String = Serialization.write(obj)(jsonFormats + apiPathSerializer(c)) + } diff --git a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala index 7476b72..6eea427 100644 --- a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala @@ -14,7 +14,6 @@ import org.scalatra.i18n.Messages import org.eclipse.jgit.api.Git import org.eclipse.jgit.lib.Constants -import scala.util.{Success, Failure} import org.eclipse.jgit.lib.ObjectId @@ -174,6 +173,8 @@ * Send the test request to registered web hook URLs. */ ajaxPost("/:owner/:repository/settings/hooks/test")(ownerOnly { repository => + def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] = h.map { h => Array(h.getName, h.getValue) } + using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git => import scala.collection.JavaConverters._ import scala.concurrent.duration._ @@ -183,6 +184,7 @@ import scala.concurrent.ExecutionContext.Implicits.global val url = params("url") + val dummyWebHookInfo = WebHook(repository.owner, repository.name, url) val dummyPayload = { val ownerAccount = getAccountByUserName(repository.owner).get val commits = if(repository.commitCount == 0) List.empty else git.log @@ -190,34 +192,41 @@ .setMaxCount(4) .call.iterator.asScala.map(new CommitInfo(_)).toList val pushedCommit = commits.drop(1) - WebHookPushPayload(git, ownerAccount, "refs/heads/" + repository.repository.defaultBranch, repository, pushedCommit, ownerAccount, - oldId = commits.lastOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId()), - newId = commits.headOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId())) + + WebHookPushPayload( + git = git, + sender = ownerAccount, + refName = "refs/heads/" + repository.repository.defaultBranch, + repositoryInfo = repository, + commits = pushedCommit, + repositoryOwner = ownerAccount, + oldId = commits.lastOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId()), + newId = commits.headOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId()) + ) } - val dummyWebHookInfo = WebHook(repository.owner, repository.name, url) val (webHook, json, reqFuture, resFuture) = callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload).head - def headers(h: Array[org.apache.http.Header]): Array[Array[String]] = h.map{ h => Array(h.getName, h.getValue) } - val toErrorMap:PartialFunction[Throwable, Map[String,String]] = { - case e:java.net.UnknownHostException => Map("error"-> ("Unknown host "+ e.getMessage)) - case e:java.lang.IllegalArgumentException => Map("error"-> ("invalid url")) - case e:org.apache.http.client.ClientProtocolException => Map("error"-> ("invalid url")) + val toErrorMap: PartialFunction[Throwable, Map[String,String]] = { + case e: java.net.UnknownHostException => Map("error"-> ("Unknown host " + e.getMessage)) + case e: java.lang.IllegalArgumentException => Map("error"-> ("invalid url")) + case e: org.apache.http.client.ClientProtocolException => Map("error"-> ("invalid url")) case NonFatal(e) => Map("error"-> (e.getClass + " "+ e.getMessage)) } + contentType = formats("json") - var result = Map( + org.json4s.jackson.Serialization.write(Map( "url" -> url, - "request" -> Await.result(reqFuture.map(req => Map( - "headers" -> headers(req.getAllHeaders), - "payload" -> json + "request" -> Await.result(reqFuture.map(req => Map( + "headers" -> _headers(req.getAllHeaders), + "payload" -> json )).recover(toErrorMap), 20 seconds), "responce" -> Await.result(resFuture.map(res => Map( - "status" -> res.getStatusLine(), - "body" -> EntityUtils.toString(res.getEntity()), - "headers" -> headers(res.getAllHeaders()) - )).recover(toErrorMap), 20 seconds)) - org.json4s.jackson.Serialization.write(result) + "status" -> res.getStatusLine(), + "body" -> EntityUtils.toString(res.getEntity()), + "headers" -> _headers(res.getAllHeaders()) + )).recover(toErrorMap), 20 seconds) + )) } }) diff --git a/src/main/scala/gitbucket/core/service/WebHookService.scala b/src/main/scala/gitbucket/core/service/WebHookService.scala index 058d2ba..059ca5d 100644 --- a/src/main/scala/gitbucket/core/service/WebHookService.scala +++ b/src/main/scala/gitbucket/core/service/WebHookService.scala @@ -61,14 +61,16 @@ def deleteWebHook(owner: String, repository: String, url :String)(implicit s: Session): Unit = WebHooks.filter(_.byPrimaryKey(owner, repository, url)).delete - def callWebHookOf(owner: String, repository: String, event: WebHook.Event)(makePayload: => Option[WebHookPayload])(implicit s: Session, c: JsonFormat.Context): Unit = { + def callWebHookOf(owner: String, repository: String, event: WebHook.Event)(makePayload: => Option[WebHookPayload]) + (implicit s: Session, c: JsonFormat.Context): Unit = { val webHooks = getWebHooksByEvent(owner, repository, event) if(webHooks.nonEmpty){ makePayload.map(callWebHook(event, webHooks, _)) } } - def callWebHook(event: WebHook.Event, webHookURLs: List[WebHook], payload: WebHookPayload)(implicit c: JsonFormat.Context): List[(WebHook, String, Future[HttpRequest], Future[HttpResponse])] = { + def callWebHook(event: WebHook.Event, webHookURLs: List[WebHook], payload: WebHookPayload) + (implicit c: JsonFormat.Context): List[(WebHook, String, Future[HttpRequest], Future[HttpResponse])] = { import org.apache.http.impl.client.HttpClientBuilder import ExecutionContext.Implicits.global import org.apache.http.protocol.HttpContext @@ -131,7 +133,8 @@ import WebHookService._ // https://developer.github.com/v3/activity/events/types/#issuesevent - def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: Account)(implicit s: Session, context:JsonFormat.Context): Unit = { + def callIssuesWebHook(action: String, repository: RepositoryService.RepositoryInfo, issue: Issue, baseUrl: String, sender: Account) + (implicit s: Session, context:JsonFormat.Context): Unit = { callWebHookOf(repository.owner, repository.name, WebHook.Issues){ val users = getAccountsByUserNames(Set(repository.owner, issue.openedUserName), Set(sender)) for{ @@ -148,7 +151,8 @@ } } - def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account)(implicit s: Session, context:JsonFormat.Context): Unit = { + def callPullRequestWebHook(action: String, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account) + (implicit s: Session, context:JsonFormat.Context): Unit = { import WebHookService._ callWebHookOf(repository.owner, repository.name, WebHook.PullRequest){ for{ @@ -191,7 +195,8 @@ ((is, iu, pr, bu, ru), wh) }).list.groupBy(_._1).mapValues(_.map(_._2)) - def callPullRequestWebHookByRequestBranch(action: String, requestRepository: RepositoryService.RepositoryInfo, requestBranch: String, baseUrl: String, sender: Account)(implicit s: Session, context:JsonFormat.Context): Unit = { + def callPullRequestWebHookByRequestBranch(action: String, requestRepository: RepositoryService.RepositoryInfo, requestBranch: String, baseUrl: String, sender: Account) + (implicit s: Session, context:JsonFormat.Context): Unit = { import WebHookService._ for{ ((issue, issueUser, pullRequest, baseOwner, headOwner), webHooks) <- getPullRequestsByRequestForWebhook(requestRepository.owner, requestRepository.name, requestBranch) @@ -214,7 +219,8 @@ trait WebHookPullRequestReviewCommentService extends WebHookService { self: AccountService with RepositoryService with PullRequestService with IssuesService with CommitsService => - def callPullRequestReviewCommentWebHook(action: String, comment: CommitComment, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account)(implicit s: Session, context:JsonFormat.Context): Unit = { + def callPullRequestReviewCommentWebHook(action: String, comment: CommitComment, repository: RepositoryService.RepositoryInfo, issueId: Int, baseUrl: String, sender: Account) + (implicit s: Session, context:JsonFormat.Context): Unit = { import WebHookService._ callWebHookOf(repository.owner, repository.name, WebHook.PullRequestReviewComment){ for{ @@ -245,7 +251,8 @@ self: AccountService with RepositoryService with PullRequestService with IssuesService => import WebHookService._ - def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: Account)(implicit s: Session, context:JsonFormat.Context): Unit = { + def callIssueCommentWebHook(repository: RepositoryService.RepositoryInfo, issue: Issue, issueCommentId: Int, sender: Account) + (implicit s: Session, context:JsonFormat.Context): Unit = { callWebHookOf(repository.owner, repository.name, WebHook.IssueComment){ for{ issueComment <- getComment(repository.owner, repository.name, issueCommentId.toString())