mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 05:29:51 +00:00
add webhook deployer
This commit is contained in:
parent
4b8fa3502c
commit
1861e73531
8
go.mod
8
go.mod
@ -11,6 +11,7 @@ require (
|
||||
github.com/alibabacloud-go/tea v1.2.1
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.5
|
||||
github.com/go-acme/lego/v4 v4.17.4
|
||||
github.com/gojek/heimdall/v7 v7.0.3
|
||||
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/pocketbase/dbx v1.10.1
|
||||
@ -52,6 +53,7 @@ require (
|
||||
github.com/aws/smithy-go v1.20.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.5.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
@ -61,6 +63,7 @@ require (
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@ -80,9 +83,13 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.898 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.898 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
@ -106,6 +113,7 @@ require (
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
|
13
go.sum
13
go.sum
@ -19,9 +19,11 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.7.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||
@ -99,6 +101,7 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudr
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
|
||||
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
|
||||
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@ -150,6 +153,10 @@ github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVH
|
||||
github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gojek/heimdall/v7 v7.0.3 h1:+5sAhl8S0m+qRRL8IVeHCJudFh/XkG3wyO++nvOg+gc=
|
||||
github.com/gojek/heimdall/v7 v7.0.3/go.mod h1:Z43HtMid7ysSjmsedPTXAki6jcdcNVnjn5pmsTyiMic=
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf h1:5xRGbUdOmZKoDXkGx5evVLehuCMpuO1hl701bEQqXOM=
|
||||
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf/go.mod h1:QzhUKaYKJmcbTnCYCAVQrroCOY7vOOI8cSQ4NbuhYf0=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
@ -246,6 +253,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||
@ -260,6 +268,7 @@ github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWK
|
||||
github.com/pocketbase/pocketbase v0.22.18 h1:yVckUhi5GDORqCb0BbtlvRB1CVxHY9HO9btEaeZHVJU=
|
||||
github.com/pocketbase/pocketbase v0.22.18/go.mod h1:0QFvDOOW7ANId78ChZSagyHbmP6CgMxDQrQFXzeaDpA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
@ -276,8 +285,11 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
@ -488,6 +500,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
|
@ -17,6 +17,7 @@ const (
|
||||
targetAliyunOss = "aliyun-oss"
|
||||
targetAliyunCdn = "aliyun-cdn"
|
||||
targetSSH = "ssh"
|
||||
targetWebhook = "webhook"
|
||||
)
|
||||
|
||||
type DeployerOption struct {
|
||||
@ -55,6 +56,8 @@ func Get(record *models.Record, cert *applicant.Certificate) (Deployer, error) {
|
||||
return NewAliyunCdn(option)
|
||||
case targetSSH:
|
||||
return NewSSH(option)
|
||||
case targetWebhook:
|
||||
return NewWebhook(option)
|
||||
}
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
55
internal/deployer/webhook.go
Normal file
55
internal/deployer/webhook.go
Normal file
@ -0,0 +1,55 @@
|
||||
package deployer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
xhttp "certimate/internal/utils/http"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type webhookAccess struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type hookData struct {
|
||||
Domain string `json:"domain"`
|
||||
Certificate string `json:"certificate"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
}
|
||||
|
||||
type webhook struct {
|
||||
option *DeployerOption
|
||||
}
|
||||
|
||||
func NewWebhook(option *DeployerOption) (Deployer, error) {
|
||||
|
||||
return &webhook{
|
||||
option: option,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *webhook) Deploy(ctx context.Context) error {
|
||||
access := &webhookAccess{}
|
||||
if err := json.Unmarshal([]byte(w.option.Access), access); err != nil {
|
||||
return fmt.Errorf("failed to parse hook access config: %w", err)
|
||||
}
|
||||
|
||||
data := &hookData{
|
||||
Domain: w.option.Domain,
|
||||
Certificate: w.option.Certificate.Certificate,
|
||||
PrivateKey: w.option.Certificate.PrivateKey,
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(data)
|
||||
|
||||
_, err := xhttp.Req(access.Url, http.MethodPost, bytes.NewReader(body), map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send hook request: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
60
internal/utils/http/http.go
Normal file
60
internal/utils/http/http.go
Normal file
@ -0,0 +1,60 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gojek/heimdall/v7/httpclient"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
func WithTimeout(timeout time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.Timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
func Req(url string, method string, body io.Reader, head map[string]string, opts ...Option) ([]byte, error) {
|
||||
reader, err := Req2GetReader(url, method, body, head, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
return io.ReadAll(reader)
|
||||
}
|
||||
|
||||
func Req2GetReader(url string, method string, body io.Reader, head map[string]string, opts ...Option) (io.ReadCloser, error) {
|
||||
options := &Options{
|
||||
Timeout: 30000 * time.Millisecond,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
client := httpclient.NewClient(httpclient.WithHTTPTimeout(options.Timeout))
|
||||
|
||||
// Create an http.Request instance
|
||||
req, _ := http.NewRequest(method, url, body)
|
||||
for k, v := range head {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
// Call the `Do` method, which has a similar interface to the `http.Do` method
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("status code is not 200: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
return res.Body, nil
|
||||
}
|
File diff suppressed because one or more lines are too long
1
ui/dist/imgs/providers/webhook.svg
vendored
Normal file
1
ui/dist/imgs/providers/webhook.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="#059669" d="M7 20.5q-1.864 0-3.182-1.318T2.5 16q0-1.246.608-2.268t1.617-1.615q.275-.165.525-.026q.25.14.25.459q0 .121-.064.24q-.065.12-.169.181q-.776.452-1.272 1.258T3.5 16q0 1.442 1.029 2.471T7 19.5q1.404 0 2.414-.961q1.009-.962 1.086-2.347q.02-.31.199-.5q.18-.192.47-.192h4.725q.142-.321.44-.526q.297-.205.666-.205q.51 0 .87.36q.36.361.36.871t-.36.87t-.87.36q-.388 0-.676-.194q-.288-.196-.43-.536h-4.417q-.235 1.84-1.54 2.92T7 20.5m0-3.27q-.51 0-.87-.36T5.77 16q0-.512.378-.892q.379-.381.994-.314l2.562-4.265q-.84-.656-1.272-1.574T8 7q0-1.864 1.318-3.182T12.5 2.5q1.73 0 2.991 1.14t1.455 2.802q.048.225-.108.392q-.155.166-.386.166q-.171 0-.315-.132t-.185-.309q-.16-1.296-1.136-2.177Q13.838 3.5 12.5 3.5q-1.442 0-2.471 1.029T9 7q0 .883.393 1.618t1.101 1.251q.235.162.303.423q.069.262-.068.485l-2.727 4.542q.108.144.168.321t.06.36q0 .51-.36.87t-.87.36m10 3.27q-.708 0-1.34-.201t-1.195-.591q-.329-.221-.268-.58q.06-.359.474-.359q.106 0 .208.05t.188.106q.402.271.903.423T17 19.5q1.442 0 2.471-1.029T20.5 16t-1.029-2.471T17 12.5q-.25 0-.475.038t-.45.093q-.285.086-.558-.017t-.41-.32l-2.459-4.088q-.525.073-.952-.279T11.27 7q0-.51.36-.87q.362-.36.871-.36t.87.36t.36.87q0 .183-.057.357t-.165.299l2.367 3.977q.258-.05.53-.092q.274-.041.595-.041q1.864 0 3.182 1.318T21.5 16t-1.318 3.182T17 20.5"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
2
ui/dist/index.html
vendored
2
ui/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||
<script type="module" crossorigin src="/assets/index-vWJSQP8e.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-D-MCicNE.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-VYJgHfoP.css">
|
||||
</head>
|
||||
<body class="bg-background">
|
||||
|
1
ui/public/imgs/providers/webhook.svg
Normal file
1
ui/public/imgs/providers/webhook.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="#059669" d="M7 20.5q-1.864 0-3.182-1.318T2.5 16q0-1.246.608-2.268t1.617-1.615q.275-.165.525-.026q.25.14.25.459q0 .121-.064.24q-.065.12-.169.181q-.776.452-1.272 1.258T3.5 16q0 1.442 1.029 2.471T7 19.5q1.404 0 2.414-.961q1.009-.962 1.086-2.347q.02-.31.199-.5q.18-.192.47-.192h4.725q.142-.321.44-.526q.297-.205.666-.205q.51 0 .87.36q.36.361.36.871t-.36.87t-.87.36q-.388 0-.676-.194q-.288-.196-.43-.536h-4.417q-.235 1.84-1.54 2.92T7 20.5m0-3.27q-.51 0-.87-.36T5.77 16q0-.512.378-.892q.379-.381.994-.314l2.562-4.265q-.84-.656-1.272-1.574T8 7q0-1.864 1.318-3.182T12.5 2.5q1.73 0 2.991 1.14t1.455 2.802q.048.225-.108.392q-.155.166-.386.166q-.171 0-.315-.132t-.185-.309q-.16-1.296-1.136-2.177Q13.838 3.5 12.5 3.5q-1.442 0-2.471 1.029T9 7q0 .883.393 1.618t1.101 1.251q.235.162.303.423q.069.262-.068.485l-2.727 4.542q.108.144.168.321t.06.36q0 .51-.36.87t-.87.36m10 3.27q-.708 0-1.34-.201t-1.195-.591q-.329-.221-.268-.58q.06-.359.474-.359q.106 0 .208.05t.188.106q.402.271.903.423T17 19.5q1.442 0 2.471-1.029T20.5 16t-1.029-2.471T17 12.5q-.25 0-.475.038t-.45.093q-.285.086-.558-.017t-.41-.32l-2.459-4.088q-.525.073-.952-.279T11.27 7q0-.51.36-.87q.362-.36.871-.36t.87.36t.36.87q0 .183-.057.357t-.165.299l2.367 3.977q.258-.05.53-.092q.274-.041.595-.041q1.864 0 3.182 1.318T21.5 16t-1.318 3.182T17 20.5"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -18,6 +18,7 @@ import { cn } from "@/lib/utils";
|
||||
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
|
||||
|
||||
import AccessSSHForm from "./AccessSSHForm";
|
||||
import WebhookForm from "./AccessWebhookFrom";
|
||||
|
||||
type TargetConfigEditProps = {
|
||||
op: "add" | "edit";
|
||||
@ -69,6 +70,15 @@ export function AccessEdit({
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case "webhook":
|
||||
form = (
|
||||
<WebhookForm
|
||||
data={data}
|
||||
onAfterReq={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const getOptionCls = (val: string) => {
|
||||
|
173
ui/src/components/certimate/AccessWebhookFrom.tsx
Normal file
173
ui/src/components/certimate/AccessWebhookFrom.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import z from "zod";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { Access, accessFormType, WebhookConfig } from "@/domain/access";
|
||||
import { save } from "@/repository/access";
|
||||
import { useConfig } from "@/providers/config";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
import { PbErrorData } from "@/domain/base";
|
||||
|
||||
const WebhookForm = ({
|
||||
data,
|
||||
onAfterReq,
|
||||
}: {
|
||||
data?: Access;
|
||||
onAfterReq: () => void;
|
||||
}) => {
|
||||
const { addAccess, updateAccess } = useConfig();
|
||||
const formSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1).max(64),
|
||||
configType: accessFormType,
|
||||
url: z.string().url(),
|
||||
});
|
||||
|
||||
let config: WebhookConfig = {
|
||||
url: "",
|
||||
};
|
||||
if (data) config = data.config as WebhookConfig;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
id: data?.id,
|
||||
name: data?.name,
|
||||
configType: "webhook",
|
||||
url: config.url,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
console.log(data);
|
||||
const req: Access = {
|
||||
id: data.id as string,
|
||||
name: data.name,
|
||||
configType: data.configType,
|
||||
config: {
|
||||
url: data.url,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const rs = await save(req);
|
||||
|
||||
onAfterReq();
|
||||
|
||||
req.id = rs.id;
|
||||
req.created = rs.created;
|
||||
req.updated = rs.updated;
|
||||
if (data.id) {
|
||||
updateAccess(req);
|
||||
return;
|
||||
}
|
||||
addAccess(req);
|
||||
} catch (e) {
|
||||
const err = e as ClientResponseError;
|
||||
|
||||
Object.entries(err.response.data as PbErrorData).forEach(
|
||||
([key, value]) => {
|
||||
form.setError(key as keyof z.infer<typeof formSchema>, {
|
||||
type: "manual",
|
||||
message: value.message,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="max-w-[35em] mx-auto mt-10">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
console.log(e);
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>名称</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="请输入授权名称" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => (
|
||||
<FormItem className="hidden">
|
||||
<FormLabel>配置类型</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="configType"
|
||||
render={({ field }) => (
|
||||
<FormItem className="hidden">
|
||||
<FormLabel>配置类型</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="url"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Webhook Url</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="请输入Webhook Url" {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">保存</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WebhookForm;
|
@ -4,10 +4,16 @@ export const accessTypeMap: Map<string, [string, string]> = new Map([
|
||||
["tencent", ["腾讯云", "/imgs/providers/tencent.svg"]],
|
||||
["aliyun", ["阿里云", "/imgs/providers/aliyun.svg"]],
|
||||
["ssh", ["SSH部署", "/imgs/providers/ssh.png"]],
|
||||
["webhook", ["Webhook", "/imgs/providers/webhook.svg"]],
|
||||
]);
|
||||
|
||||
export const accessFormType = z.union(
|
||||
[z.literal("aliyun"), z.literal("tencent"), z.literal("ssh")],
|
||||
[
|
||||
z.literal("aliyun"),
|
||||
z.literal("tencent"),
|
||||
z.literal("ssh"),
|
||||
z.literal("webhook"),
|
||||
],
|
||||
{ message: "请选择云服务商" }
|
||||
);
|
||||
|
||||
@ -15,12 +21,16 @@ export type Access = {
|
||||
id: string;
|
||||
name: string;
|
||||
configType: string;
|
||||
config: TencentConfig | AliyunConfig | SSHConfig;
|
||||
config: TencentConfig | AliyunConfig | SSHConfig | WebhookConfig;
|
||||
deleted?: string;
|
||||
created?: string;
|
||||
updated?: string;
|
||||
};
|
||||
|
||||
export type WebhookConfig = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type TencentConfig = {
|
||||
secretId: string;
|
||||
secretKey: string;
|
||||
|
@ -31,6 +31,7 @@ export const targetTypeMap: Map<string, [string, string]> = new Map([
|
||||
["aliyun-cdn", ["阿里云-CDN", "/imgs/providers/aliyun.svg"]],
|
||||
["aliyun-oss", ["阿里云-OSS", "/imgs/providers/aliyun.svg"]],
|
||||
["ssh", ["SSH部署", "/imgs/providers/ssh.png"]],
|
||||
["webhook", ["Webhook", "/imgs/providers/webhook.svg"]],
|
||||
]);
|
||||
|
||||
export const targetTypeKeys = Array.from(targetTypeMap.keys());
|
||||
|
Loading…
x
Reference in New Issue
Block a user