mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-06 21:45:50 +01:00
Merge pull request #1488 from kounoike/pr-add-account-webhook
Add account(group/user)'s webhooks feature.
This commit is contained in:
@@ -11,4 +11,22 @@
|
|||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_DEPLOY_KEY_PK" tableName="DEPLOY_KEY" columnNames="USER_NAME, REPOSITORY_NAME, DEPLOY_KEY_ID"/>
|
<addPrimaryKey constraintName="IDX_DEPLOY_KEY_PK" tableName="DEPLOY_KEY" columnNames="USER_NAME, REPOSITORY_NAME, DEPLOY_KEY_ID"/>
|
||||||
<addForeignKeyConstraint constraintName="IDX_DEPLOY_KEY_FK0" baseTableName="DEPLOY_KEY" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
<addForeignKeyConstraint constraintName="IDX_DEPLOY_KEY_FK0" baseTableName="DEPLOY_KEY" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||||
|
|
||||||
|
<createTable tableName="ACCOUNT_WEB_HOOK">
|
||||||
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
|
<column name="URL" type="varchar(200)" nullable="false"/>
|
||||||
|
<column name="TOKEN" type="varchar(100)" nullable="true"/>
|
||||||
|
<column name="CTYPE" type="varchar(10)" nullable="true"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addPrimaryKey constraintName="IDX_ACCOUNT_WEB_HOOK_PK" tableName="ACCOUNT_WEB_HOOK" columnNames="USER_NAME, URL"/>
|
||||||
|
<addForeignKeyConstraint constraintName="IDX_ACCOUNT_WEB_HOOK_FK0" baseTableName="ACCOUNT_WEB_HOOK" baseColumnNames="USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME"/>
|
||||||
|
|
||||||
|
<createTable tableName="ACCOUNT_WEB_HOOK_EVENT">
|
||||||
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
|
<column name="URL" type="varchar(200)" nullable="false"/>
|
||||||
|
<column name="EVENT" type="varchar(30)" nullable="false"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|||||||
@@ -53,4 +53,14 @@ object ApiRepository{
|
|||||||
def forPushPayload(repositoryInfo: RepositoryInfo, owner: ApiUser): ApiRepository =
|
def forPushPayload(repositoryInfo: RepositoryInfo, owner: ApiUser): ApiRepository =
|
||||||
ApiRepository(repositoryInfo.repository, owner, forkedCount=repositoryInfo.forkedCount, urlIsHtmlUrl=true)
|
ApiRepository(repositoryInfo.repository, owner, forkedCount=repositoryInfo.forkedCount, urlIsHtmlUrl=true)
|
||||||
|
|
||||||
|
def forDummyPayload(owner: ApiUser): ApiRepository =
|
||||||
|
ApiRepository(
|
||||||
|
name="dummy",
|
||||||
|
full_name=s"${owner.login}/dummy",
|
||||||
|
description="",
|
||||||
|
watchers=0,
|
||||||
|
forks=0,
|
||||||
|
`private`=false,
|
||||||
|
default_branch="master",
|
||||||
|
owner=owner)(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ package gitbucket.core.controller
|
|||||||
|
|
||||||
import gitbucket.core.account.html
|
import gitbucket.core.account.html
|
||||||
import gitbucket.core.helper
|
import gitbucket.core.helper
|
||||||
import gitbucket.core.model.{GroupMember, Role}
|
import gitbucket.core.model.{GroupMember, Role, WebHook, WebHookContentType, AccountWebHook, RepositoryWebHook, RepositoryWebHookEvent}
|
||||||
import gitbucket.core.plugin.PluginRegistry
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
import gitbucket.core.service._
|
import gitbucket.core.service._
|
||||||
|
import gitbucket.core.service.WebHookService._
|
||||||
import gitbucket.core.ssh.SshUtil
|
import gitbucket.core.ssh.SshUtil
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
@@ -16,7 +17,6 @@ import org.apache.commons.io.FileUtils
|
|||||||
import org.scalatra.i18n.Messages
|
import org.scalatra.i18n.Messages
|
||||||
import org.scalatra.BadRequest
|
import org.scalatra.BadRequest
|
||||||
|
|
||||||
|
|
||||||
class AccountController extends AccountControllerBase
|
class AccountController extends AccountControllerBase
|
||||||
with AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService
|
with AccountService with RepositoryService with ActivityService with WikiService with LabelsService with SshKeyService
|
||||||
with OneselfAuthenticator with UsersAuthenticator with GroupManagerAuthenticator with ReadableUsersAuthenticator
|
with OneselfAuthenticator with UsersAuthenticator with GroupManagerAuthenticator with ReadableUsersAuthenticator
|
||||||
@@ -109,6 +109,47 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
"account" -> trim(label("Group/User name", text(required, validAccountName)))
|
"account" -> trim(label("Group/User name", text(required, validAccountName)))
|
||||||
)(AccountForm.apply)
|
)(AccountForm.apply)
|
||||||
|
|
||||||
|
// for account web hook url addition.
|
||||||
|
case class AccountWebHookForm(url: String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])
|
||||||
|
|
||||||
|
def accountWebHookForm(update:Boolean) = mapping(
|
||||||
|
"url" -> trim(label("url", text(required, accountWebHook(update)))),
|
||||||
|
"events" -> accountWebhookEvents,
|
||||||
|
"ctype" -> label("ctype", text()),
|
||||||
|
"token" -> optional(trim(label("token", text(maxlength(100)))))
|
||||||
|
)(
|
||||||
|
(url, events, ctype, token) => AccountWebHookForm(url, events, WebHookContentType.valueOf(ctype), token)
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* Provides duplication check for web hook url. duplicated from RepositorySettingsController.scala
|
||||||
|
*/
|
||||||
|
private def accountWebHook(needExists: Boolean): Constraint = new Constraint(){
|
||||||
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||||
|
if(getAccountWebHook(params("userName"), value).isDefined != needExists){
|
||||||
|
Some(if(needExists){
|
||||||
|
"URL had not been registered yet."
|
||||||
|
} else {
|
||||||
|
"URL had been registered already."
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def accountWebhookEvents = new ValueType[Set[WebHook.Event]]{
|
||||||
|
def convert(name: String, params: Map[String, String], messages: Messages): Set[WebHook.Event] = {
|
||||||
|
WebHook.Event.values.flatMap { t =>
|
||||||
|
params.get(name + "." + t.name).map(_ => t)
|
||||||
|
}.toSet
|
||||||
|
}
|
||||||
|
def validate(name: String, params: Map[String, String], messages: Messages): Seq[(String, String)] = if(convert(name,params,messages).isEmpty){
|
||||||
|
Seq(name -> messages("error.required").format(name))
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays user information.
|
* Displays user information.
|
||||||
*/
|
*/
|
||||||
@@ -129,6 +170,13 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
context.loginAccount.exists(x => members.exists { member => member.userName == x.userName && member.isManager }))
|
context.loginAccount.exists(x => members.exists { member => member.userName == x.userName && member.isManager }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Webhooks
|
||||||
|
case "webhooks" =>
|
||||||
|
gitbucket.core.account.html.webhook(account,
|
||||||
|
if(account.isGroupAccount) Nil else getGroupsByUserName(userName),
|
||||||
|
getAccountWebHooks(account.userName)
|
||||||
|
)
|
||||||
|
|
||||||
// Repositories
|
// Repositories
|
||||||
case _ => {
|
case _ => {
|
||||||
val members = getGroupMembers(account.userName)
|
val members = getGroupMembers(account.userName)
|
||||||
@@ -273,6 +321,106 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
redirect(s"/${userName}/_application")
|
redirect(s"/${userName}/_application")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the account web hook edit page.
|
||||||
|
*/
|
||||||
|
get("/:userName/_hooks/new")(oneselfOnly {
|
||||||
|
val userName = params("userName")
|
||||||
|
getAccountByUserName(userName).map { account =>
|
||||||
|
val webhook = AccountWebHook(userName, "", WebHookContentType.FORM, None)
|
||||||
|
html.edithooks(webhook, Set(WebHook.Push), account, if (account.isGroupAccount) Nil else getGroupsByUserName(userName), flash.get("info"), true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the account web hook URL.
|
||||||
|
*/
|
||||||
|
post("/:userName/_hooks/new", accountWebHookForm(false))(oneselfOnly { form =>
|
||||||
|
val userName = params("userName")
|
||||||
|
addAccountWebHook(userName, form.url, form.events, form.ctype, form.token)
|
||||||
|
flash += "info" -> s"Webhook ${form.url} created"
|
||||||
|
redirect(s"/${userName}?tab=webhooks")
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the account web hook URL.
|
||||||
|
*/
|
||||||
|
get("/:userName/_hooks/delete")(oneselfOnly {
|
||||||
|
val userName = params("userName")
|
||||||
|
deleteAccountWebHook(userName, params("url"))
|
||||||
|
flash += "info" -> s"Webhook ${params("url")} deleted"
|
||||||
|
redirect(s"/${userName}?tab=webhooks")
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the account web hook edit page.
|
||||||
|
*/
|
||||||
|
get("/:userName/_hooks/edit")(oneselfOnly {
|
||||||
|
val userName = params("userName")
|
||||||
|
getAccountByUserName(userName).map { account =>
|
||||||
|
getAccountWebHook(userName, params("url")).map { case (webhook, events) =>
|
||||||
|
html.edithooks(webhook, events, account, if (account.isGroupAccount) Nil else getGroupsByUserName(userName), flash.get("info"), false)
|
||||||
|
} getOrElse NotFound()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update account web hook settings.
|
||||||
|
*/
|
||||||
|
post("/:userName/_hooks/edit", accountWebHookForm(true))(oneselfOnly { form =>
|
||||||
|
val userName = params("userName")
|
||||||
|
updateAccountWebHook(userName, form.url, form.events, form.ctype, form.token)
|
||||||
|
flash += "info" -> s"webhook ${form.url} updated"
|
||||||
|
redirect(s"/${userName}?tab=webhooks")
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the test request to registered account web hook URLs.
|
||||||
|
*/
|
||||||
|
ajaxPost("/:userName/_hooks/test")(oneselfOnly {
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import scala.concurrent._
|
||||||
|
import scala.util.control.NonFatal
|
||||||
|
import org.apache.http.util.EntityUtils
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
|
||||||
|
def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] = h.map { h => Array(h.getName, h.getValue) }
|
||||||
|
|
||||||
|
val userName = params("userName")
|
||||||
|
val url = params("url")
|
||||||
|
val token = Some(params("token"))
|
||||||
|
val ctype = WebHookContentType.valueOf(params("ctype"))
|
||||||
|
val dummyWebHookInfo = RepositoryWebHook(userName, "dummy", url, ctype, token)
|
||||||
|
val dummyPayload = {
|
||||||
|
val ownerAccount = getAccountByUserName(userName).get
|
||||||
|
WebHookPushPayload.createDummyPayload(ownerAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
val (webHook, json, reqFuture, resFuture) = callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload).head
|
||||||
|
|
||||||
|
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")
|
||||||
|
org.json4s.jackson.Serialization.write(Map(
|
||||||
|
"url" -> url,
|
||||||
|
"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)
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
get("/register"){
|
get("/register"){
|
||||||
if(context.settings.allowAccountRegistration){
|
if(context.settings.allowAccountRegistration){
|
||||||
if(context.loginAccount.isDefined){
|
if(context.loginAccount.isDefined){
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package gitbucket.core.controller
|
package gitbucket.core.controller
|
||||||
|
|
||||||
import gitbucket.core.settings.html
|
import gitbucket.core.settings.html
|
||||||
import gitbucket.core.model.WebHook
|
import gitbucket.core.model.{WebHook, RepositoryWebHook}
|
||||||
import gitbucket.core.service._
|
import gitbucket.core.service._
|
||||||
import gitbucket.core.service.WebHookService._
|
import gitbucket.core.service.WebHookService._
|
||||||
import gitbucket.core.util._
|
import gitbucket.core.util._
|
||||||
@@ -221,7 +221,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
* Display the web hook edit page.
|
* Display the web hook edit page.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/settings/hooks/new")(ownerOnly { repository =>
|
get("/:owner/:repository/settings/hooks/new")(ownerOnly { repository =>
|
||||||
val webhook = WebHook(repository.owner, repository.name, "", WebHookContentType.FORM, None)
|
val webhook = RepositoryWebHook(repository.owner, repository.name, "", WebHookContentType.FORM, None)
|
||||||
html.edithooks(webhook, Set(WebHook.Push), repository, flash.get("info"), true)
|
html.edithooks(webhook, Set(WebHook.Push), repository, flash.get("info"), true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
val url = params("url")
|
val url = params("url")
|
||||||
val token = Some(params("token"))
|
val token = Some(params("token"))
|
||||||
val ctype = WebHookContentType.valueOf(params("ctype"))
|
val ctype = WebHookContentType.valueOf(params("ctype"))
|
||||||
val dummyWebHookInfo = WebHook(repository.owner, repository.name, url, ctype, token)
|
val dummyWebHookInfo = RepositoryWebHook(repository.owner, repository.name, url, ctype, token)
|
||||||
val dummyPayload = {
|
val dummyPayload = {
|
||||||
val ownerAccount = getAccountByUserName(repository.owner).get
|
val ownerAccount = getAccountByUserName(repository.owner).get
|
||||||
val commits = if(JGitUtil.isEmpty(git)) List.empty else git.log
|
val commits = if(JGitUtil.isEmpty(git)) List.empty else git.log
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package gitbucket.core.controller
|
package gitbucket.core.controller
|
||||||
|
|
||||||
import gitbucket.core.model.{WebHook, WebHookEvent}
|
import gitbucket.core.model.WebHook
|
||||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
import gitbucket.core.service.WebHookService.WebHookGollumPayload
|
import gitbucket.core.service.WebHookService.WebHookGollumPayload
|
||||||
import gitbucket.core.wiki.html
|
import gitbucket.core.wiki.html
|
||||||
|
|||||||
25
src/main/scala/gitbucket/core/model/AccountWebHook.scala
Normal file
25
src/main/scala/gitbucket/core/model/AccountWebHook.scala
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package gitbucket.core.model
|
||||||
|
|
||||||
|
trait AccountWebHookComponent extends TemplateComponent { self: Profile =>
|
||||||
|
import profile.api._
|
||||||
|
|
||||||
|
private implicit val whContentTypeColumnType = MappedColumnType.base[WebHookContentType, String](whct => whct.code , code => WebHookContentType.valueOf(code))
|
||||||
|
|
||||||
|
lazy val AccountWebHooks = TableQuery[AccountWebHooks]
|
||||||
|
|
||||||
|
class AccountWebHooks(tag: Tag) extends Table[AccountWebHook](tag, "ACCOUNT_WEB_HOOK") with BasicTemplate {
|
||||||
|
val url = column[String]("URL")
|
||||||
|
val token = column[Option[String]]("TOKEN")
|
||||||
|
val ctype = column[WebHookContentType]("CTYPE")
|
||||||
|
def * = (userName, url, ctype, token) <> ((AccountWebHook.apply _).tupled, AccountWebHook.unapply)
|
||||||
|
|
||||||
|
def byPrimaryKey(userName: String, url: String) = (this.userName === userName.bind) && (this.url === url.bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case class AccountWebHook(
|
||||||
|
userName: String,
|
||||||
|
url: String,
|
||||||
|
ctype: WebHookContentType,
|
||||||
|
token: Option[String]
|
||||||
|
) extends WebHook
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package gitbucket.core.model
|
||||||
|
|
||||||
|
trait AccountWebHookEventComponent extends TemplateComponent {
|
||||||
|
self: Profile =>
|
||||||
|
|
||||||
|
import profile.api._
|
||||||
|
import gitbucket.core.model.Profile.AccountWebHooks
|
||||||
|
|
||||||
|
lazy val AccountWebHookEvents = TableQuery[AccountWebHookEvents]
|
||||||
|
|
||||||
|
class AccountWebHookEvents(tag: Tag) extends Table[AccountWebHookEvent](tag, "ACCOUNT_WEB_HOOK_EVENT") with BasicTemplate {
|
||||||
|
val url = column[String]("URL")
|
||||||
|
val event = column[WebHook.Event]("EVENT")
|
||||||
|
|
||||||
|
def * = (userName, url, event) <> ((AccountWebHookEvent.apply _).tupled, AccountWebHookEvent.unapply)
|
||||||
|
|
||||||
|
def byAccountWebHook(userName: String, url: String) = (this.userName === userName.bind) && (this.url === url.bind)
|
||||||
|
|
||||||
|
def byAccountWebHook(owner: Rep[String], url: Rep[String]) =
|
||||||
|
(this.userName === userName) && (this.url === url)
|
||||||
|
|
||||||
|
def byAccountWebHook(webhook: AccountWebHooks) =
|
||||||
|
(this.userName === webhook.userName) && (this.url === webhook.url)
|
||||||
|
|
||||||
|
def byPrimaryKey(userName: String, url: String, event: WebHook.Event) =
|
||||||
|
(this.userName === userName.bind) && (this.url === url.bind) && (this.event === event.bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case class AccountWebHookEvent(
|
||||||
|
userName: String,
|
||||||
|
url: String,
|
||||||
|
event: WebHook.Event
|
||||||
|
)
|
||||||
@@ -7,6 +7,10 @@ protected[model] trait TemplateComponent { self: Profile =>
|
|||||||
val userName = column[String]("USER_NAME")
|
val userName = column[String]("USER_NAME")
|
||||||
val repositoryName = column[String]("REPOSITORY_NAME")
|
val repositoryName = column[String]("REPOSITORY_NAME")
|
||||||
|
|
||||||
|
def byAccount(userName: String) = (this.userName === userName.bind)
|
||||||
|
|
||||||
|
def byAccount(userName: Rep[String]) = (this.userName === userName)
|
||||||
|
|
||||||
def byRepository(owner: String, repository: String) =
|
def byRepository(owner: String, repository: String) =
|
||||||
(userName === owner.bind) && (repositoryName === repository.bind)
|
(userName === owner.bind) && (repositoryName === repository.bind)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ trait Profile {
|
|||||||
t => new java.util.Date(t.getTime)
|
t => new java.util.Date(t.getTime)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebHookBase.Event Column Types
|
||||||
|
*/
|
||||||
|
implicit val eventColumnType = MappedColumnType.base[WebHook.Event, String](_.name, WebHook.Event.valueOf(_))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends Column to add conditional condition
|
* Extends Column to add conditional condition
|
||||||
*/
|
*/
|
||||||
@@ -52,8 +57,10 @@ trait CoreProfile extends ProfileProvider with Profile
|
|||||||
with PullRequestComponent
|
with PullRequestComponent
|
||||||
with RepositoryComponent
|
with RepositoryComponent
|
||||||
with SshKeyComponent
|
with SshKeyComponent
|
||||||
with WebHookComponent
|
with RepositoryWebHookComponent
|
||||||
with WebHookEventComponent
|
with RepositoryWebHookEventComponent
|
||||||
|
with AccountWebHookComponent
|
||||||
|
with AccountWebHookEventComponent
|
||||||
with ProtectedBranchComponent
|
with ProtectedBranchComponent
|
||||||
with DeployKeyComponent
|
with DeployKeyComponent
|
||||||
|
|
||||||
|
|||||||
27
src/main/scala/gitbucket/core/model/RepositoryWebHook.scala
Normal file
27
src/main/scala/gitbucket/core/model/RepositoryWebHook.scala
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package gitbucket.core.model
|
||||||
|
|
||||||
|
trait RepositoryWebHookComponent extends TemplateComponent { self: Profile =>
|
||||||
|
import profile.api._
|
||||||
|
|
||||||
|
implicit val whContentTypeColumnType = MappedColumnType.base[WebHookContentType, String](whct => whct.code , code => WebHookContentType.valueOf(code))
|
||||||
|
|
||||||
|
lazy val RepositoryWebHooks = TableQuery[RepositoryWebHooks]
|
||||||
|
|
||||||
|
class RepositoryWebHooks(tag: Tag) extends Table[RepositoryWebHook](tag, "WEB_HOOK") with BasicTemplate {
|
||||||
|
val url = column[String]("URL")
|
||||||
|
val token = column[Option[String]]("TOKEN")
|
||||||
|
val ctype = column[WebHookContentType]("CTYPE")
|
||||||
|
def * = (userName, repositoryName, url, ctype, token) <> ((RepositoryWebHook.apply _).tupled, RepositoryWebHook.unapply)
|
||||||
|
|
||||||
|
def byPrimaryKey(owner: String, repository: String, url: String) = byRepository(owner, repository) && (this.url === url.bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case class RepositoryWebHook(
|
||||||
|
userName: String,
|
||||||
|
repositoryName: String,
|
||||||
|
url: String,
|
||||||
|
ctype: WebHookContentType,
|
||||||
|
token: Option[String]
|
||||||
|
) extends WebHook
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package gitbucket.core.model
|
||||||
|
|
||||||
|
trait RepositoryWebHookEventComponent extends TemplateComponent { self: Profile =>
|
||||||
|
import profile.api._
|
||||||
|
import gitbucket.core.model.Profile.RepositoryWebHooks
|
||||||
|
|
||||||
|
lazy val RepositoryWebHookEvents = TableQuery[RepositoryWebHookEvents]
|
||||||
|
|
||||||
|
class RepositoryWebHookEvents(tag: Tag) extends Table[RepositoryWebHookEvent](tag, "WEB_HOOK_EVENT") with BasicTemplate {
|
||||||
|
val url = column[String]("URL")
|
||||||
|
val event = column[WebHook.Event]("EVENT")
|
||||||
|
def * = (userName, repositoryName, url, event) <> ((RepositoryWebHookEvent.apply _).tupled, RepositoryWebHookEvent.unapply)
|
||||||
|
|
||||||
|
def byRepositoryWebHook(owner: String, repository: String, url: String) = byRepository(owner, repository) && (this.url === url.bind)
|
||||||
|
def byRepositoryWebHook(owner: Rep[String], repository: Rep[String], url: Rep[String]) =
|
||||||
|
byRepository(userName, repositoryName) && (this.url === url)
|
||||||
|
def byRepositoryWebHook(webhook: RepositoryWebHooks) =
|
||||||
|
byRepository(webhook.userName, webhook.repositoryName) && (this.url === webhook.url)
|
||||||
|
def byPrimaryKey(owner: String, repository: String, url: String, event: WebHook.Event) = byRepositoryWebHook(owner, repository, url) && (this.event === event.bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case class RepositoryWebHookEvent(
|
||||||
|
userName: String,
|
||||||
|
repositoryName: String,
|
||||||
|
url: String,
|
||||||
|
event: WebHook.Event
|
||||||
|
)
|
||||||
@@ -1,22 +1,5 @@
|
|||||||
package gitbucket.core.model
|
package gitbucket.core.model
|
||||||
|
|
||||||
trait WebHookComponent extends TemplateComponent { self: Profile =>
|
|
||||||
import profile.api._
|
|
||||||
|
|
||||||
implicit val whContentTypeColumnType = MappedColumnType.base[WebHookContentType, String](whct => whct.code , code => WebHookContentType.valueOf(code))
|
|
||||||
|
|
||||||
lazy val WebHooks = TableQuery[WebHooks]
|
|
||||||
|
|
||||||
class WebHooks(tag: Tag) extends Table[WebHook](tag, "WEB_HOOK") with BasicTemplate {
|
|
||||||
val url = column[String]("URL")
|
|
||||||
val token = column[Option[String]]("TOKEN")
|
|
||||||
val ctype = column[WebHookContentType]("CTYPE")
|
|
||||||
def * = (userName, repositoryName, url, ctype, token) <> ((WebHook.apply _).tupled, WebHook.unapply)
|
|
||||||
|
|
||||||
def byPrimaryKey(owner: String, repository: String, url: String) = byRepository(owner, repository) && (this.url === url.bind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract sealed case class WebHookContentType(code: String, ctype: String)
|
abstract sealed case class WebHookContentType(code: String, ctype: String)
|
||||||
|
|
||||||
object WebHookContentType {
|
object WebHookContentType {
|
||||||
@@ -33,13 +16,11 @@ object WebHookContentType {
|
|||||||
def valueOpt(code: String): Option[WebHookContentType] = map.get(code)
|
def valueOpt(code: String): Option[WebHookContentType] = map.get(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class WebHook(
|
trait WebHook{
|
||||||
userName: String,
|
val url: String
|
||||||
repositoryName: String,
|
val ctype: WebHookContentType
|
||||||
url: String,
|
val token: Option[String]
|
||||||
ctype: WebHookContentType,
|
}
|
||||||
token: Option[String]
|
|
||||||
)
|
|
||||||
|
|
||||||
object WebHook {
|
object WebHook {
|
||||||
abstract sealed class Event(val name: String)
|
abstract sealed class Event(val name: String)
|
||||||
@@ -86,6 +67,7 @@ object WebHook {
|
|||||||
TeamAdd,
|
TeamAdd,
|
||||||
Watch
|
Watch
|
||||||
)
|
)
|
||||||
|
|
||||||
private val map: Map[String,Event] = values.map(e => e.name -> e).toMap
|
private val map: Map[String,Event] = values.map(e => e.name -> e).toMap
|
||||||
def valueOf(name: String): Event = map(name)
|
def valueOf(name: String): Event = map(name)
|
||||||
def valueOpt(name: String): Option[Event] = map.get(name)
|
def valueOpt(name: String): Option[Event] = map.get(name)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package gitbucket.core.model
|
|
||||||
|
|
||||||
trait WebHookEventComponent extends TemplateComponent { self: Profile =>
|
|
||||||
import profile.api._
|
|
||||||
import gitbucket.core.model.Profile.WebHooks
|
|
||||||
|
|
||||||
lazy val WebHookEvents = TableQuery[WebHookEvents]
|
|
||||||
|
|
||||||
implicit val typedType = MappedColumnType.base[WebHook.Event, String](_.name, WebHook.Event.valueOf(_))
|
|
||||||
|
|
||||||
class WebHookEvents(tag: Tag) extends Table[WebHookEvent](tag, "WEB_HOOK_EVENT") with BasicTemplate {
|
|
||||||
val url = column[String]("URL")
|
|
||||||
val event = column[WebHook.Event]("EVENT")
|
|
||||||
def * = (userName, repositoryName, url, event) <> ((WebHookEvent.apply _).tupled, WebHookEvent.unapply)
|
|
||||||
|
|
||||||
def byWebHook(owner: String, repository: String, url: String) = byRepository(owner, repository) && (this.url === url.bind)
|
|
||||||
def byWebHook(owner: Rep[String], repository: Rep[String], url: Rep[String]) =
|
|
||||||
byRepository(userName, repositoryName) && (this.url === url)
|
|
||||||
def byWebHook(webhook: WebHooks) =
|
|
||||||
byRepository(webhook.userName, webhook.repositoryName) && (this.url === webhook.url)
|
|
||||||
def byPrimaryKey(owner: String, repository: String, url: String, event: WebHook.Event) = byWebHook(owner, repository, url) && (this.event === event.bind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class WebHookEvent(
|
|
||||||
userName: String,
|
|
||||||
repositoryName: String,
|
|
||||||
url: String,
|
|
||||||
event: WebHook.Event
|
|
||||||
)
|
|
||||||
@@ -59,8 +59,8 @@ trait RepositoryService { self: AccountService =>
|
|||||||
(Repositories filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository =>
|
(Repositories filter { t => t.byRepository(oldUserName, oldRepositoryName) } firstOption).map { repository =>
|
||||||
Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
|
Repositories insert repository.copy(userName = newUserName, repositoryName = newRepositoryName)
|
||||||
|
|
||||||
val webHooks = WebHooks .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val webHooks = RepositoryWebHooks .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
val webHookEvents = WebHookEvents .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val webHookEvents = RepositoryWebHookEvents .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
val milestones = Milestones .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val milestones = Milestones .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
val issueId = IssueId .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val issueId = IssueId .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
val issues = Issues .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
val issues = Issues .filter(_.byRepository(oldUserName, oldRepositoryName)).list
|
||||||
@@ -93,8 +93,8 @@ trait RepositoryService { self: AccountService =>
|
|||||||
|
|
||||||
deleteRepository(oldUserName, oldRepositoryName)
|
deleteRepository(oldUserName, oldRepositoryName)
|
||||||
|
|
||||||
WebHooks .insertAll(webHooks .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
RepositoryWebHooks .insertAll(webHooks .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
||||||
WebHookEvents.insertAll(webHookEvents .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
RepositoryWebHookEvents.insertAll(webHookEvents .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
||||||
Milestones .insertAll(milestones .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
Milestones .insertAll(milestones .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
||||||
Priorities .insertAll(priorities .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
Priorities .insertAll(priorities .map(_.copy(userName = newUserName, repositoryName = newRepositoryName)) :_*)
|
||||||
IssueId .insertAll(issueId .map(_.copy(_1 = newUserName, _2 = newRepositoryName)) :_*)
|
IssueId .insertAll(issueId .map(_.copy(_1 = newUserName, _2 = newRepositoryName)) :_*)
|
||||||
@@ -170,8 +170,8 @@ trait RepositoryService { self: AccountService =>
|
|||||||
Priorities .filter(_.byRepository(userName, repositoryName)).delete
|
Priorities .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
IssueId .filter(_.byRepository(userName, repositoryName)).delete
|
IssueId .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
Milestones .filter(_.byRepository(userName, repositoryName)).delete
|
Milestones .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
WebHooks .filter(_.byRepository(userName, repositoryName)).delete
|
RepositoryWebHooks .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
WebHookEvents .filter(_.byRepository(userName, repositoryName)).delete
|
RepositoryWebHookEvents .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
DeployKeys .filter(_.byRepository(userName, repositoryName)).delete
|
DeployKeys .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
Repositories .filter(_.byRepository(userName, repositoryName)).delete
|
Repositories .filter(_.byRepository(userName, repositoryName)).delete
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package gitbucket.core.service
|
|||||||
import fr.brouillard.oss.security.xhub.XHub
|
import fr.brouillard.oss.security.xhub.XHub
|
||||||
import fr.brouillard.oss.security.xhub.XHub.{XHubConverter, XHubDigest}
|
import fr.brouillard.oss.security.xhub.XHub.{XHubConverter, XHubDigest}
|
||||||
import gitbucket.core.api._
|
import gitbucket.core.api._
|
||||||
import gitbucket.core.model.{Account, CommitComment, Issue, IssueComment, PullRequest, WebHook, WebHookEvent}
|
import gitbucket.core.model.{Account, CommitComment, Issue, IssueComment, PullRequest, WebHook, RepositoryWebHook, RepositoryWebHookEvent, AccountWebHook, AccountWebHookEvent}
|
||||||
import gitbucket.core.model.Profile._
|
import gitbucket.core.model.Profile._
|
||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import org.apache.http.client.utils.URLEncodedUtils
|
import org.apache.http.client.utils.URLEncodedUtils
|
||||||
@@ -32,45 +32,86 @@ trait WebHookService {
|
|||||||
private val logger = LoggerFactory.getLogger(classOf[WebHookService])
|
private val logger = LoggerFactory.getLogger(classOf[WebHookService])
|
||||||
|
|
||||||
/** get All WebHook informations of repository */
|
/** get All WebHook informations of repository */
|
||||||
def getWebHooks(owner: String, repository: String)(implicit s: Session): List[(WebHook, Set[WebHook.Event])] =
|
def getWebHooks(owner: String, repository: String)(implicit s: Session): List[(RepositoryWebHook, Set[WebHook.Event])] =
|
||||||
WebHooks.filter(_.byRepository(owner, repository))
|
RepositoryWebHooks.filter(_.byRepository(owner, repository))
|
||||||
.join(WebHookEvents).on { (w, t) => t.byWebHook(w) }
|
.join(RepositoryWebHookEvents).on { (w, t) => t.byRepositoryWebHook(w) }
|
||||||
.map { case (w, t) => w -> t.event }
|
.map { case (w, t) => w -> t.event }
|
||||||
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).toList.sortBy(_._1.url)
|
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).toList.sortBy(_._1.url)
|
||||||
|
|
||||||
/** get All WebHook informations of repository event */
|
/** get All WebHook informations of repository event */
|
||||||
def getWebHooksByEvent(owner: String, repository: String, event: WebHook.Event)(implicit s: Session): List[WebHook] =
|
def getWebHooksByEvent(owner: String, repository: String, event: WebHook.Event)(implicit s: Session): List[RepositoryWebHook] =
|
||||||
WebHooks.filter(_.byRepository(owner, repository))
|
RepositoryWebHooks.filter(_.byRepository(owner, repository))
|
||||||
.join(WebHookEvents).on { (wh, whe) => whe.byWebHook(wh) }
|
.join(RepositoryWebHookEvents).on { (wh, whe) => whe.byRepositoryWebHook(wh) }
|
||||||
.filter { case (wh, whe) => whe.event === event.bind }
|
.filter { case (wh, whe) => whe.event === event.bind}
|
||||||
.map{ case (wh, whe) => wh }
|
.map{ case (wh, whe) => wh }
|
||||||
.list.distinct
|
.list.distinct
|
||||||
|
|
||||||
/** get All WebHook information from repository to url */
|
/** get All WebHook information from repository to url */
|
||||||
def getWebHook(owner: String, repository: String, url: String)(implicit s: Session): Option[(WebHook, Set[WebHook.Event])] =
|
def getWebHook(owner: String, repository: String, url: String)(implicit s: Session): Option[(RepositoryWebHook, Set[WebHook.Event])] =
|
||||||
WebHooks
|
RepositoryWebHooks
|
||||||
.filter(_.byPrimaryKey(owner, repository, url))
|
.filter(_.byPrimaryKey(owner, repository, url))
|
||||||
.join(WebHookEvents).on { (w, t) => t.byWebHook(w) }
|
.join(RepositoryWebHookEvents).on { (w, t) => t.byRepositoryWebHook(w) }
|
||||||
.map { case (w, t) => w -> t.event }
|
.map { case (w, t) => w -> t.event }
|
||||||
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).headOption
|
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).headOption
|
||||||
|
|
||||||
def addWebHook(owner: String, repository: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
def addWebHook(owner: String, repository: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
||||||
WebHooks insert WebHook(owner, repository, url, ctype, token)
|
RepositoryWebHooks insert RepositoryWebHook(owner, repository, url, ctype, token)
|
||||||
events.map { event: WebHook.Event =>
|
events.map { event: WebHook.Event =>
|
||||||
WebHookEvents insert WebHookEvent(owner, repository, url, event)
|
RepositoryWebHookEvents insert RepositoryWebHookEvent(owner, repository, url, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateWebHook(owner: String, repository: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
def updateWebHook(owner: String, repository: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
||||||
WebHooks.filter(_.byPrimaryKey(owner, repository, url)).map(w => (w.ctype, w.token)).update((ctype, token))
|
RepositoryWebHooks.filter(_.byPrimaryKey(owner, repository, url)).map(w => (w.ctype, w.token)).update((ctype, token))
|
||||||
WebHookEvents.filter(_.byWebHook(owner, repository, url)).delete
|
RepositoryWebHookEvents.filter(_.byRepositoryWebHook(owner, repository, url)).delete
|
||||||
events.map { event: WebHook.Event =>
|
events.map { event: WebHook.Event =>
|
||||||
WebHookEvents insert WebHookEvent(owner, repository, url, event)
|
RepositoryWebHookEvents insert RepositoryWebHookEvent(owner, repository, url, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteWebHook(owner: String, repository: String, url :String)(implicit s: Session): Unit =
|
def deleteWebHook(owner: String, repository: String, url :String)(implicit s: Session): Unit =
|
||||||
WebHooks.filter(_.byPrimaryKey(owner, repository, url)).delete
|
RepositoryWebHooks.filter(_.byPrimaryKey(owner, repository, url)).delete
|
||||||
|
|
||||||
|
/** get All AccountWebHook informations of user */
|
||||||
|
def getAccountWebHooks(owner: String)(implicit s: Session): List[(AccountWebHook, Set[WebHook.Event])] =
|
||||||
|
AccountWebHooks.filter(_.byAccount(owner))
|
||||||
|
.join(AccountWebHookEvents).on { (w, t) => t.byAccountWebHook(w) }
|
||||||
|
.map { case (w, t) => w -> t.event }
|
||||||
|
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).toList.sortBy(_._1.url)
|
||||||
|
|
||||||
|
/** get All AccountWebHook informations of repository event */
|
||||||
|
def getAccountWebHooksByEvent(owner: String, event: WebHook.Event)(implicit s: Session): List[AccountWebHook] =
|
||||||
|
AccountWebHooks.filter(_.byAccount(owner))
|
||||||
|
.join(AccountWebHookEvents).on { (wh, whe) => whe.byAccountWebHook(wh) }
|
||||||
|
.filter { case (wh, whe) => whe.event === event.bind}
|
||||||
|
.map{ case (wh, whe) => wh }
|
||||||
|
.list.distinct
|
||||||
|
|
||||||
|
/** get All AccountWebHook information from repository to url */
|
||||||
|
def getAccountWebHook(owner: String, url: String)(implicit s: Session): Option[(AccountWebHook, Set[WebHook.Event])] =
|
||||||
|
AccountWebHooks
|
||||||
|
.filter(_.byPrimaryKey(owner, url))
|
||||||
|
.join(AccountWebHookEvents).on { (w, t) => t.byAccountWebHook(w) }
|
||||||
|
.map { case (w, t) => w -> t.event }
|
||||||
|
.list.groupBy(_._1).mapValues(_.map(_._2).toSet).headOption
|
||||||
|
|
||||||
|
def addAccountWebHook(owner: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
||||||
|
AccountWebHooks insert AccountWebHook(owner, url, ctype, token)
|
||||||
|
events.map { event: WebHook.Event =>
|
||||||
|
AccountWebHookEvents insert AccountWebHookEvent(owner, url, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateAccountWebHook(owner: String, url :String, events: Set[WebHook.Event], ctype: WebHookContentType, token: Option[String])(implicit s: Session): Unit = {
|
||||||
|
AccountWebHooks.filter(_.byPrimaryKey(owner, url)).map(w => (w.ctype, w.token)).update((ctype, token))
|
||||||
|
AccountWebHookEvents.filter(_.byAccountWebHook(owner, url)).delete
|
||||||
|
events.map { event: WebHook.Event =>
|
||||||
|
AccountWebHookEvents insert AccountWebHookEvent(owner, url, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def deleteAccountWebHook(owner: String, url :String)(implicit s: Session): Unit =
|
||||||
|
AccountWebHooks.filter(_.byPrimaryKey(owner, url)).delete
|
||||||
|
|
||||||
def callWebHookOf(owner: String, repository: String, event: WebHook.Event)(makePayload: => Option[WebHookPayload])
|
def callWebHookOf(owner: String, repository: String, event: WebHook.Event)(makePayload: => Option[WebHookPayload])
|
||||||
(implicit s: Session, c: JsonFormat.Context): Unit = {
|
(implicit s: Session, c: JsonFormat.Context): Unit = {
|
||||||
@@ -78,6 +119,10 @@ trait WebHookService {
|
|||||||
if(webHooks.nonEmpty){
|
if(webHooks.nonEmpty){
|
||||||
makePayload.map(callWebHook(event, webHooks, _))
|
makePayload.map(callWebHook(event, webHooks, _))
|
||||||
}
|
}
|
||||||
|
val accountWebHooks = getAccountWebHooksByEvent(owner, event)
|
||||||
|
if(accountWebHooks.nonEmpty){
|
||||||
|
makePayload.map(callWebHook(event, accountWebHooks, _))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def callWebHook(event: WebHook.Event, webHooks: List[WebHook], payload: WebHookPayload)
|
def callWebHook(event: WebHook.Event, webHooks: List[WebHook], payload: WebHookPayload)
|
||||||
@@ -207,7 +252,7 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
|
|
||||||
/** @return Map[(issue, issueUser, pullRequest, baseOwner, headOwner), webHooks] */
|
/** @return Map[(issue, issueUser, pullRequest, baseOwner, headOwner), webHooks] */
|
||||||
def getPullRequestsByRequestForWebhook(userName:String, repositoryName:String, branch:String)
|
def getPullRequestsByRequestForWebhook(userName:String, repositoryName:String, branch:String)
|
||||||
(implicit s: Session): Map[(Issue, Account, PullRequest, Account, Account), List[WebHook]] =
|
(implicit s: Session): Map[(Issue, Account, PullRequest, Account, Account), List[RepositoryWebHook]] =
|
||||||
(for{
|
(for{
|
||||||
is <- Issues if is.closed === false.bind
|
is <- Issues if is.closed === false.bind
|
||||||
pr <- PullRequests if pr.byPrimaryKey(is.userName, is.repositoryName, is.issueId)
|
pr <- PullRequests if pr.byPrimaryKey(is.userName, is.repositoryName, is.issueId)
|
||||||
@@ -217,8 +262,8 @@ trait WebHookPullRequestService extends WebHookService {
|
|||||||
bu <- Accounts if bu.userName === pr.userName
|
bu <- Accounts if bu.userName === pr.userName
|
||||||
ru <- Accounts if ru.userName === pr.requestUserName
|
ru <- Accounts if ru.userName === pr.requestUserName
|
||||||
iu <- Accounts if iu.userName === is.openedUserName
|
iu <- Accounts if iu.userName === is.openedUserName
|
||||||
wh <- WebHooks if wh.byRepository(is.userName , is.repositoryName)
|
wh <- RepositoryWebHooks if wh.byRepository(is.userName , is.repositoryName)
|
||||||
wht <- WebHookEvents if wht.event === WebHook.PullRequest.asInstanceOf[WebHook.Event].bind && wht.byWebHook(wh)
|
wht <- RepositoryWebHookEvents if wht.event === WebHook.PullRequest.asInstanceOf[WebHook.Event].bind && wht.byRepositoryWebHook(wh)
|
||||||
} yield {
|
} yield {
|
||||||
((is, iu, pr, bu, ru), wh)
|
((is, iu, pr, bu, ru), wh)
|
||||||
}).list.groupBy(_._1).mapValues(_.map(_._2))
|
}).list.groupBy(_._1).mapValues(_.map(_._2))
|
||||||
@@ -345,6 +390,17 @@ object WebHookService {
|
|||||||
repositoryInfo,
|
repositoryInfo,
|
||||||
owner= ApiUser(repositoryOwner))
|
owner= ApiUser(repositoryOwner))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def createDummyPayload(sender: Account): WebHookPushPayload =
|
||||||
|
WebHookPushPayload(
|
||||||
|
pusher = ApiPusher(sender),
|
||||||
|
sender = ApiUser(sender),
|
||||||
|
ref = "refs/heads/master",
|
||||||
|
before = "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc",
|
||||||
|
after = "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc",
|
||||||
|
commits = List.empty,
|
||||||
|
repository = ApiRepository.forDummyPayload(ApiUser(sender))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.github.com/v3/activity/events/types/#issuesevent
|
// https://developer.github.com/v3/activity/events/types/#issuesevent
|
||||||
|
|||||||
191
src/main/twirl/gitbucket/core/account/edithooks.scala.html
Normal file
191
src/main/twirl/gitbucket/core/account/edithooks.scala.html
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
@(webHook: gitbucket.core.model.AccountWebHook,
|
||||||
|
events: Set[gitbucket.core.model.WebHook.Event],
|
||||||
|
account: gitbucket.core.model.Account,
|
||||||
|
groupNames: List[String],
|
||||||
|
info: Option[Any],
|
||||||
|
create: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||||
|
@import gitbucket.core.view.helpers
|
||||||
|
@import gitbucket.core.model.WebHook._
|
||||||
|
@import gitbucket.core.model.WebHookContentType
|
||||||
|
@check(name: String, event: Event) = {
|
||||||
|
name="@(name).@event.name" value="on" @if(events(event)){checked}
|
||||||
|
}
|
||||||
|
@gitbucket.core.account.html.main(account, groupNames, "webhooks"){
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading strong">Webhook / Manage webhook</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form method="POST" validate="true">
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<label class="strong">Payload URL</label>
|
||||||
|
<div>
|
||||||
|
<span class="error" id="error-url"></span>
|
||||||
|
</div>
|
||||||
|
@if(create){
|
||||||
|
<input type="text" name="url" id="url" value="@webHook.url" class="form-control" style="display: inline; width: 500px; vertical-align: middle;" required />
|
||||||
|
} else {
|
||||||
|
<input type="text" value="@webHook.url" class="form-control" style="display: inline; width: 500px; vertical-align: middle;" disabled />
|
||||||
|
<input type="hidden" value="@webHook.url" name="url" />
|
||||||
|
}
|
||||||
|
<button class="btn btn-default" id="test">Test Hook</button>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<label class="strong">Content type</label>
|
||||||
|
<div></div>
|
||||||
|
<select name="ctype">
|
||||||
|
<option value="@WebHookContentType.FORM.code" @if(webHook.ctype == WebHookContentType.FORM){selected}>@WebHookContentType.FORM.ctype</option>
|
||||||
|
<option value="@WebHookContentType.JSON.code" @if(webHook.ctype == WebHookContentType.JSON){selected}>@WebHookContentType.JSON.ctype</option>
|
||||||
|
</select>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<label class="strong">Security Token</label>
|
||||||
|
<div></div>
|
||||||
|
<input type="text" name="token" id="token" placeholder="leave blank for no X-Hub-Signature usage" value="@webHook.token" class="form-control" style="display: inline; width: 500px; vertical-align: middle;" />
|
||||||
|
</fieldset>
|
||||||
|
<hr />
|
||||||
|
<label class="strong">Which events would you like to trigger this webhook?</label>
|
||||||
|
<div>
|
||||||
|
<span class="error" id="error-events"></span>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",CommitComment) />Commit comment <small class="help-block">Commit or diff commented on. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Create) />Create <small class="help-block">Branch, or tag created. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Delete) />Delete <small class="help-block">Branch, or tag deleted. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Deployment) />Deployment <small class="help-block">Repository deployed. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",DeploymentStatus) />Deployment status <small class="help-block">Deployment status updated from the API. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Fork) />Fork <small class="help-block">Repository forked. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Gollum) />Gollum <small class="help-block">Wiki page updated. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Member) />Member <small class="help-block">Collaborator added to a non-organization repository. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",PageBuild) />Page build <small class="help-block">Pages site built. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Public) />Public <small class="help-block">Repository changes from private to public. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Release) />Release <small class="help-block">Release published in a repository. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",TeamAdd) />Team add <small class="help-block">Team added or modified on a repository. </small> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Watch) />Watch <small class="help-block">User stars a repository.</small></label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Status) />Status <small class="help-block">Commit status updated from the API. </small> </label>
|
||||||
|
-->
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",IssueComment) />Issue comment <span class="help-block normal">Issue commented on. </span> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Issues) />Issues <span class="help-block normal">Issue opened, closed<!-- , assigned, or labeled -->. </span> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",PullRequest) />Pull request <span class="help-block normal">Pull request opened, closed<!-- , assigned, labeled -->, or synchronized. </span> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",PullRequestReviewComment) />Pull request review comment <span class="help-block normal">Pull request diff commented on. </span> </label>
|
||||||
|
<label class="checkbox"><input type="checkbox" @check("events",Push) />Push <span class="help-block normal">Git push to a repository. </span> </label>
|
||||||
|
<div class="text-right">
|
||||||
|
@if(!create){
|
||||||
|
<input type="submit" class="btn btn-success" value="Update webhook" formaction="@helpers.url(account.userName)/_hooks/edit" />
|
||||||
|
<a href="@helpers.url(account.userName)/_hooks/delete?url=@helpers.urlEncode(webHook.url)" class="btn btn-danger" onclick="return confirm('delete webhook for @webHook.url ?')">
|
||||||
|
Delete webhook
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<input type="submit" class="btn btn-success" value="Add webhook" formaction="@helpers.url(account.userName)/_hooks/new" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal" id="test-report-modal" role="dialog" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h3>WebHook Test</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" style="max-height: 300px; overflow: auto;">
|
||||||
|
<p>request to <span id="test-modal-url" style="word-break: break-all; word-wrap: break-word; white-space: pre; white-space: pre-wrap;"></span></p>
|
||||||
|
<div id="test-report" style="display:none">
|
||||||
|
<ul class="nav nav-tabs" id="test-report-tab">
|
||||||
|
<li class="active"><a href="#request">Request</a></li>
|
||||||
|
<li><a href="#response">Response <span class="badge badge-success" id="res-status"></span></a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="request">
|
||||||
|
<div id="req-errors" class="alert alert-error">
|
||||||
|
ERROR<span id="req-errors-body"></span>
|
||||||
|
</div>
|
||||||
|
<div id="req-success" style="display:none">
|
||||||
|
Headers
|
||||||
|
<pre id="req-headers"></pre>
|
||||||
|
Payload
|
||||||
|
<pre id="req-payload"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="response">
|
||||||
|
<div id="res-errors" class="alert alert-error">
|
||||||
|
ERROR<span id="res-errors-body"></span>
|
||||||
|
</div>
|
||||||
|
<div id="res-success" style="display:none">
|
||||||
|
Headers
|
||||||
|
<pre id="res-headers"></pre>
|
||||||
|
Body
|
||||||
|
<pre id="res-body"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
<script>
|
||||||
|
$(function(){
|
||||||
|
$('#test-report-tab a').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).tab('show');
|
||||||
|
});
|
||||||
|
$('#test').click(function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
var url = this.form.url.value;
|
||||||
|
var token = this.form.token.value;
|
||||||
|
var ctype = this.form.ctype.value;
|
||||||
|
if(!/^https?:\/\/.+/.test(url)){
|
||||||
|
alert("invalid url");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#test-modal-url").text(url)
|
||||||
|
$("#test-report-modal").modal('show')
|
||||||
|
$("#test-report").hide();
|
||||||
|
var targetUrl = '@helpers.url(account.userName)/_hooks/test?url=' + encodeURIComponent(url) + '&ctype=' + ctype + '&token=';
|
||||||
|
if (token) {
|
||||||
|
targetUrl = targetUrl + encodeURIComponent(token);
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
method:'POST',
|
||||||
|
url:targetUrl,
|
||||||
|
success: function(e){
|
||||||
|
//console.log(e);
|
||||||
|
$('#test-report-tab a:first').tab('show');
|
||||||
|
$("#test-report").show();
|
||||||
|
$("#req-success").toggle(e.request&&!e.request.error);
|
||||||
|
$("#req-errors").toggle(e.request&&!!e.request.error);
|
||||||
|
$("#req-errors-body").text(e.request.error);
|
||||||
|
function headers(h){
|
||||||
|
h = h["headers"];
|
||||||
|
return h ? $.map(h, function(h){
|
||||||
|
return $("<div>").append($('<b>').text(h[0] + ":"),$('<span>').text(" " + h[1]))
|
||||||
|
}):"";
|
||||||
|
}
|
||||||
|
$("#req-headers").html(headers(e.request));
|
||||||
|
$("#req-payload").text(e.request && e.request.payload ? JSON.stringify(JSON.parse(e.request.payload),undefined,4) : "");
|
||||||
|
$("#res-success").toggle(e.responce && !e.responce.error);
|
||||||
|
$("#res-errors").toggle(e.responce && !!e.responce.error);
|
||||||
|
$("#res-errors-body").text(e.responce.error);
|
||||||
|
var success = !!(e.responce && e.responce.status && /^2\d\d$/.test(e.responce.status.statusCode));
|
||||||
|
$("#res-status").text((e.responce && e.responce.status && e.responce.status.statusCode) || "ERROR");
|
||||||
|
$("#res-status").toggleClass("badge-success", success).toggleClass("badge-important", !success);
|
||||||
|
$("#res-headers").html(headers(e.responce));
|
||||||
|
$("#res-body").text(e.responce && e.responce.body ? e.responce.body : "");
|
||||||
|
},
|
||||||
|
error:function (e) {
|
||||||
|
if(e) {
|
||||||
|
console.log(e.responseText, e);
|
||||||
|
alert("request error ( http status " + e.status + " error on gitbugket or browser to gitbucket. show details on your javascript console )");
|
||||||
|
}else{
|
||||||
|
alert("unknown javascript error (please report to gitbucket team)");
|
||||||
|
}
|
||||||
|
$("#test-report-modal").modal('hide')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
}
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
} else {
|
} else {
|
||||||
<li@if(active == "activity"){ class="active"}><a href="@helpers.url(account.userName)?tab=activity">Public activity</a></li>
|
<li@if(active == "activity"){ class="active"}><a href="@helpers.url(account.userName)?tab=activity">Public activity</a></li>
|
||||||
}
|
}
|
||||||
|
<li@if(active == "webhooks"){ class="active"}><a href="@helpers.url(account.userName)?tab=webhooks">Webhooks</a></li>
|
||||||
@gitbucket.core.plugin.PluginRegistry().getProfileTabs.map { tab =>
|
@gitbucket.core.plugin.PluginRegistry().getProfileTabs.map { tab =>
|
||||||
@tab(account, context).map { link =>
|
@tab(account, context).map { link =>
|
||||||
<li@if(active == link.id){ class="active"}><a href="@context.path/@link.path">@link.label</a></li>
|
<li@if(active == link.id){ class="active"}><a href="@context.path/@link.path">@link.label</a></li>
|
||||||
|
|||||||
39
src/main/twirl/gitbucket/core/account/webhook.scala.html
Normal file
39
src/main/twirl/gitbucket/core/account/webhook.scala.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
@(account: gitbucket.core.model.Account,
|
||||||
|
groupNames: List[String],
|
||||||
|
webHooks: List[(gitbucket.core.model.AccountWebHook, Set[gitbucket.core.model.WebHook.Event])])(implicit context: gitbucket.core.controller.Context)
|
||||||
|
@import gitbucket.core.view.helpers
|
||||||
|
@gitbucket.core.account.html.main(account, groupNames, "webhooks"){
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading strong">
|
||||||
|
Webhooks
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
Webhooks allow external services to be notified when certain events happen within your repository.
|
||||||
|
When the specified events happen, we’ll send a POST request to each of the URLs you provide.
|
||||||
|
Learn more in <a href="https://github.com/takezoe/gitbucket/wiki/API-WebHook" target="_blank">GitBucket Wiki Webhook Page</a>.
|
||||||
|
</p>
|
||||||
|
<a href="@helpers.url(account.userName)/_hooks/new" class="btn btn-success pull-right" style="margin-bottom: 10px;">Add webhook</a>
|
||||||
|
|
||||||
|
<table class="table table-condensed" style="margin-bottom:0px;">
|
||||||
|
@webHooks.map { case (webHook, events) =>
|
||||||
|
<tr><td style="vertical-align: middle;">
|
||||||
|
<a href="@helpers.url(account.userName)/_hooks/edit?url=@helpers.urlEncode(webHook.url)" class="css-truncate" style="max-width:360px">
|
||||||
|
<span class="css-truncate-target">@webHook.url</span>
|
||||||
|
</a>
|
||||||
|
<em class="css-truncate" style="max-width: 225px;">(<span class="css-truncate-target">@events.map(_.name).mkString(", ")</span>)</em>
|
||||||
|
</td><td>
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<a href="@helpers.url(account.userName)/_hooks/edit?url=@helpers.urlEncode(webHook.url)" class="btn btn-default">
|
||||||
|
<span class="octicon octicon-pencil"></span>
|
||||||
|
</a>
|
||||||
|
<a href="@helpers.url(account.userName)/_hooks/delete?url=@helpers.urlEncode(webHook.url)" class="btn btn-danger" onclick="return confirm('delete webhook for @webHook.url ?')">
|
||||||
|
<span class="octicon octicon-x"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td></tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
import gitbucket.core.model.WebHook
|
import gitbucket.core.model.{WebHook, RepositoryWebHook}
|
||||||
import org.scalatest.FunSuite
|
import org.scalatest.FunSuite
|
||||||
import gitbucket.core.model.WebHookContentType
|
import gitbucket.core.model.WebHookContentType
|
||||||
|
|
||||||
@@ -47,17 +47,17 @@ class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
|||||||
val formType = WebHookContentType.FORM
|
val formType = WebHookContentType.FORM
|
||||||
val jsonType = WebHookContentType.JSON
|
val jsonType = WebHookContentType.JSON
|
||||||
service.addWebHook("user1", "repo1", "http://example.com", Set(WebHook.PullRequest), formType, Some("key"))
|
service.addWebHook("user1", "repo1", "http://example.com", Set(WebHook.PullRequest), formType, Some("key"))
|
||||||
assert(service.getWebHooks("user1", "repo1") == List((WebHook("user1","repo1","http://example.com", formType, Some("key")),Set(WebHook.PullRequest))))
|
assert(service.getWebHooks("user1", "repo1") == List((RepositoryWebHook("user1","repo1","http://example.com", formType, Some("key")),Set(WebHook.PullRequest))))
|
||||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((WebHook("user1","repo1","http://example.com", formType, Some("key")),Set(WebHook.PullRequest))))
|
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((RepositoryWebHook("user1","repo1","http://example.com", formType, Some("key")),Set(WebHook.PullRequest))))
|
||||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List((WebHook("user1","repo1","http://example.com", formType, Some("key")))))
|
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List((RepositoryWebHook("user1","repo1","http://example.com", formType, Some("key")))))
|
||||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == Nil)
|
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == Nil)
|
||||||
assert(service.getWebHook("user1", "repo1", "http://example.com2") == None)
|
assert(service.getWebHook("user1", "repo1", "http://example.com2") == None)
|
||||||
assert(service.getWebHook("user2", "repo1", "http://example.com") == None)
|
assert(service.getWebHook("user2", "repo1", "http://example.com") == None)
|
||||||
assert(service.getWebHook("user1", "repo2", "http://example.com") == None)
|
assert(service.getWebHook("user1", "repo2", "http://example.com") == None)
|
||||||
service.updateWebHook("user1", "repo1", "http://example.com", Set(WebHook.Push, WebHook.Issues), jsonType, Some("key"))
|
service.updateWebHook("user1", "repo1", "http://example.com", Set(WebHook.Push, WebHook.Issues), jsonType, Some("key"))
|
||||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((WebHook("user1","repo1","http://example.com", jsonType, Some("key")),Set(WebHook.Push, WebHook.Issues))))
|
assert(service.getWebHook("user1", "repo1", "http://example.com") == Some((RepositoryWebHook("user1","repo1","http://example.com", jsonType, Some("key")),Set(WebHook.Push, WebHook.Issues))))
|
||||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == Nil)
|
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == Nil)
|
||||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == List((WebHook("user1","repo1","http://example.com", jsonType, Some("key")))))
|
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == List((RepositoryWebHook("user1","repo1","http://example.com", jsonType, Some("key")))))
|
||||||
service.deleteWebHook("user1", "repo1", "http://example.com")
|
service.deleteWebHook("user1", "repo1", "http://example.com")
|
||||||
assert(service.getWebHook("user1", "repo1", "http://example.com") == None)
|
assert(service.getWebHook("user1", "repo1", "http://example.com") == None)
|
||||||
} }
|
} }
|
||||||
@@ -69,11 +69,11 @@ class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
|||||||
service.addWebHook("user1", "repo1", "http://example.com/2", Set(WebHook.Push), ctype, Some("key"))
|
service.addWebHook("user1", "repo1", "http://example.com/2", Set(WebHook.Push), ctype, Some("key"))
|
||||||
service.addWebHook("user1", "repo1", "http://example.com/3", Set(WebHook.PullRequest,WebHook.Push), ctype, Some("key"))
|
service.addWebHook("user1", "repo1", "http://example.com/3", Set(WebHook.PullRequest,WebHook.Push), ctype, Some("key"))
|
||||||
assert(service.getWebHooks("user1", "repo1") == List(
|
assert(service.getWebHooks("user1", "repo1") == List(
|
||||||
WebHook("user1","repo1","http://example.com/1", ctype, Some("key"))->Set(WebHook.PullRequest),
|
RepositoryWebHook("user1","repo1","http://example.com/1", ctype, Some("key"))->Set(WebHook.PullRequest),
|
||||||
WebHook("user1","repo1","http://example.com/2", ctype, Some("key"))->Set(WebHook.Push),
|
RepositoryWebHook("user1","repo1","http://example.com/2", ctype, Some("key"))->Set(WebHook.Push),
|
||||||
WebHook("user1","repo1","http://example.com/3", ctype, Some("key"))->Set(WebHook.PullRequest,WebHook.Push)))
|
RepositoryWebHook("user1","repo1","http://example.com/3", ctype, Some("key"))->Set(WebHook.PullRequest,WebHook.Push)))
|
||||||
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List(
|
assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List(
|
||||||
WebHook("user1","repo1","http://example.com/1", ctype, Some("key")),
|
RepositoryWebHook("user1","repo1","http://example.com/1", ctype, Some("key")),
|
||||||
WebHook("user1","repo1","http://example.com/3", ctype, Some("key"))))
|
RepositoryWebHook("user1","repo1","http://example.com/3", ctype, Some("key"))))
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user